返回 DeepSeek-Reasonix
presented-files-ui.test.tsx
根目录 / desktop / frontend / src / __tests__ / presented-files-ui.test.tsx
1 import assert from "node:assert/strict";
2 import React from "react";
3 import { renderToStaticMarkup } from "react-dom/server";
4 import { LocaleProvider } from "../lib/i18n";
5 import { ModifiedFiles, PresentedFiles } from "../components/PresentedFiles";
6 import type { PresentedFileView } from "../lib/chatViewSource";
7 import type { WireCompletionSummary } from "../lib/types";
8
9 const files: PresentedFileView[] = Array.from({ length: 5 }, (_, index) => ({
10 path: `output/file-${index + 1}.html`,
11 description: `Preview ${index + 1}`,
12 toolCallId: `present-${index + 1}`,
13 }));
14
15 const markup = renderToStaticMarkup(
16 <LocaleProvider><PresentedFiles files={files} tabId="tab-1" /></LocaleProvider>,
17 );
18
19 assert.equal((markup.match(/class="presented-file"/g) ?? []).length, 4);
20 assert.match(markup, /file-1\.html/);
21 assert.doesNotMatch(markup, /file-5\.html/);
22 assert.match(markup, /5/);
23 assert.equal((markup.match(/presented-file__split/g) ?? []).length, 4, "every presented card uses one split open control");
24
25 const changes = renderToStaticMarkup(<LocaleProvider><ModifiedFiles tabId="tab-1" files={[
26 { path: "src/app.ts", toolCallId: "write-1", operation: "modified" },
27 ]} summary={{
28 preset: "balanced", verdict: "complete", mutations: 2, changed_files: 2, checks_passed: 0, checks_failed: 0,
29 checks_suppressed: 0, review: "passed", constraint_degraded: false,
30 receipt: { verdict: "complete", diff: { id: "result", turn: 1, coverage: "complete", added: 7, removed: 3, reasons: [], files: [
31 { path: "src/app.ts", kind: "modify", added: 5, removed: 2 },
32 { path: "README.md", kind: "modify", added: 2, removed: 1 },
33 ] } },
34 }} /></LocaleProvider>);
35 assert.match(changes, /Edited 2 files/);
36 assert.match(changes, /\+7/);
37 assert.match(changes, /−3/);
38 assert.match(changes, /src\/app\.ts/);
39 assert.match(changes, /README\.md/);
40 console.log("presented files UI: changed summary and four-card split controls passed");
41
42 const mutationFiles = [{ path: "src/app.ts", toolCallId: "edit-1", operation: "modified" as const }];
43 const renderChanges = (diff?: NonNullable<WireCompletionSummary["receipt"]>["diff"]) => renderToStaticMarkup(
44 <LocaleProvider><ModifiedFiles files={mutationFiles} summary={diff ? {
45 preset: "balanced", verdict: "complete", mutations: 2, changed_files: diff.files.length,
46 checks_passed: 0, checks_failed: 0, checks_suppressed: 0, review: "passed", constraint_degraded: false,
47 receipt: { verdict: "complete", diff },
48 } : undefined} /></LocaleProvider>,
49 );
50 assert.equal(renderChanges({ id: "reverted", turn: 1, coverage: "complete", added: 0, removed: 0, reasons: [], files: [] }), "",
51 "a complete empty receipt must not resurrect reverted mutations");
52 const partial = renderChanges({ id: "partial", turn: 1, coverage: "partial", added: 4, removed: 2, reasons: ["limited"], files: [
53 { path: "src/app.ts", kind: "modify", added: 4, removed: 2 },
54 ] });
55 assert.match(partial, /Partial statistics/);
56 assert.match(partial, /\+4/);
57 const partialEmpty = renderChanges({ id: "partial-empty", turn: 1, coverage: "partial", added: 0, removed: 0, reasons: [], files: [] });
58 assert.match(partialEmpty, /src\/app.ts/, "an incomplete empty inventory must preserve known mutation paths");
59 assert.match(partialEmpty, /Partial statistics/);
60 assert.doesNotMatch(partialEmpty, /\+0|−0/);
61 const unknown = renderChanges();
62 assert.match(unknown, /src\/app.ts/);
63 assert.doesNotMatch(unknown, /\+0|−0/, "mutation calls alone cannot establish net line counts");
64 const uncounted = renderChanges({ id: "uncounted", turn: 1, coverage: "partial", added: 0, removed: 0, reasons: [], files: [
65 { path: "src/app.ts", kind: "modify", uncounted: true },
66 ] });
67 assert.doesNotMatch(uncounted, /\+0|−0/);
68 const modes = renderChanges({ id: "mode", turn: 1, coverage: "complete", added: 0, removed: 0, reasons: [], files: [
69 { path: "src/app.ts", kind: "modify", modeOnly: true },
70 ] });
71 assert.match(modes, /Permissions only/);
72 console.log("presented files UI: reverted, partial, unknown and permissions-only receipts passed");
73
73 lines Plain Text