test(voice-call): cover helper utilities

This commit is contained in:
Vincent Koc 2026-03-22 19:44:47 -07:00
parent ac7b7f5536
commit bbd4b39afb
4 changed files with 108 additions and 0 deletions

View File

@ -0,0 +1,22 @@
import { describe, expect, it } from "vitest";
import { isAllowlistedCaller, normalizePhoneNumber } from "./allowlist.js";
describe("voice-call allowlist", () => {
it("normalizes phone numbers by stripping non-digits", () => {
expect(normalizePhoneNumber("+1 (415) 555-0123")).toBe("14155550123");
expect(normalizePhoneNumber(" 020-7946-0958 ")).toBe("02079460958");
expect(normalizePhoneNumber("")).toBe("");
expect(normalizePhoneNumber()).toBe("");
});
it("matches normalized allowlist entries and rejects blank callers", () => {
expect(
isAllowlistedCaller("14155550123", ["+1 (415) 555-0123", " 020-7946-0958 "]),
).toBe(true);
expect(isAllowlistedCaller("02079460958", ["+1 (415) 555-0123", " 020-7946-0958 "])).toBe(
true,
);
expect(isAllowlistedCaller("", ["+1 (415) 555-0123"])).toBe(false);
expect(isAllowlistedCaller("14155550123", ["", "abc"])).toBe(false);
});
});

View File

@ -0,0 +1,40 @@
import { describe, expect, it } from "vitest";
import { deepMergeDefined } from "./deep-merge.js";
describe("deepMergeDefined", () => {
it("deep merges nested plain objects and preserves base values for undefined overrides", () => {
expect(
deepMergeDefined(
{
provider: { voice: "alloy", language: "en" },
enabled: true,
},
{
provider: { voice: "echo", language: undefined },
enabled: undefined,
},
),
).toEqual({
provider: { voice: "echo", language: "en" },
enabled: true,
});
});
it("replaces non-objects directly and blocks dangerous prototype keys", () => {
expect(deepMergeDefined(["a"], ["b"])).toEqual(["b"]);
expect(deepMergeDefined("base", undefined)).toBe("base");
expect(
deepMergeDefined(
{ safe: { keep: true } },
{
safe: { next: true },
__proto__: { polluted: true },
constructor: { polluted: true },
prototype: { polluted: true },
},
),
).toEqual({
safe: { keep: true, next: true },
});
});
});

View File

@ -0,0 +1,12 @@
import { describe, expect, it } from "vitest";
import { generateNotifyTwiml } from "./twiml.js";
describe("generateNotifyTwiml", () => {
it("renders escaped xml with the requested voice", () => {
expect(generateNotifyTwiml(`Call <ended> & "logged"`, "Polly.Joanna")).toBe(`<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say voice="Polly.Joanna">Call &lt;ended&gt; &amp; &quot;logged&quot;</Say>
<Hangup/>
</Response>`);
});
});

View File

@ -0,0 +1,34 @@
import { describe, expect, it } from "vitest";
import {
DEFAULT_POLLY_VOICE,
escapeXml,
getOpenAiVoiceNames,
isOpenAiVoice,
mapVoiceToPolly,
} from "./voice-mapping.js";
describe("voice mapping", () => {
it("escapes xml-special characters", () => {
expect(escapeXml(`5 < 6 & "quote" 'apostrophe' > 4`)).toBe(
"5 &lt; 6 &amp; &quot;quote&quot; &apos;apostrophe&apos; &gt; 4",
);
});
it("maps openai voices, passes through provider voices, and falls back to default", () => {
expect(mapVoiceToPolly("alloy")).toBe("Polly.Joanna");
expect(mapVoiceToPolly("ECHO")).toBe("Polly.Matthew");
expect(mapVoiceToPolly("Polly.Brian")).toBe("Polly.Brian");
expect(mapVoiceToPolly("Google.en-US-Standard-C")).toBe("Google.en-US-Standard-C");
expect(mapVoiceToPolly("unknown")).toBe(DEFAULT_POLLY_VOICE);
expect(mapVoiceToPolly(undefined)).toBe(DEFAULT_POLLY_VOICE);
});
it("detects known openai voices and lists them", () => {
expect(isOpenAiVoice("nova")).toBe(true);
expect(isOpenAiVoice("NOVA")).toBe(true);
expect(isOpenAiVoice("Polly.Joanna")).toBe(false);
expect(getOpenAiVoiceNames()).toEqual(
expect.arrayContaining(["alloy", "echo", "fable", "nova", "onyx", "shimmer"]),
);
});
});