返回 DeepSeek-Reasonix
completion-summary-presentation.test.ts
根目录 / desktop / frontend / src / __tests__ / completion-summary-presentation.test.ts
1 import assert from "node:assert/strict";
2 import { completionSummaryPresentation, normalizeCompletionSummary } from "../lib/completionSummary";
3 import { mergeTurnResult, normalizeTurnChanges, turnChangeText, turnCheckState } from "../lib/turnResult";
4 import { historicalResultNotice, withTurnResult, withRunningChecks } from "../lib/completionResultState";
5 import { ChatSource } from "../lib/chatViewSource";
6 import { initialState, reducer, type State, type Item } from "../lib/useController";
7 import { t } from "../lib/i18n";
8 import type { TurnChanges } from "../lib/types";
9
10 const diff: TurnChanges = { id: "0:1", turn: 0, coverage: "complete", files: [{ path: "a.ts", kind: "modify", added: 2, removed: 1 }], added: 2, removed: 1, reasons: [] };
11 const legacy = { ...mergeTurnResult(), mutations: 17, changed_files: 9 };
12 assert.equal(turnChangeText(legacy, t), "Change statistics unavailable");
13 assert.equal(turnCheckState(legacy).status, "unknown");
14 const receipt = { verdict: "partial", diff, verifications: [] };
15 const result = normalizeCompletionSummary(mergeTurnResult(legacy, receipt, "turn-0", 0));
16 assert.equal(result.checkpointTurn, 0);
17 assert.match(turnChangeText(result, t), /1.*file.*\+2 −1/);
18 assert.equal(turnCheckState(result).status, "none");
19 assert.equal(completionSummaryPresentation(result, "standard", t)?.title, "Turn result");
20 assert.match(turnChangeText(mergeTurnResult(undefined, { ...receipt, diff: { ...diff, coverage: "partial" } }), t), /partial/i);
21 assert.equal(normalizeTurnChanges({ ...diff, added: -1 })?.coverage, "unknown");
22 for (const [check, expected] of [
23 [{ command: "test", passed: true, exitCode: 1 }, "failed"],
24 [{ command: "test", passed: true, stale: true }, "stale"],
25 [{ command: "test", passed: false, interrupted: true }, "interrupted"],
26 [{ command: "test", passed: true, exitCode: 0 }, "passed"],
27 ] as const) assert.equal(turnCheckState(mergeTurnResult(undefined, { ...receipt, verifications: [check] })).status, expected);
28 const user: Item = { kind: "user", id: "u0", text: "change" };
29 let state = withTurnResult({ ...initialState, items: [user], seq: 10 } as State, result);
30 const stableId = state.items[1].id;
31 state = withTurnResult(state, result);
32 assert.equal(state.items.length, 2);
33 assert.equal(state.items[1].id, stableId);
34 state = withTurnResult({ ...state, items: [...state.items, { ...user, id: "u1" }] }, { ...result, turnId: "turn-1" });
35 assert.equal(state.items.length, 4);
36 assert.equal(state.items[1].id, stableId);
37 const tool = (id: string): Item => ({ kind: "tool", id, name: "exec_command", args: '{"command":"go test ./..."}', readOnly: false, status: "running", verifying: true });
38 state = withRunningChecks({ ...state, items: [...state.items, tool("c1"), tool("c2")] });
39 assert.equal(state.completionSummary?.liveChecks?.length, 2);
40 state = withRunningChecks({ ...state, items: state.items.map(i => i.kind === "tool" && i.id === "c1" ? { ...i, status: "done" } : i) });
41 assert.equal(state.completionSummary?.checking, true, "one completed parallel check does not stop the other");
42 const history = historicalResultNotice({ role: "notice", content: "", completionReceipt: receipt, checkpointTurn: 0, turnId: "turn-0" }, "history");
43 assert.equal(history?.completionSummary?.receipt?.diff?.id, diff.id);
44 assert.equal(history?.completionSummary?.checkpointTurn, 0);
45 const answer: Item = { kind: "assistant", id: "a0", text: "done", reasoning: "", streaming: false };
46 const source = new ChatSource("completion-results");
47 source.update({ items: [user, history!, answer], running: false, hydrating: false, hasOlder: false, loadingOlder: false });
48 assert.equal(source.getNodeSnapshot("history")?.kind, "notice", "historical results survive as ordinary records");
49 source.dispose();
50 for (const phase of ["checking", "verifying", "working", "reviewing"]) {
51 const plain: State = { ...initialState, items: [user], seq: 1 };
52 const next = reducer(plain, { type: "event", e: { kind: "turn_phase", phase } });
53 assert.equal(next.turnPhase, phase);
54 assert.equal(next.completionSummary?.checking ?? false, false, `${phase} is not verification evidence`);
55 assert.deepEqual(next.items, plain.items, `${phase} must not insert a result card`);
56
57 const checking = withRunningChecks({ ...plain, items: [user, tool("check")] });
58 const resultId = checking.items.find(i => i.kind === "notice")!.id;
59 const active = reducer(checking, { type: "event", e: { kind: "turn_phase", phase } });
60 assert.equal(active.completionSummary?.checking, true, `${phase} preserves real running checks`);
61 assert.equal(active.items.find(i => i.kind === "notice")!.id, resultId);
62 }
63 let live = reducer({ ...initialState, items: [user] }, { type: "event", e: { kind: "tool_dispatch", tool: { id: "live", name: "bash", readOnly: false, args: '{"command":"go test ./..."}' } } });
64 live = reducer(live, { type: "event", e: { kind: "tool_progress", tool: { id: "live", name: "bash", readOnly: false, verifying: true, output: "running" } } });
65 assert.equal(live.completionSummary?.checking, true);
66 live = reducer(live, { type: "event", e: { kind: "turn_phase", phase: "working" } });
67 assert.equal(live.completionSummary?.checking, true);
68 live = reducer(live, { type: "event", e: { kind: "tool_result", tool: { id: "live", name: "bash", readOnly: false, output: "PASS" } } });
69 assert.equal(live.completionSummary?.checking, false);
70 console.log("turn result truth, stable identity, concurrent checks, phases and history passed");
71
71 lines TYPESCRIPT