generated from coulomb/repo-seed
Add link: dependency on citation-engine, retarget @shared/@engine aliases, remove in-repo shared/engine copies. ADR-0002 accepted (option B). 172 tests, typecheck, and lint pass.
96 lines
2.8 KiB
TypeScript
96 lines
2.8 KiB
TypeScript
/**
|
|
* CE-WP-0008 — per-session capture state round-trip.
|
|
*/
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
import type { EvidenceLink } from "@shared/evidence-link";
|
|
import type { EvidenceItemId, EvidenceLinkId, SessionId } from "@shared/ids";
|
|
|
|
import {
|
|
CAPTURE_STATE_VERSION,
|
|
captureStateKey,
|
|
defaultCaptureState,
|
|
loadCaptureState,
|
|
persistCapturePatch,
|
|
removeCaptureState,
|
|
saveCaptureState,
|
|
} from "./capture-persistence";
|
|
|
|
function memoryStorage(): Storage {
|
|
const map = new Map<string, string>();
|
|
return {
|
|
get length() {
|
|
return map.size;
|
|
},
|
|
clear: () => map.clear(),
|
|
getItem: (k) => map.get(k) ?? null,
|
|
key: (i) => [...map.keys()][i] ?? null,
|
|
removeItem: (k) => void map.delete(k),
|
|
setItem: (k, v) => void map.set(k, v),
|
|
};
|
|
}
|
|
|
|
const SESSION = "sess_capture" as SessionId;
|
|
|
|
describe("capture-persistence", () => {
|
|
it("uses a per-session storage key", () => {
|
|
expect(captureStateKey(SESSION)).toBe(
|
|
"citation-evidence:session:sess_capture:capture-state:v1",
|
|
);
|
|
});
|
|
|
|
it("round-trips schema, field values, and links", () => {
|
|
const storage = memoryStorage();
|
|
const state = defaultCaptureState();
|
|
const withData = {
|
|
...state,
|
|
fieldValues: { summary: "Tenant owes arrears", deadline: "2026-12-15" },
|
|
evidenceLinks: [
|
|
{
|
|
id: "evlink_1" as EvidenceLinkId,
|
|
evidenceItemId: "evi_1" as EvidenceItemId,
|
|
targetType: "form-field",
|
|
targetId: "summary",
|
|
relation: "supports",
|
|
status: "candidate",
|
|
createdAt: "2026-06-08T00:00:00.000Z",
|
|
updatedAt: "2026-06-08T00:00:00.000Z",
|
|
} satisfies EvidenceLink,
|
|
],
|
|
};
|
|
|
|
saveCaptureState(SESSION, withData, storage);
|
|
const loaded = loadCaptureState(SESSION, storage);
|
|
|
|
expect(loaded?.version).toBe(CAPTURE_STATE_VERSION);
|
|
expect(loaded?.fieldValues).toEqual(withData.fieldValues);
|
|
expect(loaded?.evidenceLinks).toHaveLength(1);
|
|
expect(loaded?.formSchema.id).toBe("demo-form");
|
|
});
|
|
|
|
it("persistCapturePatch merges without dropping other fields", () => {
|
|
const storage = memoryStorage();
|
|
saveCaptureState(
|
|
SESSION,
|
|
{
|
|
...defaultCaptureState(),
|
|
fieldValues: { amount: "1200" },
|
|
evidenceLinks: [],
|
|
},
|
|
storage,
|
|
);
|
|
|
|
persistCapturePatch(SESSION, { fieldValues: { amount: "1500", summary: "Updated" } }, storage);
|
|
|
|
const loaded = loadCaptureState(SESSION, storage);
|
|
expect(loaded?.fieldValues).toEqual({ amount: "1500", summary: "Updated" });
|
|
});
|
|
|
|
it("removeCaptureState clears the key", () => {
|
|
const storage = memoryStorage();
|
|
saveCaptureState(SESSION, defaultCaptureState(), storage);
|
|
removeCaptureState(SESSION, storage);
|
|
expect(loadCaptureState(SESSION, storage)).toBeNull();
|
|
});
|
|
}); |