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)); async function readWorkspaceFile(relativePath: string) { return readFile(path.join(testsDir, "..", relativePath), "utf8"); } test("RealtimeRefresh supports project-scoped refresh filtering", async () => { const source = await readWorkspaceFile("src/components/app-runtime.tsx"); assert.match(source, /projectId\?: string/, "expected RealtimeRefresh to accept an optional projectId"); assert.match(source, /projectIds\?: string\[]/, "expected RealtimeRefresh to accept optional projectIds"); assert.match( source, /conversationUpdatedNotes\?: string\[]/, "expected RealtimeRefresh to accept optional conversationUpdatedNotes", ); assert.match( source, /shouldRefreshRealtimeEvent\(\{/, "expected RealtimeRefresh to delegate scoped filtering to helper logic", ); assert.match( source, /planThrottledRefresh\(throttleState, Date\.now\(\), 400\)/, "expected RealtimeRefresh to throttle burst refreshes on the client", ); }); test("project conversation pages wire project-scoped realtime refresh", async () => { const [projectPage, goalsPage, versionsPage, threadStatusPage] = await Promise.all([ readWorkspaceFile("src/app/conversations/[projectId]/page.tsx"), readWorkspaceFile("src/app/conversations/[projectId]/goals/page.tsx"), readWorkspaceFile("src/app/conversations/[projectId]/versions/page.tsx"), readWorkspaceFile("src/app/conversations/[projectId]/thread-status/page.tsx"), ]); assert.match(projectPage, /projectId=\{detail\.project\.id\}/, "expected project chat page to pass projectId into RealtimeRefresh"); for (const [label, source] of [ ["goals", goalsPage], ["versions", versionsPage], ["thread-status", threadStatusPage], ] as const) { assert.match(source, / { const [goalsPage, versionsPage] = await Promise.all([ readWorkspaceFile("src/app/conversations/[projectId]/goals/page.tsx"), readWorkspaceFile("src/app/conversations/[projectId]/versions/page.tsx"), ]); assert.match( goalsPage, /project\.projectUnderstanding\?\.projectGoal/, "expected goals page to surface the latest synced project goal summary", ); assert.match( goalsPage, /project\.projectUnderstanding\?\.currentProgress/, "expected goals page to surface the latest synced project progress summary", ); assert.match( goalsPage, /project\.projectUnderstanding\?\.recommendedNextStep/, "expected goals page to surface the latest synced recommended next step", ); assert.match( versionsPage, /PageNav title="版本记录"/, "expected versions page to use the compact title copy", ); }); test("folder conversation page wires folder thread ids into realtime refresh", async () => { const folderPage = await readWorkspaceFile("src/app/conversations/folders/[folderKey]/page.tsx"); assert.match(folderPage, / thread\.projectId\)\}/, "expected folder page to scope refreshes to folder thread project ids"); assert.match(folderPage, /deviceId=\{folder\.deviceId\}/, "expected folder page to scope device-only refreshes to the folder device"); assert.match(folderPage, /"conversation\.updated"/, "expected folder page to listen to conversation updates"); }); test("folder conversation page does not render a redundant intro card before the thread list", async () => { const folderPage = await readWorkspaceFile("src/app/conversations/folders/[folderKey]/page.tsx"); assert.doesNotMatch( folderPage, /rounded-2xl border border-\[#E5E5EA\] bg-white px-4 py-4/, "expected folder page to skip the standalone intro card", ); assert.doesNotMatch( folderPage, /folder\.deviceName/, "expected folder page to avoid repeating device info above the thread list", ); assert.doesNotMatch( folderPage, /folder\.threadCount/, "expected folder page to avoid repeating thread count above the thread list", ); }); test("forward page wires realtime refresh for visible source and target projects", async () => { const forwardPage = await readWorkspaceFile("src/app/conversations/[projectId]/forward/page.tsx"); assert.match(forwardPage, / target\.id\)\]\}/, "expected forward page to scope refreshes to visible source and target project ids", ); assert.match(forwardPage, /"conversation\.updated"/, "expected forward page to listen to conversation updates"); });