103 lines
5.0 KiB
TypeScript
103 lines
5.0 KiB
TypeScript
// SPEC: PJ2026-010401 Web工作台 draft-2026-06-18-r1; PJ2026-0104010803 唯一投影 draft-2026-06-18-p0-unique-projection; PJ2026-010403 API契约 draft-2026-06-18-r1.
|
|
// Responsibility: Regression tests for Workbench route parsing, server-state projection, and session tab status authority.
|
|
|
|
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import type { WorkbenchSessionRecord } from "../src/types/index.ts";
|
|
import { initialWorkbenchSessionIdFromLocation } from "../src/stores/workbench-projection.ts";
|
|
import { createWorkbenchServerState, reduceWorkbenchServerState, selectActiveMessages, selectActiveSession, selectSessionStatusAuthority, selectTraceAuthorityById } from "../src/stores/workbench-server-state.ts";
|
|
import { sessionToSessionTab, stableSessionList } from "../src/stores/workbench-session.ts";
|
|
|
|
test("Workbench route parsing accepts only session routes", () => {
|
|
assert.equal(initialWorkbenchSessionIdFromLocation({ pathname: "/workbench/sessions/ses_route" }), "ses_route");
|
|
assert.equal(initialWorkbenchSessionIdFromLocation({ pathname: "/workbench/sessions/cnv_route" }), null);
|
|
assert.equal(initialWorkbenchSessionIdFromLocation({ pathname: "/workspace/sessions/ses_route" }), null);
|
|
assert.equal(initialWorkbenchSessionIdFromLocation({ pathname: "/workbench" }), null);
|
|
});
|
|
|
|
test("Workbench server-state is keyed only by session and trace", () => {
|
|
const session: WorkbenchSessionRecord = {
|
|
sessionId: "ses_route",
|
|
threadId: "thr_route",
|
|
messages: [{ id: "msg_route", messageId: "msg_route", role: "user", title: "用户", text: "route prompt", status: "sent", createdAt: "2026-06-18T00:00:00.000Z", sessionId: "ses_route" }]
|
|
};
|
|
let state = createWorkbenchServerState();
|
|
state = reduceWorkbenchServerState(state, { type: "session.detail", session });
|
|
state = reduceWorkbenchServerState(state, { type: "trace.snapshot", traceId: "trc_route", trace: { traceId: "trc_route", status: "completed", events: [{ seq: 1, type: "done" }] } });
|
|
|
|
assert.equal(selectActiveSession(state, "ses_route")?.sessionId, "ses_route");
|
|
assert.deepEqual(selectActiveMessages(state, "ses_route").map((message) => message.id), ["msg_route"]);
|
|
assert.equal(selectTraceAuthorityById(state).trc_route?.traceId, "trc_route");
|
|
});
|
|
|
|
test("Workbench session list accepts server projection while keeping selected messages", () => {
|
|
const selected: WorkbenchSessionRecord = {
|
|
sessionId: "ses_live",
|
|
threadId: "thr_live",
|
|
status: "running",
|
|
lastTraceId: "trc_live",
|
|
messageCount: 2,
|
|
messages: [
|
|
{ id: "msg_live_user", messageId: "msg_live_user", role: "user", title: "用户", text: "ping", status: "sent", createdAt: "2026-06-18T00:00:00.000Z", sessionId: "ses_live", traceId: "trc_live" },
|
|
{ id: "msg_live_agent", messageId: "msg_live_agent", role: "agent", title: "Code Agent", text: "", status: "running", createdAt: "2026-06-18T00:00:01.000Z", sessionId: "ses_live", traceId: "trc_live" }
|
|
]
|
|
};
|
|
const serverSummary: WorkbenchSessionRecord = {
|
|
sessionId: "ses_live",
|
|
threadId: "thr_live",
|
|
status: "completed",
|
|
lastTraceId: "trc_live",
|
|
messageCount: 2,
|
|
updatedAt: "2026-06-18T00:00:03.000Z"
|
|
};
|
|
|
|
const next = stableSessionList([selected], [serverSummary], "ses_live", selected);
|
|
|
|
assert.equal(next[0]?.sessionId, "ses_live");
|
|
assert.equal(next[0]?.status, "completed");
|
|
assert.equal(next[0]?.updatedAt, "2026-06-18T00:00:03.000Z");
|
|
assert.equal(next[0]?.messages?.length, 2);
|
|
});
|
|
|
|
test("Workbench session tab status is read from server projection", () => {
|
|
const session: WorkbenchSessionRecord = {
|
|
sessionId: "ses_tab_projection",
|
|
threadId: "thr_tab_projection",
|
|
status: "running",
|
|
lastTraceId: "trc_tab_projection",
|
|
messageCount: 2,
|
|
messages: [
|
|
{ id: "msg_tab_user", messageId: "msg_tab_user", role: "user", title: "用户", text: "ping", status: "sent", createdAt: "2026-06-18T00:00:00.000Z", sessionId: "ses_tab_projection", traceId: "trc_tab_projection" },
|
|
{ id: "msg_tab_agent", messageId: "msg_tab_agent", role: "agent", title: "Code Agent", text: "OK", status: "completed", createdAt: "2026-06-18T00:00:01.000Z", sessionId: "ses_tab_projection", traceId: "trc_tab_projection" }
|
|
]
|
|
};
|
|
|
|
const tab = sessionToSessionTab(session, "ses_tab_projection");
|
|
|
|
assert.equal(tab.status, "running");
|
|
assert.equal(tab.running, true);
|
|
});
|
|
|
|
test("Workbench server-state session detail updates session status authority", () => {
|
|
let state = createWorkbenchServerState();
|
|
state = reduceWorkbenchServerState(state, {
|
|
type: "session.status",
|
|
session: { sessionId: "ses_backfill", status: "running" }
|
|
});
|
|
state = reduceWorkbenchServerState(state, {
|
|
type: "session.detail",
|
|
session: {
|
|
sessionId: "ses_backfill",
|
|
threadId: "thr_backfill",
|
|
status: "completed",
|
|
lastTraceId: "trc_backfill",
|
|
updatedAt: "2026-06-18T00:00:03.000Z"
|
|
}
|
|
});
|
|
|
|
const authority = selectSessionStatusAuthority(state).ses_backfill;
|
|
assert.equal(authority?.status, "completed");
|
|
assert.equal(authority?.lastTraceId, "trc_backfill");
|
|
});
|