test(voice-input): cover injected selection and unavailable preview

This commit is contained in:
yudshj authored and Yudong Han committed 2026-10-08 10:48:48 +08:00
1 parent 5aa153281f
commit d005b5edfd
2 files changed
+5

No files matched your search

@@ -20,6 +20,7 @@ it('reports unavailable recording and denied permission', async () => {
vi.stubGlobal('navigator', {})
const recording = new Recording(() => {})
await expect(recording.start()).rejects.toMatchObject({ kind: 'unavailable' })
await expect(recording.preview()).rejects.toMatchObject({ kind: 'unavailable' })
vi.stubGlobal('MediaRecorder', function RecorderStub() {})
vi.stubGlobal('navigator', { mediaDevices: { getUserMedia: async () => { throw new DOMException('denied', 'NotAllowedError') } } })
await expect(recording.start()).rejects.toMatchObject({ kind: 'permission' })
@@ -26,6 +26,7 @@ vi.mock('../src/client/readiness.ts', () => ({ observeReadiness: () => ({
function assertVoiceActions(value: Record<string, unknown>): asserts value is Record<string, unknown> & VoiceInputInjected {
assert(typeof value.openSettings === 'function')
assert(typeof value.createRecording === 'function')
assert(typeof value.selectMicrophone === 'function')
assert(typeof value.configure === 'function')
assert(typeof value.prepare === 'function')
assert(typeof value.cancelPreparation === 'function')
@@ -128,9 +129,12 @@ it('joins the same audio closure when cancellation overlaps Client plugin withdr
const entry = b.ctx.slots.entries('conversation.input.activity').find(item => item.component === VoiceInput)!
const actions = entry.inject!()
assertVoiceActions(actions)
actions.selectMicrophone({ id: 'usb', label: 'USB microphone' })
expect(actions.hooks.microphoneDevice.getSnapshot()).toEqual({ id: 'usb', label: 'USB microphone' })
const recording = actions.createRecording()
assert(recording instanceof Recording)
await recording.start()
expect(audio.getUserMedia.mock.calls.at(-1)?.[0].audio).toMatchObject({ deviceId: { exact: 'usb' } })
cancelled = recording.dispose()
const originalDispose = recording.dispose.bind(recording), joined = Promise.withResolvers<{ pending: Promise<void> }>()
vi.spyOn(recording, 'dispose').mockImplementationOnce(() => {