/** * Integration round-trip: ingest → createSelectors → resolveSelectors. * * This test crosses the source ↔ anchor boundary, which the * `boundaries/element-types` lint rule (correctly) forbids inside `src/`. * It lives under `tests/integration/` so it can verify the end-to-end * MVP contract without weakening the production-code boundary. * * CE-WP-0002-T04 contract: * For each fixture+known-quote pair, create selectors then immediately * resolve them; resolution must succeed with confidence ≥ 0.9. */ import { readFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { createRequire } from "node:module"; import { fileURLToPath } from "node:url"; import { beforeAll, describe, expect, it } from "vitest"; import { ingestPdf } from "@source/pdf/ingest"; import { createSelectors, resolveSelectors } from "@anchor/selectors"; import type { PdfSelectionCapture } from "@anchor/types"; import manifest from "../../fixtures/pdfs/manifest.json" with { type: "json" }; const __dirname = dirname(fileURLToPath(import.meta.url)); const FIXTURE_DIR = resolve(__dirname, "../../fixtures/pdfs"); interface Fixture { id: string; filename: string; known_good_quote: string; known_good_quote_page: number; } const FIXTURES: readonly Fixture[] = manifest.fixtures; beforeAll(async () => { const pdfjs = await import("pdfjs-dist"); const require = createRequire(import.meta.url); pdfjs.GlobalWorkerOptions.workerSrc = require.resolve( "pdfjs-dist/legacy/build/pdf.worker.mjs", ); }); describe("create + resolve round-trip — fixture corpus", { timeout: 30_000 }, () => { for (const fixture of FIXTURES) { it(`${fixture.id}: known-good quote round-trips with confidence ≥ 0.9`, async () => { const bytes = new Uint8Array(readFileSync(resolve(FIXTURE_DIR, fixture.filename))); const { representation } = await ingestPdf(bytes, { filename: fixture.filename }); const capture: PdfSelectionCapture = { kind: "pdf", text: fixture.known_good_quote, page: fixture.known_good_quote_page, rects: [{ x: 0.1, y: 0.2, width: 0.5, height: 0.04 }], }; const selectors = createSelectors(capture, representation); const resolution = resolveSelectors(selectors, representation); expect(resolution.status).toBe("resolved"); expect(resolution.confidence).toBeGreaterThanOrEqual(0.9); const span = resolution.candidates[0]?.textPosition; expect(span).toBeDefined(); const text = representation.canonicalText ?? ""; expect(text.slice(span!.start, span!.end)).toBe(fixture.known_good_quote); expect(resolution.candidates[0]?.page).toBe(fixture.known_good_quote_page); }); } });