


























@@ -3,6 +3,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
33const {
44 addTranscriptEntryMock,
55 clearMaxDurationTimerMock,
6+ generateDtmfRedirectTwimlMock,
67 generateNotifyTwimlMock,
78 getCallByProviderCallIdMock,
89 mapVoiceToPollyMock,
@@ -12,6 +13,7 @@ const {
1213} = vi.hoisted(() => ({
1314addTranscriptEntryMock: vi.fn(),
1415clearMaxDurationTimerMock: vi.fn(),
16+generateDtmfRedirectTwimlMock: vi.fn(),
1517generateNotifyTwimlMock: vi.fn(),
1618getCallByProviderCallIdMock: vi.fn(),
1719mapVoiceToPollyMock: vi.fn(),
@@ -45,6 +47,7 @@ vi.mock("../voice-mapping.js", () => ({
4547}));
46484749vi.mock("./twiml.js", () => ({
50+generateDtmfRedirectTwiml: generateDtmfRedirectTwimlMock,
4851generateNotifyTwiml: generateNotifyTwimlMock,
4952}));
5053@@ -69,6 +72,7 @@ describe("voice-call outbound helpers", () => {
6972beforeEach(() => {
7073vi.clearAllMocks();
7174mapVoiceToPollyMock.mockReturnValue("Polly.Joanna");
75+generateDtmfRedirectTwimlMock.mockReturnValue("<DtmfRedirect />");
7276generateNotifyTwimlMock.mockReturnValue("<Response />");
7377});
7478@@ -169,6 +173,51 @@ describe("voice-call outbound helpers", () => {
169173expect(persistCallRecordMock).toHaveBeenCalledTimes(2);
170174});
171175176+it("initiates conversation calls with pre-connect DTMF TwiML", async () => {
177+const initiateProviderCall = vi.fn(async () => ({ providerCallId: "provider-1" }));
178+const ctx = {
179+activeCalls: new Map(),
180+providerCallIdMap: new Map(),
181+provider: { name: "twilio", initiateCall: initiateProviderCall },
182+config: {
183+maxConcurrentCalls: 3,
184+outbound: { defaultMode: "conversation" },
185+fromNumber: "+14155550100",
186+},
187+storePath: "/tmp/voice-call.json",
188+webhookUrl: "https://example.com/webhook",
189+};
190+191+const result = await initiateCall(ctx as never, "+14155550123", "session-1", {
192+mode: "conversation",
193+message: "hello meet",
194+dtmfSequence: "ww123456#",
195+});
196+197+expect(result).toEqual({
198+callId: expect.any(String),
199+success: true,
200+});
201+const callId = result.callId;
202+203+expect(generateDtmfRedirectTwimlMock).toHaveBeenCalledWith(
204+"ww123456#",
205+"https://example.com/webhook",
206+);
207+expect(initiateProviderCall).toHaveBeenCalledWith({
208+ callId,
209+from: "+14155550100",
210+to: "+14155550123",
211+webhookUrl: "https://example.com/webhook",
212+inlineTwiml: undefined,
213+preConnectTwiml: "<DtmfRedirect />",
214+});
215+expect(ctx.activeCalls.get(callId)?.metadata).toMatchObject({
216+initialMessage: "hello meet",
217+mode: "conversation",
218+});
219+});
220+172221it("fails initiateCall cleanly when provider initiation throws", async () => {
173222const ctx = {
174223activeCalls: new Map(),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。