98 lines
5.7 KiB
TypeScript
98 lines
5.7 KiB
TypeScript
import { act, cleanup, renderHook, waitFor } from "@testing-library/react";
|
|
import { afterEach, expect, it, vi } from "vitest";
|
|
import type { RefObject } from "react";
|
|
import type { Map as MapLibreMap } from "maplibre-gl";
|
|
import type { WorkbenchMapController } from "../map/workbench-map-controller";
|
|
import type { WorkbenchSyncState } from "./use-workbench-sync";
|
|
import { useInvestigationPresentation } from "./use-investigation-presentation";
|
|
|
|
const sync = { subscribePresentationEvents: vi.fn(() => () => undefined) } as unknown as WorkbenchSyncState;
|
|
const mapRef: RefObject<MapLibreMap | null> = { current: null };
|
|
const controller = { queryPresentationFeatures: vi.fn() } as unknown as WorkbenchMapController;
|
|
const padding = () => ({ top: 0, right: 0, bottom: 0, left: 0 });
|
|
const onClearLayers = vi.fn();
|
|
const options = { scope: "preview" as const, enabled: false, task: null, projectId: "one", sync, mapRef, mapReady: false, controller, getPadding: padding, onClearLayers };
|
|
|
|
afterEach(() => { cleanup(); vi.useRealTimers(); });
|
|
|
|
it("restores the last successful result when an unfinished display is aborted", async () => {
|
|
const { result } = renderHook(() => useInvestigationPresentation(options));
|
|
await act(() => result.current.runPreview({ blocks: [], records: [{ value: "saved" }], commands: [] }));
|
|
const abort = new AbortController();
|
|
let pending!: Promise<unknown>;
|
|
act(() => {
|
|
pending = result.current.executeCommand({ action: "open_chart", chart_id: "pending", evidence_refs: ["test"], chart: {
|
|
title: "Unfinished", chart_type: "line", x_data: ["10:00"], series: [{ name: "pressure", data: [20] }]
|
|
} }, abort.signal, "preview").catch(() => undefined);
|
|
});
|
|
await waitFor(() => expect(result.current.charts).toHaveLength(1));
|
|
await act(async () => { abort.abort(); await pending; });
|
|
expect(result.current.charts).toEqual([]);
|
|
expect(result.current.records).toEqual([{ value: "saved" }]);
|
|
expect(result.current.history.entries.at(-1)?.status).toBe("cancelled");
|
|
});
|
|
|
|
it("retries a cancelled live event in the same history row", async () => {
|
|
const { result } = renderHook(() => useInvestigationPresentation(options));
|
|
const command = { action: "open_chart" as const, chart_id: "retry", evidence_refs: ["test"], chart: {
|
|
title: "Recoverable", chart_type: "line" as const, x_data: ["10:00"], series: [{ name: "pressure", data: [20] }],
|
|
} };
|
|
const event = { task_id: "50000000-0000-4000-8000-000000000001", run_id: "55000000-0000-4000-8000-000000000001",
|
|
execution_generation: 1, event_seq: 1, command };
|
|
const abort = new AbortController();
|
|
let pending!: Promise<unknown>;
|
|
act(() => { pending = result.current.executeCommand(command, abort.signal, "live", event).catch(() => undefined); });
|
|
await waitFor(() => expect(result.current.charts).toHaveLength(1));
|
|
await act(async () => { abort.abort(); await pending; });
|
|
const id = result.current.history.entries[0].id;
|
|
act(() => result.current.history.onSelect(id));
|
|
await act(() => result.current.executeCommand(command, new AbortController().signal, "live", event));
|
|
expect(result.current.history.entries).toHaveLength(1);
|
|
expect(result.current.history.entries[0]).toMatchObject({ id, status: "completed" });
|
|
act(() => result.current.history.onSelect(null));
|
|
expect(result.current.charts[0].chart.title).toBe("Recoverable");
|
|
});
|
|
|
|
it("does not restore an old partial display after the project changes", async () => {
|
|
const { result, rerender } = renderHook(({ projectId }) => useInvestigationPresentation({ ...options, projectId }), { initialProps: { projectId: "one" } });
|
|
await act(() => result.current.runPreview({ blocks: [], records: [{ value: "old project" }], commands: [] }));
|
|
const abort = new AbortController();
|
|
let pending!: Promise<unknown>;
|
|
act(() => {
|
|
pending = result.current.executeCommand({ action: "open_chart", chart_id: "pending", evidence_refs: ["test"], chart: {
|
|
title: "Unfinished", chart_type: "line", x_data: ["10:00"], series: [{ name: "pressure", data: [20] }]
|
|
} }, abort.signal, "preview").catch(() => undefined);
|
|
});
|
|
await waitFor(() => expect(result.current.charts).toHaveLength(1));
|
|
rerender({ projectId: "two" });
|
|
await act(async () => { abort.abort(); await pending; });
|
|
expect(result.current.charts).toEqual([]);
|
|
expect(result.current.records).toEqual([]);
|
|
expect(result.current.history.entries).toEqual([]);
|
|
});
|
|
|
|
|
|
it("advances saved snapshots on its timer, ignores new results and stops when the user clears overlays", async () => {
|
|
vi.useFakeTimers();
|
|
const { result } = renderHook(() => useInvestigationPresentation(options));
|
|
await act(() => result.current.runPreview({ blocks: [], records: [{ value: 1 }], commands: [] }));
|
|
await act(() => result.current.runPreview({ blocks: [], records: [{ value: 2 }], commands: [] }));
|
|
act(() => result.current.history.playback.onToggle());
|
|
expect(result.current.records).toEqual([{ value: 1 }]);
|
|
expect(result.current.history.playback.playing).toBe(true);
|
|
await act(() => result.current.runPreview({ blocks: [], records: [{ value: 3 }], commands: [] }));
|
|
expect(result.current.records).toEqual([{ value: 1 }]);
|
|
act(() => vi.advanceTimersByTime(1500));
|
|
expect(result.current.records).toEqual([{ value: 2 }]);
|
|
act(() => vi.advanceTimersByTime(1500));
|
|
expect(result.current.history.playback.playing).toBe(false);
|
|
expect(result.current.records).toEqual([{ value: 2 }]);
|
|
act(() => result.current.history.playback.onToggle());
|
|
expect(result.current.history.playback.playing).toBe(true);
|
|
act(() => result.current.clearMapOverlays());
|
|
expect(result.current.history.playback.playing).toBe(false);
|
|
expect(result.current.records).toEqual([{ value: 3 }]);
|
|
act(() => vi.advanceTimersByTime(3000));
|
|
expect(result.current.records).toEqual([{ value: 3 }]);
|
|
});
|