collabSupport/tests/callTest.service.test.js
Joseph McQueen 7aa8c37d1d Add Twilio /calltest for store and direct-dial voice path testing.
Enables outbound PSTN probes via TwiML webhooks with Webex result cards, status polling, and optional store CDR enrichment.
2026-07-23 17:59:10 -04:00

145 lines
3.8 KiB
JavaScript

// tests/callTest.service.test.js
import test from 'node:test';
import assert from 'node:assert/strict';
import {
handleStatusCallback,
handleVoiceWebhook,
tryFinalizeFromVoiceDoneForTests,
_clearPendingFinalizeTimersForTests,
} from '../services/callTest/callTestService.js';
import {
createSession,
_clearAllSessionsForTests,
getSession,
} from '../services/callTest/sessionStore.js';
import { renderCallTestResultMarkdown } from '../services/renderers/callTestRenderer.js';
const TEST_ID = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee';
test('handleVoiceWebhook: store path marks core on intro', () => {
_clearAllSessionsForTests();
createSession(TEST_ID, {
mode: 'store',
dialNumber: '+12125550100',
config: { listenSec: 60, introTts: 'x', outroTts: 'y', dtmf: '1', greetingPauseSec: 5, answerWaitSec: 45 },
});
handleVoiceWebhook(TEST_ID, 'store', 'wait');
let s = getSession(TEST_ID);
assert.equal(s.lastStep, 'wait');
assert.equal(s.reachedCore, false);
handleVoiceWebhook(TEST_ID, 'store', 'intro');
s = getSession(TEST_ID);
assert.equal(s.lastStep, 'intro');
assert.equal(s.reachedCore, true);
assert.ok(s.events.coreStartedAt);
});
test('handleVoiceWebhook done step finalizes without status callback', async () => {
_clearAllSessionsForTests();
_clearPendingFinalizeTimersForTests();
createSession(TEST_ID, {
mode: 'dial',
dialNumber: '+12125550100',
roomId: 'room-1',
reachedCore: true,
config: {},
});
handleVoiceWebhook(TEST_ID, 'dial', 'outro');
handleVoiceWebhook(TEST_ID, 'dial', 'done');
const pending = getSession(TEST_ID);
assert.equal(pending.lastStep, 'done');
const finalized = await tryFinalizeFromVoiceDoneForTests(TEST_ID);
assert.equal(finalized.result, 'pass');
assert.equal(finalized.status, 'completed');
});
test('handleStatusCallback: in-progress maps to answered and passes on completed', async () => {
_clearAllSessionsForTests();
createSession(TEST_ID, {
mode: 'dial',
dialNumber: '+12125550100',
reachedCore: true,
lastStep: 'done',
config: {},
});
await handleStatusCallback(TEST_ID, {
CallStatus: 'in-progress',
CallSid: 'CA123',
});
await handleStatusCallback(TEST_ID, {
CallStatus: 'completed',
CallDuration: '75',
CallSid: 'CA123',
});
const s = getSession(TEST_ID);
assert.ok(s.events.answered);
assert.equal(s.result, 'pass');
});
test('handleStatusCallback: completed with core yields pass in renderer', async () => {
_clearAllSessionsForTests();
createSession(TEST_ID, {
mode: 'dial',
dialNumber: '+12125550100',
reachedCore: true,
lastStep: 'done',
config: {},
});
await handleStatusCallback(TEST_ID, {
CallStatus: 'answered',
CallSid: 'CA123',
});
await handleStatusCallback(TEST_ID, {
CallStatus: 'completed',
CallDuration: '75',
CallSid: 'CA123',
});
const s = getSession(TEST_ID);
assert.equal(s.result, 'pass');
assert.equal(s.durationSec, 75);
const md = renderCallTestResultMarkdown(s);
assert.match(md, /PASSED/);
assert.match(md, /CA123/);
});
test('handleStatusCallback: no-answer fails', async () => {
_clearAllSessionsForTests();
createSession(TEST_ID, {
mode: 'dial',
dialNumber: '+12125550100',
config: {},
});
await handleStatusCallback(TEST_ID, {
CallStatus: 'no-answer',
CallSid: 'CA999',
});
const s = getSession(TEST_ID);
assert.equal(s.result, 'fail');
const md = renderCallTestResultMarkdown(s);
assert.match(md, /FAILED/);
});
test('renderCallTestResultMarkdown shows in progress before final result', () => {
const md = renderCallTestResultMarkdown({
mode: 'dial',
status: 'in_progress',
dialNumber: '+12125550100',
testId: TEST_ID,
events: { coreStartedAt: new Date().toISOString() },
});
assert.match(md, /IN PROGRESS/);
});