Skip to content

Commit 576a80a

Browse files
committed
fix(browser): simplify navigation wait
1 parent 9d674e0 commit 576a80a

4 files changed

Lines changed: 25 additions & 38 deletions

File tree

packages/bcode-browser/skills/browser-execute/SKILL.md

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,10 @@ Common moves:
115115
```js
116116
// Navigate.
117117
await session.Page.enable()
118-
const loaded = session.waitFor("Page.loadEventFired", { timeoutMs: 15_000 })
119-
// Keep the rejection observed if navigation itself fails before `await loaded`.
120-
void loaded.catch(() => {})
121-
const navigation = await session.Page.navigate({ url: "https://example.com" })
122-
if (navigation.errorText) throw new Error(`Navigation failed: ${navigation.errorText}`)
123-
// Same-document navigations have no loaderId and do not fire a new load event.
124-
if (navigation.loaderId) await loaded
118+
await Promise.all([
119+
session.waitFor("Page.loadEventFired", { timeoutMs: 15_000 }),
120+
session.Page.navigate({ url: "https://example.com" }),
121+
])
125122
126123
// Evaluate JS in the page.
127124
const r = await session.Runtime.evaluate({
@@ -158,11 +155,10 @@ export async function scrapeTitles(session: any, urls: string[]) {
158155
const titles: string[] = []
159156
await session.Page.enable()
160157
for (const url of urls) {
161-
const loaded = session.waitFor("Page.loadEventFired", { timeoutMs: 15_000 })
162-
void loaded.catch(() => {})
163-
const navigation = await session.Page.navigate({ url })
164-
if (navigation.errorText) throw new Error(`Navigation failed: ${navigation.errorText}`)
165-
if (navigation.loaderId) await loaded
158+
await Promise.all([
159+
session.waitFor("Page.loadEventFired", { timeoutMs: 15_000 }),
160+
session.Page.navigate({ url }),
161+
])
166162
const r = await session.Runtime.evaluate({ expression: "document.title", returnByValue: true })
167163
titles.push(r.result.value)
168164
}

packages/bcode-browser/test/browser-execute.test.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,10 @@ test.skipIf(!enabled)("workspace import inside a snippet", async () => {
8787
await session.use(page.targetId)
8888
}
8989
await session.Page.enable()
90-
const loaded = session.waitFor("Page.loadEventFired", { timeoutMs: 5000 })
91-
await session.Page.navigate({ url: "data:text/html,<title>bcode-be</title>" })
92-
await loaded
90+
await Promise.all([
91+
session.waitFor("Page.loadEventFired", { timeoutMs: 5000 }),
92+
session.Page.navigate({ url: "data:text/html,<title>bcode-be</title>" }),
93+
])
9394
const r = await session.Runtime.evaluate({ expression: "document.title", returnByValue: true })
9495
return r.result.value
9596
}`,
@@ -126,9 +127,10 @@ test.skipIf(!enabled)("Page.captureScreenshot is collected into result.screensho
126127
{
127128
description: "Capture two screenshots",
128129
code: `await session.Page.enable();
129-
const loaded = session.waitFor("Page.loadEventFired", { timeoutMs: 5000 });
130-
await session.Page.navigate({ url: "data:text/html,<title>shot</title><body>hi" });
131-
await loaded;
130+
await Promise.all([
131+
session.waitFor("Page.loadEventFired", { timeoutMs: 5000 }),
132+
session.Page.navigate({ url: "data:text/html,<title>shot</title><body>hi" }),
133+
]);
132134
const a = await session.Page.captureScreenshot({ format: "png" });
133135
const b = await session.Page.captureScreenshot({ format: "jpeg", quality: 50 });
134136
return { aLen: a.data.length, bLen: b.data.length };`,

packages/bcode-browser/test/cdp-session.test.ts

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@ const server = Bun.serve({
1717
const method = Reflect.get(message, "method")
1818
const id = Reflect.get(message, "id")
1919
if (method !== "Page.navigate" || typeof id !== "number") return
20-
const params = Reflect.get(message, "params")
21-
const url = typeof params === "object" && params !== null ? Reflect.get(params, "url") : undefined
22-
if (url === "https://navigation-fails.example") {
23-
ws.send(JSON.stringify({ id, result: { frameId: "frame", errorText: "net::ERR_FAILED" } }))
24-
return
25-
}
2620
ws.send(JSON.stringify({ method: "Page.loadEventFired", params: { timestamp: 1 } }))
2721
ws.send(JSON.stringify({ id, result: { frameId: "frame" } }))
2822
},
@@ -83,9 +77,11 @@ test("waitFor retains the positional signature", async () => {
8377
})
8478

8579
test("a waiter registered before navigation catches an event emitted before the navigation response", async () => {
86-
const loaded = session.waitFor<{ timestamp: number }>("Page.loadEventFired", { timeoutMs: 1_000 })
87-
await session.domains.Page.navigate({ url: "https://example.com" })
88-
expect(await loaded).toEqual({ timestamp: 1 })
80+
const [loaded] = await Promise.all([
81+
session.waitFor<{ timestamp: number }>("Page.loadEventFired", { timeoutMs: 1_000 }),
82+
session.domains.Page.navigate({ url: "https://example.com" }),
83+
])
84+
expect(loaded).toEqual({ timestamp: 1 })
8985
})
9086

9187
test("waitFor ignores matching events from another attached session", async () => {
@@ -100,14 +96,6 @@ test("waitFor ignores matching events from another attached session", async () =
10096
}
10197
})
10298

103-
test("navigation failure does not leave an unhandled waiter rejection", async () => {
104-
const loaded = session.waitFor("Page.loadEventFired", { timeoutMs: 20 })
105-
void loaded.catch(() => {})
106-
const navigation = await session.domains.Page.navigate({ url: "https://navigation-fails.example" })
107-
expect(navigation.errorText).toBe("net::ERR_FAILED")
108-
await Bun.sleep(30)
109-
})
110-
11199
test("waitFor rejects invalid runtime arguments immediately", () => {
112100
expect(() =>
113101
// @ts-expect-error Runtime callers can still pass invalid JavaScript.

packages/bcode-browser/test/cdp-smoke.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ test.skipIf(!enabled)("Session connects, navigates, reads title", async () => {
3232
}
3333

3434
await session.domains.Page.enable()
35-
const loaded = session.waitFor("Page.loadEventFired", { timeoutMs: 5000 })
36-
await session.domains.Page.navigate({ url: "data:text/html,<title>bcode-smoke</title>" })
37-
await loaded
35+
await Promise.all([
36+
session.waitFor("Page.loadEventFired", { timeoutMs: 5000 }),
37+
session.domains.Page.navigate({ url: "data:text/html,<title>bcode-smoke</title>" }),
38+
])
3839

3940
const r = (await session.domains.Runtime.evaluate({
4041
expression: "document.title",

0 commit comments

Comments
 (0)