const assert = require("node:assert/strict"); const test = require("node:test"); const fs = require("node:fs"); const path = require("node:path"); const vm = require("node:vm"); const ts = require("typescript"); // Execute the actual renderer with a small DOM/IPC fixture; no network or audio. const source = fs.readFileSync(path.join(__dirname, "../src/hardware.ts"), "utf8"); const compiled = ts.transpileModule(source, { compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.CommonJS }, }).outputText; function fixture(overrides = {}) { const elements = new Map(); const element = () => ({ style: {}, value: "", textContent: "", disabled: false, children: [], append(...items) { this.children.push(...items); }, prepend(...items) { this.children.unshift(...items); }, replaceChildren(...items) { this.children = items; }, querySelector() { return null; }, addEventListener() {}, }); const get = (id) => { if (!elements.has(id)) elements.set(id, element()); return elements.get(id); }; const events = []; const closes = []; const texts = []; const created = { conversation_id: "test-conversation", session: {}, runtime: { transport: "low_load", config_digest: "digest", session_nonce: "nonce", provider_session_ref: "ref", bot_id: "test-bot" }, session_config: { authorized_context: "test", prompt_bundle_version: "test-v1" }, }; const ipc = { getRuntimeDefaults: async () => ({}), getHardwareRuntimeDefaults: async () => ({}), onHardwareProviderEvent: () => () => {}, createHardwareAgentSession: async () => created, closeHardwareAgent: async (input) => { closes.push(input); }, hardwareAgentEvent: async (input) => { events.push(input); return { status: "FAILED" }; }, sendHardwareAgentText: async (input) => { texts.push(input); }, ...overrides, }; const context = vm.createContext({ exports: {}, require: () => ({}), console, URL, document: { querySelector: () => get("app"), getElementById: get, createElement: element }, window: { deviceSimulator: ipc, addEventListener() {}, clearInterval() {}, setTimeout, setInterval() {} }, }); vm.runInContext(compiled + `\nglobalThis.renderer = { state, controls, setPhase, setCheck, resetSessionState, failHardwareConversation, stopHardwareConversation, startHardwareConversation, handleProviderEvent, sendTextQuestion, buildReport };`, context); return { r: context.renderer, events, closes, texts, created, get, ipc }; } test("provider error plus connect rejection sends one failure, including late duplicates", async () => { const f = fixture(); const r = f.r; f.ipc.connectHardwareAgent = async () => { void r.handleProviderEvent({ type: "error", error: { code: "internal_error", message: "StartVoiceChat failed" } }); throw new Error("wrapped connect rejection"); }; r.setPhase("ready", "ready"); await r.startHardwareConversation(); await r.failHardwareConversation("SECOND_FAILURE"); await r.stopHardwareConversation(); await r.handleProviderEvent({ type: "error", error: { message: "late error" } }); assert.equal(f.events.length, 1); assert.equal(f.events[0].eventType, "session_failed"); assert.equal(f.events[0].errorCode, "VOLC_HARDWARE_AGENT_ERROR"); assert.equal(f.closes.length, 1); assert.equal(r.state.failure, "internal_error: StartVoiceChat failed"); assert.equal(r.state.phase, "error"); assert.equal(r.controls.stop.disabled, true); assert.equal(r.controls.check.disabled, false); }); test("concurrent failure callers share pending cleanup; late events cannot reactivate", async () => { let release; const gate = new Promise((resolve) => { release = resolve; }); const f = fixture({ closeHardwareAgent: () => gate }); f.r.state.platformSession = f.created; f.r.state.failure = "first cause"; f.r.setPhase("active", "active"); const first = f.r.failHardwareConversation("FIRST"); const second = f.r.failHardwareConversation("SECOND"); assert.equal(first, second); assert.equal(f.r.state.phase, "stopping"); await f.r.handleProviderEvent({ type: "response.done" }); assert.equal(f.r.state.phase, "stopping"); release(); await first; assert.equal(f.events.length, 1); assert.equal(f.events[0].errorCode, "FIRST"); await f.r.handleProviderEvent({ type: "transport.close", code: 1011 }); assert.equal(f.r.state.checks.get("provider_closed").status, "failed"); f.r.controls.textQuestion.value = "should not send"; await f.r.sendTextQuestion(); assert.equal(f.texts.length, 0); }); test("new call clears stale checks, duration and failure while retaining device preparation", async () => { const f = fixture(); f.r.state.platformSession = f.created; f.r.state.failure = "old failure"; await f.r.failHardwareConversation("OLD"); for (const id of f.r.state.checks.keys()) f.r.setCheck(id, "passed", "old"); f.get("duration").textContent = "48:15"; f.r.resetSessionState(); assert.equal(f.r.state.failure, undefined); assert.equal(f.r.state.failureTask, undefined); assert.equal(f.get("duration").textContent, "00:00"); assert.equal(f.r.state.checks.get("platform_authenticated").status, "passed"); assert.equal(f.r.state.checks.get("credential_resolved").status, "passed"); assert.equal(f.r.state.checks.get("platform_completed").status, "pending"); f.r.state.platformSession = { ...f.created, conversation_id: "next-conversation" }; await f.r.failHardwareConversation("NEW"); assert.equal(f.events.length, 2); assert.equal(f.events[1].conversationID, "next-conversation"); assert.equal(f.events[1].sequenceNo, 1); }); test("failed platform receipt does not trigger a new terminal event on hangup", async () => { let attempts = 0; const f = fixture({ hardwareAgentEvent: async () => { attempts += 1; throw new Error("network unavailable"); } }); f.r.state.platformSession = f.created; await f.r.failHardwareConversation("FIRST"); await f.r.stopHardwareConversation(); assert.equal(attempts, 1); assert.equal(f.r.state.phase, "error"); assert.equal(f.r.buildReport().checks.find((c) => c.id === "platform_completed").status, "failed"); }); test("connection rejection without a provider event still reports failure once", async () => { const f = fixture({ connectHardwareAgent: async () => { throw new Error("connect timeout"); } }); f.r.setPhase("ready", "ready"); await f.r.startHardwareConversation(); assert.equal(f.events.length, 1); assert.equal(f.events[0].errorCode, "WINDOWS_HARDWARE_START_FAILED"); assert.match(f.r.state.failure, /connect timeout/); assert.equal(f.r.state.phase, "error"); }); test("normal hangup still reports completed and closes normally", async () => { const f = fixture(); f.ipc.hardwareAgentEvent = async (input) => { f.events.push(input); return { status: "COMPLETED" }; }; f.r.state.platformSession = f.created; f.r.setPhase("active", "active"); await f.r.stopHardwareConversation(); assert.equal(f.events.length, 1); assert.equal(f.events[0].eventType, "session_ended"); assert.equal(f.closes[0].code, 1000); assert.equal(f.r.state.phase, "completed"); assert.equal(f.r.state.failureTask, undefined); assert.equal(f.r.controls.start.disabled, false); });