citation-evidence/tests/integration/capture-session-persist.dom.test.tsx
tegwick e9f7676a1a
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Implement CE-WP-0010 Annotate & Attributes UX.
Rename Review→Annotate; Capture keeps Evidence and adds Attributes column
(no bottom strip); evidence/attribute filters; card→citation connectors via
shared Overlay bridges; finish workplan T01–T07.
2026-07-30 19:41:42 +02:00

100 lines
No EOL
3.2 KiB
TypeScript

/**
* Capture state survives switching away from and back to a session.
*/
// @vitest-environment happy-dom
import { cleanup, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import manifest from "../../fixtures/pdfs/manifest.json" with { type: "json" };
import { captureStateKey, loadCaptureState } from "@app/forms/capture-persistence";
vi.mock("@citation-evidence/evidence-anchor", async (importOriginal) => {
const original = await importOriginal<typeof import("@citation-evidence/evidence-anchor")>();
const MockPdfSpikeViewer = () => (
<div data-testid="mock-pdf-viewer" />
);
return { ...original, PdfSpikeViewer: MockPdfSpikeViewer };
});
const FIXTURE = manifest.fixtures.find((f) => f.id === "fristsetzung-bezifferung")!;
const SYNTHETIC_CANONICAL = ["Pre.", FIXTURE.known_good_quote, "Post."].join(" ");
const SESSION_NAME = "capture-persist-session";
import { seedSessionWithDoc } from "./helpers/seed-session";
async function loadApp() {
const { App } = await import("@app/App");
return render(<App />);
}
describe("Capture session persistence", () => {
beforeEach(() => {
globalThis.localStorage?.clear();
if (typeof window !== "undefined") {
history.replaceState(null, "", window.location.pathname);
}
seedSessionWithDoc({
sessionName: SESSION_NAME,
documentTitle: FIXTURE.filename,
canonicalText: SYNTHETIC_CANONICAL,
mode: "forms",
});
});
afterEach(() => {
vi.restoreAllMocks();
cleanup();
});
it(
"restores typed field values after leaving and reopening the session",
{ timeout: 20000 },
async () => {
const user = userEvent.setup();
const first = await loadApp();
const summary = screen.getByRole("textbox", { name: /Summary of the matter/ });
await user.type(summary, "Persisted summary text");
await user.click(screen.getByRole("textbox", { name: /Disputed amount/ }));
await waitFor(() => {
const stored = Object.values(globalThis.localStorage ?? {}).join("");
expect(stored).toContain("Persisted summary text");
});
first.unmount();
await loadApp();
const restored = screen.getByRole("textbox", { name: /Summary of the matter/ }) as HTMLTextAreaElement;
await waitFor(() => {
expect(restored.value).toBe("Persisted summary text");
});
},
);
it(
"writes capture state under the per-session storage key",
{ timeout: 15000 },
async () => {
const user = userEvent.setup();
await loadApp();
await user.type(screen.getByRole("textbox", { name: /Disputed amount/ }), "EUR 500");
await waitFor(() => {
const keys = Object.keys(globalThis.localStorage ?? {});
const captureKey = keys.find((k) => k.includes(":capture-state:v1"));
expect(captureKey).toBeTruthy();
const sessionId = captureKey!.split(":")[2];
const state = loadCaptureState(sessionId as never);
expect(state?.fieldValues.amount).toBe("EUR 500");
expect(captureStateKey(sessionId as never)).toBe(captureKey);
});
},
);
});