test(cv): reproduce initially hidden preview pagination readiness

This commit is contained in:
cesnimda
2026-10-10 21:45:25 +02:00
parent bab2730d9b
commit 24c98e160f
2 changed files with 50 additions and 0 deletions
@@ -0,0 +1,11 @@
# P5-15-04-CV-01 — Initially hidden preview lifecycle
## Reproduction checkpoint
The unchanged owned mobile/PDF audit fails again: the hidden measurement iframe has physical A4 width, but the initially hidden visible-page iframe publishes ready with a zero-width content flow. Preview and native PDF both have one page; the demonstrated defect is clipping/incorrect placement, not a page-count mismatch. The native PDF export remains correct.
Two additional native Chromium regressions in `e2e/cv-pagination.spec.ts` reproduce the lifecycle independently of the application server, using retained deterministic renderer HTML: `default-modern` (one page) and `long-en-minimal` (four pages). Both fail before correction because the hidden document has width zero but `cvPreviewReady=true`. They also require physical width and exact page count after revealing, with no second ready event after hide/show, orientation and scale changes.
The injected one-shot script measures `.page` before its display:none ancestor becomes visible, constructs permanent zero-width column flow and announces a settled layout. Fonts/images readiness does not establish usable geometry. Correction must await actual layout without altering PDF, page dimensions, print spacing, fonts or existing fidelity tolerances.
PRES-C06 is FAIL at this reproduction checkpoint; C09/C12 retain independently passing PDF evidence and incomplete acceptance. This record makes no repair/full-suite claim. Screen-reader, real-device and production font/photo qualifications remain incomplete.
+39
View File
@@ -49,3 +49,42 @@ test("[PRES-C06 C09] pagination waits for image layout and publishes one settled
await page.evaluate(() => new Promise<void>(resolve => requestAnimationFrame(() => requestAnimationFrame(() => resolve()))));
expect(await page.evaluate(() => document.documentElement.dataset.readyEvents)).toBe("1");
});
for (const fixture of [{ name: "default-modern", pages: 1 }, { name: "long-en-minimal", pages: 4 }]) {
test(`[PRES-C06 C09] initially hidden ${fixture.name} preview waits for physical layout`, async ({ page }, info) => {
const html = await fs.readFile(path.join(original, fixture.name, "render.html"), "utf8");
await page.setContent('<div id="preview-pane" style="display:none"><iframe title="Fixture CV" style="width:210mm;height:297mm;border:0"></iframe></div>');
await page.locator("iframe").evaluate((frame, documentHtml) => { (frame as HTMLIFrameElement).srcdoc = documentHtml; }, previewDocumentHtml(html, 1122.52));
const documentPage = page.frameLocator("iframe").locator(".page");
await expect(documentPage).toBeAttached();
const before = await documentPage.evaluate(async () => {
await document.fonts.ready;
await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
document.documentElement.dataset.readyEvents = "0";
window.addEventListener("cv-preview-ready", () => { document.documentElement.dataset.readyEvents = String(Number(document.documentElement.dataset.readyEvents) + 1); });
return { width: document.querySelector(".page")!.getBoundingClientRect().width, ready: document.documentElement.dataset.cvPreviewReady };
});
expect(before.width).toBe(0);
expect(before.ready, "a hidden document must not publish a settled zero-width layout").toBeUndefined();
await page.locator("#preview-pane").evaluate(element => { (element as HTMLElement).style.display = "block"; });
await expect.poll(() => documentPage.evaluate(() => document.documentElement.dataset.cvPreviewReady)).toBe("true");
const after = await documentPage.evaluate(() => ({
width: Number(document.documentElement.dataset.cvPreviewWidth),
flowWidth: document.querySelector("[data-cv-preview-flow]")!.getBoundingClientRect().width,
pages: Number(document.documentElement.dataset.cvPreviewPages),
events: document.documentElement.dataset.readyEvents,
durationMs: Number(document.documentElement.dataset.cvPreviewDurationMs),
}));
expect(after.width).toBeCloseTo(210 * 96 / 25.4, 1);
expect(after.flowWidth).toBeCloseTo(210 * 96 / 25.4, 1);
expect(after.pages).toBe(fixture.pages);
expect(after.events).toBe("1");
await page.locator("#preview-pane").evaluate(element => { (element as HTMLElement).style.display = "none"; });
await page.setViewportSize({ width: 844, height: 390 });
await page.locator("#preview-pane").evaluate(element => { (element as HTMLElement).style.display = "block"; element.querySelector("iframe")!.style.transform = "scale(.45)"; });
await documentPage.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))));
expect(await documentPage.evaluate(() => ({ width: Number(document.documentElement.dataset.cvPreviewWidth), pages: Number(document.documentElement.dataset.cvPreviewPages), events: document.documentElement.dataset.readyEvents })))
.toEqual({ width: after.width, pages: fixture.pages, events: "1" });
await info.attach("initially-hidden-preview", { body: JSON.stringify({ fixture: fixture.name, before, after }), contentType: "application/json" });
});
}