





















@@ -141,6 +141,10 @@ function envRef(id: string) {
141141return { source: "env" as const, provider: "default", id };
142142}
143143144+function expectWarningIncludes(text: string): void {
145+expect(noopLogger.warn.mock.calls.some(([message]) => String(message).includes(text))).toBe(true);
146+}
147+144148async function registerVoiceCallCli(
145149program: Command,
146150pluginConfig: Record<string, unknown> = { provider: "mock" },
@@ -303,10 +307,8 @@ describe("voice-call plugin", () => {
303307String(message).includes("Failed to start runtime"),
304308),
305309).toBe(false);
306-expect(noopLogger.warn).toHaveBeenCalledWith(
307-expect.stringContaining("Runtime not started; setup incomplete"),
308-);
309-expect(noopLogger.warn).toHaveBeenCalledWith(expect.stringContaining("TWILIO_ACCOUNT_SID"));
310+expectWarningIncludes("Runtime not started; setup incomplete");
311+expectWarningIncludes("TWILIO_ACCOUNT_SID");
310312});
311313312314it("registers Twilio configs with SecretRef auth tokens", async () => {
@@ -345,12 +347,11 @@ describe("voice-call plugin", () => {
345347await handler?.({ params: { message: "Hi", to: "+15550001234" }, respond });
346348347349expect(createVoiceCallRuntime).not.toHaveBeenCalled();
348-expect(respond).toHaveBeenCalledWith(
349-false,
350-undefined,
351-expect.objectContaining({
352-message: expect.stringContaining("TWILIO_ACCOUNT_SID"),
353-}),
350+const [ok, payload, error] = respond.mock.calls[0] ?? [];
351+expect(ok).toBe(false);
352+expect(payload).toBeUndefined();
353+expect(String((error as { message?: unknown } | undefined)?.message)).toContain(
354+"TWILIO_ACCOUNT_SID",
354355);
355356});
356357@@ -578,23 +579,14 @@ describe("voice-call plugin", () => {
578579await handler?.({ params: { callId: "call-1" }, respond });
579580580581expect(vi.mocked(createVoiceCallRuntime)).toHaveBeenCalledTimes(1);
581-expect(vi.mocked(createVoiceCallRuntime).mock.calls[0]?.[0]?.config).toMatchObject({
582-enabled: true,
583-provider: "mock",
584-fromNumber: "+15550001234",
585-streaming: {
586-enabled: true,
587-provider: "openai",
588-providers: {
589-openai: {
590-apiKey: "sk-test",
591-},
592-},
593-},
594-});
595-expect(noopLogger.warn).toHaveBeenCalledWith(
596-expect.stringContaining('Run "openclaw doctor --fix"'),
597-);
582+const runtimeConfig = vi.mocked(createVoiceCallRuntime).mock.calls[0]?.[0]?.config;
583+expect(runtimeConfig?.enabled).toBe(true);
584+expect(runtimeConfig?.provider).toBe("mock");
585+expect(runtimeConfig?.fromNumber).toBe("+15550001234");
586+expect(runtimeConfig?.streaming?.enabled).toBe(true);
587+expect(runtimeConfig?.streaming?.provider).toBe("openai");
588+expect(runtimeConfig?.streaming?.providers?.openai?.apiKey).toBe("sk-test");
589+expectWarningIncludes('Run "openclaw doctor --fix"');
598590});
599591600592it("tool get_status returns json payload", async () => {
@@ -715,14 +707,11 @@ describe("voice-call plugin", () => {
715707716708await handler?.({ params: {}, respond });
717709718-expect(respond).toHaveBeenCalledWith(
719-false,
720-undefined,
721-expect.objectContaining({
722-code: "INVALID_REQUEST",
723-message: "to required",
724-}),
725-);
710+const [ok, payload, error] = respond.mock.calls[0] ?? [];
711+expect(ok).toBe(false);
712+expect(payload).toBeUndefined();
713+expect((error as { code?: unknown } | undefined)?.code).toBe("INVALID_REQUEST");
714+expect((error as { message?: unknown } | undefined)?.message).toBe("to required");
726715});
727716728717it("starts and polls delegated gateway continue operations", async () => {
@@ -803,27 +792,23 @@ describe("voice-call plugin", () => {
803792respond: startRespond,
804793});
805794const startPayload = startRespond.mock.calls[0]?.[1] as
806-| { operationId?: string; pollTimeoutMs?: number }
795+| { operationId?: string; pollTimeoutMs?: number; status?: string }
807796| undefined;
808-expect(startPayload).toEqual(
809-expect.objectContaining({
810-operationId: expect.stringMatching(
811-/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu,
812-),
813-status: "pending",
814-pollTimeoutMs: 180000,
815-}),
797+expect(startPayload?.operationId).toMatch(
798+/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu,
816799);
800+expect(startPayload?.status).toBe("pending");
801+expect(startPayload?.pollTimeoutMs).toBe(180000);
817802expect(runtimeStub.manager.continueCall).toHaveBeenCalledWith("call-1", "Hello");
818803819804const pendingRespond = vi.fn();
820805await result?.({
821806params: { operationId: startPayload?.operationId },
822807respond: pendingRespond,
823808});
824-expect(pendingRespond).toHaveBeenCalledWith(
825- true,
826-expect.objectContaining({ status: "pending" }),
809+expect(pendingRespond.mock.calls[0]?.[0]).toBe(true);
810+expect((pendingRespond.mock.calls[0]?.[1] as { status?: unknown } | undefined)?.status).toBe(
811+"pending",
827812);
828813829814finishContinue?.({ success: true, transcript: "gateway hello" });
@@ -835,13 +820,12 @@ describe("voice-call plugin", () => {
835820params: { operationId: startPayload?.operationId },
836821respond: completedRespond,
837822});
838-expect(completedRespond).toHaveBeenCalledWith(
839-true,
840-expect.objectContaining({
841-status: "completed",
842-result: { success: true, transcript: "gateway hello" },
843-}),
844-);
823+const completedPayload = completedRespond.mock.calls[0]?.[1] as
824+| { status?: unknown; result?: unknown }
825+| undefined;
826+expect(completedRespond.mock.calls[0]?.[0]).toBe(true);
827+expect(completedPayload?.status).toBe("completed");
828+expect(completedPayload?.result).toEqual({ success: true, transcript: "gateway hello" });
845829});
846830847831it("CLI setup prints human-readable checks by default", async () => {
@@ -885,9 +869,8 @@ describe("voice-call plugin", () => {
885869checks?: Array<{ id: string; ok: boolean }>;
886870};
887871expect(parsed.ok).toBe(false);
888-expect(parsed.checks).toContainEqual(
889-expect.objectContaining({ id: "webhook-exposure", ok: false }),
890-);
872+const webhookExposure = parsed.checks?.find((check) => check.id === "webhook-exposure");
873+expect(webhookExposure?.ok).toBe(false);
891874} finally {
892875stdout.restore();
893876}
@@ -917,13 +900,9 @@ describe("voice-call plugin", () => {
917900checks?: Array<{ id: string; ok: boolean; message: string }>;
918901};
919902expect(parsed.ok).toBe(false);
920-expect(parsed.checks).toContainEqual(
921-expect.objectContaining({
922-id: "webhook-exposure",
923-ok: false,
924-message: expect.stringContaining("local/private"),
925-}),
926-);
903+const webhookExposure = parsed.checks?.find((check) => check.id === "webhook-exposure");
904+expect(webhookExposure?.ok).toBe(false);
905+expect(webhookExposure?.message).toContain("local/private");
927906} finally {
928907stdout.restore();
929908}
@@ -939,7 +918,8 @@ describe("voice-call plugin", () => {
939918const parsed = JSON.parse(stdout.output()) as {
940919calls?: Array<{ callId?: string }>;
941920};
942-expect(parsed.calls).toEqual([expect.objectContaining({ callId: "call-1" })]);
921+expect(parsed.calls).toHaveLength(1);
922+expect(parsed.calls?.[0]?.callId).toBe("call-1");
943923} finally {
944924stdout.restore();
945925}
@@ -966,7 +946,8 @@ describe("voice-call plugin", () => {
966946{ progress: false },
967947);
968948expect(createVoiceCallRuntime).not.toHaveBeenCalled();
969-expect(parsed.calls).toEqual([expect.objectContaining({ callId: "gateway-call" })]);
949+expect(parsed.calls).toHaveLength(1);
950+expect(parsed.calls?.[0]?.callId).toBe("gateway-call");
970951} finally {
971952stdout.restore();
972953}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。