Enables outbound PSTN probes via TwiML webhooks with Webex result cards, status polling, and optional store CDR enrichment.
108 lines
3.9 KiB
JavaScript
108 lines
3.9 KiB
JavaScript
// tests/callTest.twiml.test.js
|
|
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import {
|
|
buildTwiml,
|
|
initialStepForMode,
|
|
CORE_STEP_ORDER,
|
|
STORE_ENTRY_STEP_ORDER,
|
|
} from '../services/callTest/twiml.js';
|
|
import {
|
|
buildVoiceWebhookUrl,
|
|
getCallTestConfig,
|
|
normalizeE164,
|
|
} from '../services/callTest/config.js';
|
|
import { parseCallTestArgs } from '../services/callTest/parseArgs.js';
|
|
|
|
const TEST_ID = '11111111-2222-3333-4444-555555555555';
|
|
const CFG = {
|
|
dtmf: '1',
|
|
greetingPauseSec: 5,
|
|
answerWaitSec: 45,
|
|
listenSec: 60,
|
|
introTts: 'Intro message',
|
|
outroTts: 'Outro message',
|
|
};
|
|
|
|
test('initialStepForMode: store starts at greeting, dial at intro', () => {
|
|
assert.equal(initialStepForMode('store'), 'greeting');
|
|
assert.equal(initialStepForMode('dial'), 'intro');
|
|
});
|
|
|
|
test('buildTwiml: store entry chain references next steps', () => {
|
|
const greeting = buildTwiml({ mode: 'store', step: 'greeting', testId: TEST_ID, config: CFG });
|
|
assert.match(greeting, /<Pause length="5"\/>/);
|
|
assert.match(greeting, /step=dtmf/);
|
|
|
|
const dtmf = buildTwiml({ mode: 'store', step: 'dtmf', testId: TEST_ID, config: CFG });
|
|
assert.match(dtmf, /<Play digits="wwww1"\/>/);
|
|
assert.match(dtmf, /step=wait/);
|
|
|
|
const wait = buildTwiml({ mode: 'store', step: 'wait', testId: TEST_ID, config: CFG });
|
|
assert.match(wait, /<Pause length="45"\/>/);
|
|
assert.match(wait, /step=intro/);
|
|
});
|
|
|
|
test('buildTwiml: shared core chain', () => {
|
|
for (const step of CORE_STEP_ORDER) {
|
|
const xml = buildTwiml({ mode: 'dial', step, testId: TEST_ID, config: CFG });
|
|
assert.match(xml, /^<\?xml/);
|
|
assert.match(xml, /<Response>/);
|
|
if (step === 'done') {
|
|
assert.match(xml, /<Hangup\/>/);
|
|
}
|
|
}
|
|
|
|
const intro = buildTwiml({ mode: 'dial', step: 'intro', testId: TEST_ID, config: CFG });
|
|
assert.match(intro, /Intro message/);
|
|
assert.match(intro, /step=listen/);
|
|
|
|
const listen = buildTwiml({ mode: 'dial', step: 'listen', testId: TEST_ID, config: CFG });
|
|
assert.match(listen, /<Pause length="60"\/>/);
|
|
|
|
const outro = buildTwiml({ mode: 'dial', step: 'outro', testId: TEST_ID, config: CFG });
|
|
assert.match(outro, /Outro message/);
|
|
});
|
|
|
|
test('buildTwiml: store entry order ends at intro then core', () => {
|
|
assert.deepEqual(STORE_ENTRY_STEP_ORDER, ['greeting', 'dtmf', 'wait']);
|
|
const last = buildTwiml({ mode: 'store', step: 'wait', testId: TEST_ID, config: CFG });
|
|
assert.match(last, /step=intro/);
|
|
});
|
|
|
|
test('normalizeE164', () => {
|
|
assert.equal(normalizeE164('2125550100'), '+12125550100');
|
|
assert.equal(normalizeE164('+12125550100'), '+12125550100');
|
|
assert.equal(normalizeE164('bad'), null);
|
|
});
|
|
|
|
test('parseCallTestArgs', () => {
|
|
assert.deepEqual(parseCallTestArgs(['782']), { kind: 'store', storeNum: '782', dialOverride: null });
|
|
assert.deepEqual(parseCallTestArgs(['store', '782']), { kind: 'store', storeNum: '782', dialOverride: null });
|
|
assert.deepEqual(parseCallTestArgs(['dial', '+12125550100']), { kind: 'dial', dial: '+12125550100' });
|
|
assert.deepEqual(parseCallTestArgs(['+12125550100']), { kind: 'dial', dial: '+12125550100' });
|
|
assert.deepEqual(parseCallTestArgs(['status', 'abc']), { kind: 'status', testId: 'abc' });
|
|
});
|
|
|
|
test('buildVoiceWebhookUrl uses TWILIO_WEBHOOK_BASE_URL', () => {
|
|
const prev = process.env.TWILIO_WEBHOOK_BASE_URL;
|
|
process.env.TWILIO_WEBHOOK_BASE_URL = 'https://example.com';
|
|
try {
|
|
const url = buildVoiceWebhookUrl(TEST_ID, 'store', 'greeting');
|
|
assert.match(url, /^https:\/\/example\.com\/twilio\/calltest\/voice\?/);
|
|
assert.match(url, /testId=11111111/);
|
|
assert.match(url, /mode=store/);
|
|
assert.match(url, /step=greeting/);
|
|
} finally {
|
|
if (prev == null) delete process.env.TWILIO_WEBHOOK_BASE_URL;
|
|
else process.env.TWILIO_WEBHOOK_BASE_URL = prev;
|
|
}
|
|
});
|
|
|
|
test('getCallTestConfig defaults listen to 60', () => {
|
|
const cfg = getCallTestConfig();
|
|
assert.equal(cfg.listenSec, 60);
|
|
assert.equal(cfg.dtmf, '1');
|
|
});
|