import { expect, test } from "@playwright/test"; import { buildSurfaceDocument } from "../packages/views/plugins/surface-document"; /** * Real Chromium coverage for behavior jsdom does not implement: executing a * sandboxed srcdoc document, reporting errors from a dynamically inserted * script, and firing page lifecycle events when the host rewrites srcdoc. */ test.describe("plugin surface document (real Chromium, sandboxed srcdoc)", () => { test("a host-authored srcdoc reload is not reported as hostile navigation", async ({ page }) => { const first = buildSurfaceDocument({ code: "parent.postMessage({ type: 'plugin-test-ran' }, '*');", grantedScopes: [], theme: {}, }); const themed = buildSurfaceDocument({ code: "parent.postMessage({ type: 'plugin-test-ran' }, '*');", grantedScopes: [], theme: { "--background": "white" }, }); await page.setContent(""); await page.evaluate((srcdoc) => { const state = { ran: 0, navigated: 0 }; (window as unknown as { __surfaceState: typeof state }).__surfaceState = state; window.addEventListener("message", (event) => { const type = (event.data as { type?: string } | null)?.type; if (type === "plugin-test-ran") state.ran++; if (type === "multica:plugin-surface-navigated") state.navigated++; }); const frame = document.createElement("iframe"); frame.id = "surface"; frame.sandbox.add("allow-scripts"); frame.srcdoc = srcdoc; document.body.appendChild(frame); }, first); await expect.poll(() => page.evaluate(() => (window as unknown as { __surfaceState: { ran: number } }).__surfaceState.ran, )).toBe(1); await page.evaluate((srcdoc) => { document.querySelector("#surface")!.srcdoc = srcdoc; }, themed); await expect.poll(() => page.evaluate(() => (window as unknown as { __surfaceState: { ran: number } }).__surfaceState.ran, )).toBe(2); expect(await page.evaluate(() => (window as unknown as { __surfaceState: { navigated: number } }).__surfaceState.navigated, )).toBe(0); }); test("reports a synchronous plugin error even when the host listener mounts late", async ({ page }) => { const documentWithError = buildSurfaceDocument({ code: "throw new Error('plugin failed during bootstrap');", grantedScopes: [], theme: {}, }); await page.setContent(""); await page.evaluate((srcdoc) => { const frame = document.createElement("iframe"); frame.id = "surface"; frame.sandbox.add("allow-scripts"); frame.srcdoc = srcdoc; document.body.appendChild(frame); }, documentWithError); // The guest has already executed and failed before the host starts // listening. A one-shot postMessage is lost in this ordering. await page.waitForTimeout(300); await page.evaluate(() => { (window as unknown as { __surfaceErrors: number }).__surfaceErrors = 0; window.addEventListener("message", (event) => { if ((event.data as { type?: string } | null)?.type !== "multica:plugin-surface-error") return; const frame = document.querySelector("#surface")!; if (event.source !== frame.contentWindow) return; (window as unknown as { __surfaceErrors: number }).__surfaceErrors++; frame.contentWindow!.postMessage({ type: "multica:plugin-surface-error-ack" }, "*"); }); }); await expect.poll(() => page.evaluate(() => (window as unknown as { __surfaceErrors: number }).__surfaceErrors, )).toBe(1); }); });