test: reuse Google Live bridge fixtures (#156161)

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Peter Steinberger 2026-09-22 21:36:47 -07:00 • committed by GitHub
parent 7f0ea8e546
commit 06bb025f03
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -280,10 +280,8 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
});
it("connects with Google Live setup config and tool declarations", async () => {
const provider = buildGoogleRealtimeVoiceProvider();
const bridge = provider.createBridge({
const bridge = createGoogleLiveBridge({
providerConfig: {
apiKey: "gemini-key",
model: "gemini-live-2.5-flash-preview",
voice: "Kore",
temperature: 0.3,
@ -319,8 +317,6 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
},
},
],
onAudio: vi.fn(),
onClearAudio: vi.fn(),
});
await bridge.connect();
@ -688,12 +684,7 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
const pendingSession = createDeferred<MockGoogleLiveSession>();
const connectedSession = createMockGoogleLiveSession();
connectMock.mockReturnValueOnce(pendingSession.promise);
const provider = buildGoogleRealtimeVoiceProvider();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
});
const bridge = createGoogleLiveBridge();
const firstConnect = bridge.connect();
const secondConnect = bridge.connect();
@ -712,13 +703,9 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
connectMock
.mockReturnValueOnce(pendingSession.promise)
.mockResolvedValueOnce(replacementSession);
const provider = buildGoogleRealtimeVoiceProvider();
const onReady = vi.fn();
const onError = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onReady,
onError,
});
@ -760,16 +747,12 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("preserves transcript fragments and interruption while reusing a resumption handle", async () => {
vi.useFakeTimers();
const provider = buildGoogleRealtimeVoiceProvider();
const onTranscript = vi.fn();
const onResponseDone = vi.fn();
const bridge = provider.createBridge({
const bridge = createGoogleLiveBridge({
providerConfig: {
model: "gemini-2.5-flash-native-audio-preview-12-2025",
apiKey: "gemini-key",
},
onAudio: vi.fn(),
onClearAudio: vi.fn(),
onTranscript,
onResponseDone,
});
@ -798,13 +781,9 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("preserves tool ownership while reusing a resumption handle", async () => {
vi.useFakeTimers();
const provider = buildGoogleRealtimeVoiceProvider();
const onError = vi.fn();
const onToolCall = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onError,
onToolCall,
});
@ -851,13 +830,9 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("fails closed when resumable tool responses exceed the reconnect buffer", async () => {
vi.useFakeTimers();
const provider = buildGoogleRealtimeVoiceProvider();
const onError = vi.fn();
const onClose = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onToolCall: vi.fn(),
onError,
onClose,
@ -887,12 +862,8 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("drops queued reconnect responses when the resumed session cancels their call", async () => {
vi.useFakeTimers();
const provider = buildGoogleRealtimeVoiceProvider();
const onEvent = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onToolCall: vi.fn(),
onEvent,
});
@ -927,14 +898,10 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("resets tool ownership and interruption before a fresh automatic reconnect", async () => {
vi.useFakeTimers();
const provider = buildGoogleRealtimeVoiceProvider();
const onToolCall = vi.fn();
const onEvent = vi.fn();
const onResponseDone = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onToolCall,
onEvent,
onResponseDone,
@ -978,16 +945,12 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("preserves continuity when resumability recovers before reconnect", async () => {
vi.useFakeTimers();
const provider = buildGoogleRealtimeVoiceProvider();
const onEvent = vi.fn();
const onTranscript = vi.fn();
const bridge = provider.createBridge({
const bridge = createGoogleLiveBridge({
providerConfig: {
model: "gemini-2.5-flash-native-audio-preview-12-2025",
apiKey: "gemini-key",
},
onAudio: vi.fn(),
onClearAudio: vi.fn(),
onEvent,
onTranscript,
});
@ -1021,16 +984,12 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("drops unfinished hypotheses when a new session has no continuity", async () => {
vi.useFakeTimers();
const provider = buildGoogleRealtimeVoiceProvider();
const onTranscript = vi.fn();
const bridge = provider.createBridge({
const bridge = createGoogleLiveBridge({
providerConfig: {
model: "gemini-2.5-flash-native-audio-preview-12-2025",
apiKey: "gemini-key",
sessionResumption: false,
},
onAudio: vi.fn(),
onClearAudio: vi.fn(),
onTranscript,
});
@ -1053,18 +1012,14 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it.each([undefined, "invalidated-handle"])("invalidates resume handles %#", async (newHandle) => {
vi.useFakeTimers();
try {
const provider = buildGoogleRealtimeVoiceProvider();
const onClose = vi.fn();
const onError = vi.fn();
const onEvent = vi.fn();
const onTranscript = vi.fn();
const bridge = provider.createBridge({
const bridge = createGoogleLiveBridge({
providerConfig: {
model: "gemini-2.5-flash-native-audio-preview-12-2025",
apiKey: "gemini-key",
},
onAudio: vi.fn(),
onClearAudio: vi.fn(),
onClose,
onError,
onEvent,
@ -1217,13 +1172,10 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("emits one continuity reset across failed fresh reconnect attempts", async () => {
vi.useFakeTimers();
const provider = buildGoogleRealtimeVoiceProvider();
const onClose = vi.fn();
const onEvent = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key", sessionResumption: false },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
providerConfig: { sessionResumption: false },
onClose,
onEvent,
});
@ -1253,18 +1205,14 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
connectMock
.mockReturnValueOnce(Promise.resolve(session))
.mockReturnValueOnce(pendingSession.promise);
const provider = buildGoogleRealtimeVoiceProvider();
const onEvent = vi.fn();
const onReady = vi.fn();
const onTranscript = vi.fn();
const bridge = provider.createBridge({
const bridge = createGoogleLiveBridge({
providerConfig: {
model: "gemini-2.5-flash-native-audio-preview-12-2025",
apiKey: "gemini-key",
sessionResumption: false,
},
onAudio: vi.fn(),
onClearAudio: vi.fn(),
onEvent,
onReady,
onTranscript,
@ -1336,12 +1284,8 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
const pendingSession = createDeferred<MockGoogleLiveSession>();
const connectedSession = createMockGoogleLiveSession();
connectMock.mockReturnValueOnce(pendingSession.promise);
const provider = buildGoogleRealtimeVoiceProvider();
const onReady = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onReady,
});
@ -1379,12 +1323,8 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("copies and bounds pending audio by aggregate bytes before activation", async () => {
const connectedSession = createMockGoogleLiveSession();
connectMock.mockResolvedValueOnce(connectedSession);
const provider = buildGoogleRealtimeVoiceProvider();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
const bridge = createGoogleLiveBridge({
audioFormat: REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ,
onAudio: vi.fn(),
onClearAudio: vi.fn(),
});
const backing = Buffer.alloc(2 * 1024 * 1024);
const firstChunk = backing.subarray(0, 512 * 1024);
@ -1412,12 +1352,8 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("bounds pending audio by chunk count before activation", async () => {
const connectedSession = createMockGoogleLiveSession();
connectMock.mockResolvedValueOnce(connectedSession);
const provider = buildGoogleRealtimeVoiceProvider();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
const bridge = createGoogleLiveBridge({
audioFormat: REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ,
onAudio: vi.fn(),
onClearAudio: vi.fn(),
});
for (let index = 0; index < 321; index += 1) {
@ -1434,13 +1370,9 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
it("drops reconnect audio on terminal exhaustion until an explicit reconnect owns admission", async () => {
vi.useFakeTimers();
const reconnectedSession = createMockGoogleLiveSession();
const provider = buildGoogleRealtimeVoiceProvider();
const onClose = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
const bridge = createGoogleLiveBridge({
audioFormat: REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ,
onAudio: vi.fn(),
onClearAudio: vi.fn(),
onClose,
});
@ -1480,13 +1412,9 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
const pendingSession = createDeferred<MockGoogleLiveSession>();
const lateSession = createMockGoogleLiveSession();
connectMock.mockReturnValueOnce(pendingSession.promise);
const provider = buildGoogleRealtimeVoiceProvider();
const onReady = vi.fn();
const onClose = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onReady,
onClose,
});
@ -1514,11 +1442,7 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
const pendingSession = createDeferred<MockGoogleLiveSession>();
const connectedSession = createMockGoogleLiveSession();
connectMock.mockReturnValueOnce(pendingSession.promise);
const provider = buildGoogleRealtimeVoiceProvider();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onReady: () => {
throw new Error("ready callback failed");
},
@ -1641,12 +1565,9 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
});
it("converts Google PCM output to mu-law audio", async () => {
const provider = buildGoogleRealtimeVoiceProvider();
const onAudio = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
const bridge = createGoogleLiveBridge({
onAudio,
onClearAudio: vi.fn(),
});
const pcm24k = Buffer.alloc(480);
pcm24k.set([0xfb, 0xff]);
@ -1675,13 +1596,10 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
});
it("can keep Google PCM output as PCM16 24 kHz audio", async () => {
const provider = buildGoogleRealtimeVoiceProvider();
const onAudio = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
const bridge = createGoogleLiveBridge({
audioFormat: REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ,
onAudio,
onClearAudio: vi.fn(),
});
const pcm24k = Buffer.alloc(480);
@ -1711,16 +1629,13 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
["non-canonical pad bits", "ZE=="],
["mixed alphabet", "aGVsbG8+_"],
])("terminates the session for %s in output audio", async (_scenario, data) => {
const provider = buildGoogleRealtimeVoiceProvider();
const onAudio = vi.fn();
const onError = vi.fn();
const onClose = vi.fn();
const onTranscript = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
const bridge = createGoogleLiveBridge({
audioFormat: REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ,
onAudio,
onClearAudio: vi.fn(),
onError,
onClose,
onTranscript,
@ -1755,12 +1670,8 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
});
it("uses official output transcription instead of model-turn text", async () => {
const provider = buildGoogleRealtimeVoiceProvider();
const onTranscript = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onTranscript,
});
@ -1820,15 +1731,11 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
});
it("allows each role's UTF-8 transcript limit and releases it on finished", async () => {
const provider = buildGoogleRealtimeVoiceProvider();
const onTranscript = vi.fn();
const bridge = provider.createBridge({
const bridge = createGoogleLiveBridge({
providerConfig: {
model: "gemini-2.5-flash-native-audio-preview-12-2025",
apiKey: "gemini-key",
},
onAudio: vi.fn(),
onClearAudio: vi.fn(),
onTranscript,
});
@ -1858,17 +1765,13 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
});
it("terminates and clears a runaway transcript stream at the UTF-8 byte limit", async () => {
const provider = buildGoogleRealtimeVoiceProvider();
const onError = vi.fn();
const onClose = vi.fn();
const onTranscript = vi.fn();
const bridge = provider.createBridge({
const bridge = createGoogleLiveBridge({
providerConfig: {
model: "gemini-2.5-flash-native-audio-preview-12-2025",
apiKey: "gemini-key",
},
onAudio: vi.fn(),
onClearAudio: vi.fn(),
onError,
onClose,
onTranscript,
@ -2023,12 +1926,8 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
});
it("deduplicates replayed Google Live tool calls by call id", async () => {
const provider = buildGoogleRealtimeVoiceProvider();
const onToolCall = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onToolCall,
});
@ -2065,13 +1964,9 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
});
it("ignores late results after Google cancels a tool call", async () => {
const provider = buildGoogleRealtimeVoiceProvider();
const onEvent = vi.fn();
const onError = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onToolCall: vi.fn(),
onEvent,
onError,
@ -2100,14 +1995,10 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
});
it("fails closed when Google exceeds the tool-call session limit", async () => {
const provider = buildGoogleRealtimeVoiceProvider();
const onToolCall = vi.fn();
const onError = vi.fn();
const onClose = vi.fn();
const bridge = provider.createBridge({
providerConfig: { apiKey: "gemini-key" },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
const bridge = createGoogleLiveBridge({
onToolCall,
onError,
onClose,
@ -2246,10 +2137,8 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
"rejects %s Google Live tool results while keeping the call retryable",
async (_label, create) => {
const onError = vi.fn();
const bridge = buildGoogleRealtimeVoiceProvider().createBridge({
const bridge = createGoogleLiveBridge({
providerConfig: { apiKey: ["google", "test"].join("-") },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
onError,
onToolCall: vi.fn(),
});
@ -2272,10 +2161,8 @@ describe("buildGoogleRealtimeVoiceProvider", () => {
);
it("preserves valid Google Live tool results and nested serialization keys", async () => {
const bridge = buildGoogleRealtimeVoiceProvider().createBridge({
const bridge = createGoogleLiveBridge({
providerConfig: { apiKey: ["google", "test"].join("-") },
onAudio: vi.fn(),
onClearAudio: vi.fn(),
onToolCall: vi.fn(),
});
const objectSerialization = vi.fn((key: string) => ({ key }));