test(ui): cover realtime media abort ordering

This commit is contained in:
Vincent Koc
2026-08-02 18:13:25 +08:00
parent e4f5a42210
commit ff8faac465
@@ -158,6 +158,43 @@ describe("realtime Talk microphone inputs", () => {
expect(getUserMedia).not.toHaveBeenCalled();
});
it("releases media when cancellation follows browser permission resolution", async () => {
const stop = vi.fn();
let resolveMedia: (stream: MediaStream) => void = () => undefined;
const pending = new Promise<MediaStream>((resolve) => {
resolveMedia = resolve;
});
vi.stubGlobal("navigator", {
mediaDevices: { getUserMedia: vi.fn(() => pending) },
});
const controller = new AbortController();
const opening = openRealtimeTalkInput(undefined, { signal: controller.signal });
resolveMedia({ getTracks: () => [{ stop }] } as unknown as MediaStream);
controller.abort();
await expect(opening).rejects.toMatchObject({ name: "AbortError" });
expect(stop).toHaveBeenCalledOnce();
});
it("keeps cancellation precedence over a late media rejection", async () => {
let rejectMedia: (error: unknown) => void = () => undefined;
const pending = new Promise<MediaStream>((_resolve, reject) => {
rejectMedia = reject;
});
vi.stubGlobal("navigator", {
mediaDevices: { getUserMedia: vi.fn(() => pending) },
});
const controller = new AbortController();
const reason = new DOMException("cancelled", "AbortError");
const opening = openRealtimeTalkCamera(undefined, { signal: controller.signal });
controller.abort(reason);
rejectMedia(new DOMException("denied", "NotAllowedError"));
await expect(opening).rejects.toBe(reason);
});
it("acquires camera separately so camera errors cannot stop microphone input", async () => {
const audio = { getTracks: () => [] } as unknown as MediaStream;
const camera = { getTracks: () => [] } as unknown as MediaStream;