Files
NetMesh/components/ai/draftSendGate.test.ts

57 lines
1.7 KiB
TypeScript
Raw Permalink Normal View History

import assert from "node:assert/strict";
import test from "node:test";
import { readFileSync } from "node:fs";
import {
endDraftSend,
endSend,
endSendForKey,
tryBeginDraftSend,
tryBeginSend,
tryBeginSendForKey,
} from "./draftSendGate.ts";
test("draft send gate allows only one in-flight draft send at a time", () => {
const gate = { current: false };
assert.equal(tryBeginDraftSend(gate), true);
assert.equal(tryBeginDraftSend(gate), false);
endDraftSend(gate);
assert.equal(tryBeginDraftSend(gate), true);
});
test("send gate aliases cover session-mode re-entry the same way", () => {
const gate = { current: false };
assert.equal(tryBeginSend(gate), true);
assert.equal(tryBeginSend(gate), false);
endSend(gate);
assert.equal(tryBeginSend(gate), true);
});
test("module send latch survives across independent gate objects (remount-safe)", () => {
const key = `test-send-${Date.now()}-${Math.random()}`;
assert.equal(tryBeginSendForKey(key), true);
assert.equal(tryBeginSendForKey(key), false);
endSendForKey(key);
assert.equal(tryBeginSendForKey(key), true);
endSendForKey(key);
});
test("AIChatSidePanel gates every send including session mode", () => {
const source = readFileSync(new URL("../AIChatSidePanel.tsx", import.meta.url), "utf8");
assert.match(source, /tryBeginSendForKey\(sendGateKey\)/);
assert.match(source, /isAIChatSessionStreaming\(sessionId\)/);
assert.doesNotMatch(
source,
/isDraftMode && !tryBeginDraftSend/,
"session-mode sends must share the sync re-entry gate",
);
assert.doesNotMatch(
source,
/sendInFlightRef/,
"component refs reset on StrictMode remount; use module key latch",
);
});