Extract three AppInner state clusters into hooks: - useMainPanelTaskDetail: the main-panel task-detail snapshot + initial tab; setTask accepts the SetStateAction updater form so the embedded detail can patch the snapshot on task updates. - useBoardScrollRestore: the board scroll snapshot refs, capture, and the double-requestAnimationFrame restore effect keyed on taskView; exposes requestRestore for App to schedule a restore on detail close. - usePoppedOutTasks: the popped-out task-detail windows (dedupe-by-id popOut, close-by-id). App keeps the navigation-history composition (openTaskDetailInMainPanel / closeTaskDetailMainPanel) and now consumes the hooks' primitives. Behavior-preserving; App.test.tsx identical (5 pre-existing failures, none introduced). Verified by typecheck, eslint, and 5 renderHook tests. Completes U6 (App.tsx module-breakup plan).
32 lines
945 B
TypeScript
32 lines
945 B
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { renderHook, act } from "@testing-library/react";
|
|
import { usePoppedOutTasks } from "../usePoppedOutTasks";
|
|
|
|
const task = (id: string) => ({ id, title: id, status: "todo" } as never);
|
|
|
|
describe("usePoppedOutTasks", () => {
|
|
it("popOut adds a task and dedupes by id", () => {
|
|
const { result } = renderHook(() => usePoppedOutTasks());
|
|
|
|
act(() => {
|
|
result.current.popOut(task("1"));
|
|
result.current.popOut(task("1"));
|
|
result.current.popOut(task("2"));
|
|
});
|
|
|
|
expect(result.current.tasks.map((t) => t.id)).toEqual(["1", "2"]);
|
|
});
|
|
|
|
it("close removes only the matching id", () => {
|
|
const { result } = renderHook(() => usePoppedOutTasks());
|
|
|
|
act(() => {
|
|
result.current.popOut(task("1"));
|
|
result.current.popOut(task("2"));
|
|
result.current.close("1");
|
|
});
|
|
|
|
expect(result.current.tasks.map((t) => t.id)).toEqual(["2"]);
|
|
});
|
|
});
|