NODEDC_MISSION_CORE/apps/control-station/test/runtimeAcquisitionGuard.tes...

96 lines
3.1 KiB
JavaScript

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/);
});