返回 DeepSeek-Reasonix
goal-lifecycle-actions.test.tsx
根目录 / desktop / frontend / src / __tests__ / goal-lifecycle-actions.test.tsx
1 // Run: tsx src/__tests__/goal-lifecycle-actions.test.tsx
2
3 import { JSDOM } from "jsdom";
4
5 const dom = new JSDOM("<!doctype html><html><body><div id=\"root\"></div></body></html>", { url: "http://localhost/" });
6 (globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
7 globalThis.window = dom.window as unknown as Window & typeof globalThis;
8 globalThis.document = dom.window.document;
9 globalThis.HTMLElement = dom.window.HTMLElement;
10 globalThis.Event = dom.window.Event;
11
12 const React = await import("react");
13 const { act } = React;
14 const { createRoot } = await import("react-dom/client");
15 const { GoalLifecycleActions } = await import("../components/GoalLifecycleActions");
16 const { LocaleProvider } = await import("../lib/i18n");
17
18 let edit: { objective: string; maxGoalRounds: number | null } | undefined;
19 let paused = 0;
20 window.prompt = () => { throw new Error("prompt() is not supported."); };
21 window.alert = () => { throw new Error("alert() is not supported."); };
22
23 await act(async () => {
24 createRoot(document.getElementById("root")!).render(
25 <LocaleProvider>
26 <GoalLifecycleActions
27 goalView={{
28 id: "goal-1", revision: 3, objective: "finish the migration", phase: "active",
29 maxGoalRounds: null, roundsStarted: 2, createdAt: "2026-01-01T00:00:00Z",
30 updatedAt: "2026-01-01T00:00:00Z", activation: "armed",
31 }}
32 goalStatus="running"
33 running
34 onEditGoal={(objective, maxGoalRounds) => { edit = { objective, maxGoalRounds }; }}
35 onPauseGoal={() => { paused += 1; }}
36 onResumeGoal={() => {}}
37 onStopGoal={() => {}}
38 />
39 </LocaleProvider>,
40 );
41 });
42
43 const buttons = Array.from(document.querySelectorAll<HTMLButtonElement>("button"));
44 const editButton = buttons.find((button) => button.textContent === "Edit goal");
45 const pauseButton = buttons.find((button) => button.textContent === "Pause goal");
46 if (!editButton || !pauseButton) throw new Error("active goal lifecycle actions did not render");
47 if (pauseButton.disabled) throw new Error("running automatic Goal round is not pausable");
48
49 const setValue = async (el: HTMLInputElement | HTMLTextAreaElement, value: string) => {
50 const proto = el instanceof dom.window.HTMLTextAreaElement ? dom.window.HTMLTextAreaElement.prototype : dom.window.HTMLInputElement.prototype;
51 await act(async () => {
52 Object.getOwnPropertyDescriptor(proto, "value")!.set!.call(el, value);
53 el.dispatchEvent(new dom.window.Event("input", { bubbles: true }));
54 });
55 };
56
57 await act(async () => { editButton.click(); });
58 const objectiveInput = document.querySelector<HTMLTextAreaElement>("[data-goal-edit-objective]");
59 const roundsInput = document.querySelector<HTMLInputElement>("[data-goal-edit-rounds]");
60 if (!objectiveInput || !roundsInput) throw new Error("edit goal did not open an in-app form");
61 if (objectiveInput.value !== "finish the migration") throw new Error("objective not prefilled");
62 await setValue(roundsInput, "0");
63 const form = document.querySelector<HTMLFormElement>("form[data-goal-edit-form]")!;
64 await act(async () => { form.dispatchEvent(new dom.window.Event("submit", { bubbles: true, cancelable: true })); });
65 if (edit) throw new Error("invalid rounds must not submit");
66 if (!document.querySelector("[data-goal-edit-error]")) throw new Error("invalid rounds error not shown");
67 await setValue(objectiveInput, "finish the migration safely");
68 await setValue(roundsInput, "12");
69 await act(async () => { form.dispatchEvent(new dom.window.Event("submit", { bubbles: true, cancelable: true })); });
70 if (document.querySelector("form[data-goal-edit-form]")) throw new Error("form should close after save");
71 if (edit?.objective !== "finish the migration safely" || edit.maxGoalRounds !== 12) {
72 throw new Error(`edit action returned ${JSON.stringify(edit)}`);
73 }
74 await act(async () => { pauseButton.click(); });
75 if (paused !== 1) throw new Error("pause action was not delivered");
76 console.log("goal lifecycle actions: PASS");
77
77 lines Plain Text