返回 DeepSeek-Reasonix
archive-management-scope.test.tsx
根目录 / desktop / frontend / src / __tests__ / archive-management-scope.test.tsx
1 import assert from "node:assert/strict";
2 import { managementDom } from "../test-support/managementDom";
3 import { installDesktopHostStub } from "./desktopHostStub";
4
5 const dom = managementDom();
6 const { default: React, act } = await import("react");
7 const { createRoot } = await import("react-dom/client");
8 const { LocaleProvider } = await import("../lib/i18n");
9 const { ArchivedSessionsList } = await import("../components/ArchivedSessionsList");
10 const row = (id: string) => ({ id, ref: { hostId: "local", sessionId: id }, title: id, workspaceId: "global", workspaceTitle: "Global", archivedAt: 0, health: "ready", canPreview: true, canRestore: true, canPurge: true });
11 let rows = [row("alpha"), row("beta")];
12 let generation = 1;
13 const requests: Array<{ action: string; targets: Array<{ ref: { sessionId: string } }> }> = [];
14 const host = installDesktopHostStub({
15 ListTrashEntries: async () => ({ items: rows, generation }),
16 ApplySessionLifecycle: async (request: { action: string; targets: Array<{ ref: { sessionId: string } }> }) => {
17 requests.push(request);
18 rows = rows.filter(item => !request.targets.some(target => target.ref.sessionId === item.id));
19 generation++;
20 return { committed: true, generation, items: request.targets.map(target => ({ target, committed: true, retryable: false })) };
21 },
22 });
23 const root = createRoot(document.getElementById("root")!);
24 const button = (name: string) => Array.from(document.querySelectorAll<HTMLButtonElement>("button")).find(node => node.textContent?.trim() === name)!;
25 const openClear = async () => {
26 await act(async () => (document.querySelector(".archived-sessions__management") as HTMLButtonElement).click());
27 await act(async () => (document.querySelector('[role="menuitem"]:last-child') as HTMLButtonElement).click());
28 };
29 await act(async () => root.render(<LocaleProvider><ArchivedSessionsList active onOpenSession={async () => {}} /></LocaleProvider>));
30
31 // Filtering changes what is visible, never the frozen bulk target set.
32 const search = document.querySelector<HTMLInputElement>(".archived-sessions__search input")!;
33 await act(async () => {
34 Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")!.set!.call(search, "alpha");
35 search.dispatchEvent(new Event("input", { bubbles: true }));
36 });
37 assert.equal(document.querySelectorAll(".archived-sessions__row").length, 1);
38 await openClear();
39 assert.ok(document.querySelector('[role="dialog"]')?.textContent?.includes("all 2 archived conversations"));
40 await act(async () => button("Cancel").click());
41 assert.equal(requests.length, 0);
42 await openClear();
43 await act(async () => button("Delete all 2 conversations").click());
44 assert.deepEqual(requests[0].targets.map(target => target.ref.sessionId), ["alpha", "beta"]);
45
46 // The clear-all route stays a bulk confirmation even with only one archive.
47 rows = [row("solo")];
48 await act(async () => host.emit("project-tree:changed"));
49 await openClear();
50 assert.ok(document.querySelector('[role="dialog"]')?.textContent?.includes("all 1 archived conversations"));
51 assert.equal(button("Delete all 1 conversations")?.textContent, "Delete all 1 conversations");
52 await act(async () => button("Cancel").click());
53
54 await act(async () => root.unmount());
55 host.uninstall();
56 dom.window.close();
57 console.log("PASS filtered bulk scope, cancellation, captured targets and single-entry clear-all wording");
58
58 lines Plain Text