import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import { after, before, test } from "node:test"; import { createServer } from "vite"; let server; let guard; before(async () => { server = await createServer({ appType: "custom", logLevel: "silent", server: { middlewareMode: true }, }); guard = await server.ssrLoadModule("/src/core/runtime/acquisitionGuard.ts"); }); after(async () => { await server?.close(); }); function runtimeState(acquisitionState, cleanupPending = false) { return { phase: "idle", sourceMode: "idle", acquisition: acquisitionState === null ? null : { acquisitionId: "acq-1", deviceId: "device-1", deviceSessionId: "device-session-1", compatibilityProfileId: "profile-1", controlMode: "operator-manual", state: acquisitionState, stateRevision: 1, operatorInstructions: [], cleanupPending, }, }; } test("every nonterminal acquisition phase blocks saved and manual source replacement", () => { for (const state of [ "preparing", "prepared", "awaiting_external_start", "starting", "acquiring", "awaiting_external_stop", "stopping", "finalizing", ]) { assert.equal(guard.isSpatialSourceSwitchBlocked(runtimeState(state)), true, state); } }); test("terminal or absent acquisitions allow an explicit source selection", () => { for (const state of ["completed", "failed", "aborted", "interrupted"]) { assert.equal(guard.isSpatialSourceSwitchBlocked(runtimeState(state)), false, state); } assert.equal(guard.isSpatialSourceSwitchBlocked(runtimeState(null)), false); assert.equal(guard.isSpatialSourceSwitchBlocked(null), false); }); test("an unknown acquisition state fails closed", () => { assert.equal( guard.isSpatialSourceSwitchBlocked(runtimeState("future_vendor_phase")), true, ); assert.match(guard.SPATIAL_SOURCE_SWITCH_BLOCKED_REASON, /Завершите текущий приём/); }); test("terminal acquisition with retained cleanup remains source-switch blocked", () => { assert.equal(guard.isSpatialSourceSwitchBlocked(runtimeState("failed", true)), true); assert.equal(guard.isSpatialSourceSwitchBlocked(runtimeState("failed", false)), false); }); test("saved-session and manual source controls share the acquisition guard", async () => { const appSource = await readFile(new URL("../src/App.tsx", import.meta.url), "utf8"); const sessionSelectSource = await readFile( new URL("../src/components/ObservationSessionSelect.tsx", import.meta.url), "utf8", ); const observationHookSource = await readFile( new URL("../src/core/observation/useObservationSessions.ts", import.meta.url), "utf8", ); assert.match(appSource, /blockedReason=\{sourceSwitchBlockedReason\}/); assert.match(appSource, /disabled=\{sourceSwitchBlocked \|\| !sourceDraft\.trim\(\)\}/); assert.match(appSource, /if \(sourceSwitchBlockedRef\.current\) return;/); assert.match(sessionSelectSource, /replayEnabled: blockedReason === null/); assert.match(observationHookSource, /!replayEnabledRef\.current/); });