import test from 'node:test'; import assert from 'node:assert/strict'; import { VoiceStateMachine } from '../daemon/voice-state.js'; import { QvacScheduler } from '../daemon/qvac-scheduler.js'; test('voice state machine handles wake, reply, cancel, and idle sleep', () => { let now = 0; const voice = new VoiceStateMachine({ now: () => now, idleMs: 100 }); voice.wake(); voice.utterance(); voice.speak(); voice.finishSpeaking(); assert.equal(voice.state, 'LISTENING'); assert.equal(voice.command('hands off'), 'cancel'); assert.equal(voice.state, 'ARMED'); voice.wake(); now = 101; voice.expireIdle(); assert.equal(voice.state, 'SLEEPING'); }); test('typed questions wake an armed voice session before thinking', () => { const voice = new VoiceStateMachine(); voice.typedUtterance(); assert.equal(voice.state, 'THINKING'); }); test('QVAC scheduler prioritizes voice and keeps one active job', async () => { const scheduler = new QvacScheduler(); const order = []; const first = scheduler.run(async () => { order.push('first'); await new Promise((r) => setTimeout(r, 5)); }, { lane: 'background' }); const media = scheduler.run(async () => order.push('media'), { lane: 'background' }); const voice = scheduler.run(async () => order.push('voice'), { lane: 'voice' }); await Promise.all([first, media, voice]); assert.deepEqual(order, ['first', 'voice', 'media']); assert.deepEqual(scheduler.status(), { running: 0, queued: [] }); });