import test from 'node:test' import assert from 'node:assert/strict' import { VoiceSession } from '../src/voice.mjs' import { VOICE_PRICING } from '../src/voice-usage.mjs' test('stopping during audio resume never requests microphone access afterward', async t => { let resume, microphoneRequests = 0, closed = 0 const originalContext = globalThis.AudioContext const originalNavigator = Object.getOwnPropertyDescriptor(globalThis, 'navigator') globalThis.AudioContext = class { resume() { return new Promise(resolve => { resume = resolve }) } async close() { closed++ } } Object.defineProperty(globalThis, 'navigator', { configurable: true, value: { mediaDevices: { async getUserMedia() { microphoneRequests++ return { getTracks: () => [] } } }, } }) t.after(() => { globalThis.AudioContext = originalContext if (originalNavigator) Object.defineProperty(globalThis, 'navigator', originalNavigator) else delete globalThis.navigator }) const voice = new VoiceSession({ model: VOICE_PRICING.model, onError() {} }) t.after(() => voice.stop()) const starting = voice.start() voice.stop() resume() await starting assert.equal(microphoneRequests, 0) assert.equal(closed, 1) assert.equal(voice.socket, undefined) }) test('a stopped session cannot reopen audio resources', async t => { let created = 0 const originalContext = globalThis.AudioContext globalThis.AudioContext = class { constructor() { created++ } async resume() {} async close() {} } t.after(() => { globalThis.AudioContext = originalContext }) const voice = new VoiceSession({ model: VOICE_PRICING.model, onError() {} }) voice.stop() await voice.start(false) // Clean up an incorrectly restarted interval even when this assertion fails. clearInterval(voice.usageTimer) assert.equal(created, 0) })