From 49e486ec843893f6ea3b0c6c25b8f92faed37368 Mon Sep 17 00:00:00 2001 From: Alex Nahas Date: Mon, 7 Sep 2026 22:42:39 -0700 Subject: [PATCH] Wait for preview navigation before exercising the example API The built status is written immediately after assigning iframe.srcdoc, while the previous document can still be active. Register for navigation before each build, save, and reload, then wait for the new preview root so API calls use its installed bridge. This also synchronizes the initial automatic build and uses the correct Playwright timeout argument. --- examples/vibe-platform/scripts/e2e.mjs | 41 +++++++++++++++----------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/examples/vibe-platform/scripts/e2e.mjs b/examples/vibe-platform/scripts/e2e.mjs index e518d23..0f71f69 100644 --- a/examples/vibe-platform/scripts/e2e.mjs +++ b/examples/vibe-platform/scripts/e2e.mjs @@ -131,10 +131,23 @@ page.on("console", (message) => { const preview = () => page.frameLocator("#preview"); const file = (path) => page.locator(`#files button[data-path="${path}"]`); -const builtOk = () => - page.waitForFunction(() => /^built in \d+ms$/.test(document.querySelector("#status").textContent), { - timeout: TIMEOUT, - }); +// Register before the action: the build status updates before srcdoc navigation commits. +const builtOk = async (run) => { + const [frame] = await Promise.all([ + page.waitForEvent("framenavigated", { + predicate: (frame) => frame.parentFrame() === page.mainFrame() && frame.url() === "about:srcdoc", + timeout: TIMEOUT, + }), + run(), + ]); + // The bridge is installed before #root is parsed; no CDN resources are needed. + await frame.locator("#root").waitFor({ state: "attached", timeout: TIMEOUT }); + await page.waitForFunction( + () => /^built in \d+ms$/.test(document.querySelector("#status").textContent), + undefined, + { timeout: TIMEOUT }, + ); +}; const previewApi = (method = "GET") => preview() @@ -156,7 +169,7 @@ let exportDirectory; try { // 1 ----------------------------------------------------------------------- await step("page loads and the actor seeded its starter files", async () => { - await page.goto(url, { waitUntil: "domcontentloaded" }); + await builtOk(() => page.goto(url, { waitUntil: "domcontentloaded" })); for (const seeded of [ "/server/agent.ts", "/src/main.tsx", @@ -200,8 +213,7 @@ try { // 3 ----------------------------------------------------------------------- await step("build & run bundles the workspace out of the Durable Object", async () => { - await page.locator("#build").click(); - await builtOk(); + await builtOk(() => page.locator("#build").click()); }); await step("the seeded front-end reaches the user Agent through /api/*", async () => { @@ -248,8 +260,7 @@ try { agentSourceForExport = source.replace("a quiet hello", "a cheerful hello"); if (agentSourceForExport === source) throw new Error("agent edit marker was missing"); await page.locator("#editor").fill(agentSourceForExport); - await page.locator("#save").click(); - await builtOk(); + await builtOk(() => page.locator("#save").click()); await page.waitForFunction( () => document.querySelector("#log").textContent.includes("agent restarted; storage intact"), undefined, @@ -277,8 +288,7 @@ try { } await page.locator("#editor").fill(agentSourceForExport); - await page.locator("#save").click(); - await builtOk(); + await builtOk(() => page.locator("#save").click()); const state = await previewApi(); if (state.visits !== 1) throw new Error(`visit count after recovery is ${String(state.visits)}`); }); @@ -302,8 +312,7 @@ try { ); await page.locator("#editor").fill(agentSourceForExport); - await page.locator("#save").click(); - await builtOk(); + await builtOk(() => page.locator("#save").click()); const state = await previewApi(); if (state.visits !== 1) { throw new Error(`visit count after constructor recovery is ${String(state.visits)}`); @@ -321,8 +330,7 @@ try { ); const source = await editor.inputValue(); await editor.fill(source.replace(TITLE_BEFORE, TITLE_AFTER)); - await page.locator("#save").click(); - await builtOk(); + await builtOk(() => page.locator("#save").click()); }); if (!online) { @@ -338,8 +346,7 @@ try { // 6 ----------------------------------------------------------------------- await step("the edit survives a page reload (OPFS persistence)", async () => { - await page.reload({ waitUntil: "domcontentloaded" }); - await builtOk(); + await builtOk(() => page.reload({ waitUntil: "domcontentloaded" })); await file("/src/App.tsx").waitFor({ timeout: TIMEOUT }); await file("/src/App.tsx").click(); await page.waitForFunction(