Files
boss/tests/project-chat-page-realtime-events.test.ts

86 lines
3.2 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import path from "node:path";
import { readFile } from "node:fs/promises";
import { fileURLToPath } from "node:url";
const testsDir = path.dirname(fileURLToPath(import.meta.url));
const projectChatPagePath = path.join(testsDir, "../src/app/conversations/[projectId]/page.tsx");
test("project chat page listens to conversation updates for realtime refresh", async () => {
const source = await readFile(projectChatPagePath, "utf8");
const realtimeRefreshConfig = source.match(/<RealtimeRefresh[\s\S]*?events=\{\[([\s\S]*?)\]\}/);
assert.ok(realtimeRefreshConfig, "expected project chat page to declare RealtimeRefresh events");
assert.match(
realtimeRefreshConfig[1],
/"conversation\.updated"/,
"expected project chat page to refresh when conversation.updated is emitted",
);
assert.match(
source,
/const warningMap = new Map<string, typeof detail\.executionWarnings\[number\]>\(\);/,
"expected project chat page to build a per-message warning map from executionWarnings",
);
assert.match(
source,
/detail\.conversationTasks\.find\(\(task\) => task\.requestMessageId === message\.id\)/,
"expected project chat page to bind lightweight conversation tasks to each message",
);
assert.match(
source,
/messageTask \? \(/,
"expected project chat page to render a compact per-message task status strip",
);
assert.match(
source,
/new Map<string, typeof detail\.executionWarnings\[number\]>\(\)/,
"expected project chat page to dedupe repeated warnings per message before rendering",
);
assert.match(
source,
/dedupedWarnings\.map\(\(warning\) => \(/,
"expected project chat page to render deduped warnings instead of the raw warning list",
);
assert.match(
source,
/detail\.conversationTasks\.length \?/,
"expected project chat page to keep a task status summary when lightweight conversation tasks exist",
);
assert.match(
source,
/resolveDispatchPlanComposerState\(detail\.dispatchPlans\)/,
"expected project chat page to derive dispatch plan composer state directly from project detail payload",
);
assert.doesNotMatch(
source,
/listDispatchPlansByProject/,
"expected project chat page to avoid a separate dispatch plan read outside project detail payload",
);
assert.match(
source,
/detail\.participantsPayload && detail\.participantsPayload\.repairRequired/,
"expected project chat page to surface a repair card when group participants are invalid",
);
assert.match(
source,
/修复群成员/,
"expected project chat page to show a visible repair members affordance",
);
assert.match(
source,
/detail\.participantsPayload\.repairReason/,
"expected project chat page to render the server-provided repair reason copy",
);
assert.match(
source,
/detail\.participantsPayload\.participants\.filter\(\(participant\) => participant\.status !== "active"\)/,
"expected project chat page to surface the concrete invalid group members instead of only a generic repair flag",
);
assert.match(
source,
/participant\.statusLabel \?\? participant\.status/,
"expected project chat page to show each invalid participant status label",
);
});