Created
July 28, 2026 03:43
-
-
Save staylor/a0e5980248be4eabab1a1d8ee9ab925b to your computer and use it in GitHub Desktop.
Lightpanda HTMLCollection CDP close-timeout reproducer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { spawn } from "node:child_process"; | |
| import http from "node:http"; | |
| import { setTimeout as sleep } from "node:timers/promises"; | |
| import playwright from "playwright-core"; | |
| const { chromium } = playwright; | |
| const LIGHTPANDA_BIN = process.env.LIGHTPANDA_BIN ?? "../zig-out/bin/lightpanda"; | |
| const COUNT = Number(process.env.COUNT ?? "20000"); | |
| const CLOSE_TIMEOUT_MS = Number(process.env.CLOSE_TIMEOUT_MS ?? "5100"); | |
| const CDP_PORT = Number(process.env.CDP_PORT ?? "9222"); | |
| const CDP = `http://127.0.0.1:${CDP_PORT}`; | |
| const html = `<!doctype html><body>${'<div class="item"></div>'.repeat(COUNT)}</body>`; | |
| const fixture = http.createServer((_request, response) => { | |
| response.writeHead(200, { "content-type": "text/html" }); | |
| response.end(html); | |
| }); | |
| await new Promise((resolve) => fixture.listen(0, "127.0.0.1", resolve)); | |
| const fixturePort = fixture.address().port; | |
| const lightpanda = spawn( | |
| LIGHTPANDA_BIN, | |
| ["serve", "--host", "127.0.0.1", "--port", String(CDP_PORT), "--log-level", "error"], | |
| { stdio: "inherit" }, | |
| ); | |
| for (let attempt = 0; attempt < 100; attempt++) { | |
| try { | |
| const browser = await chromium.connectOverCDP(CDP, { timeout: 100 }); | |
| await browser.close(); | |
| break; | |
| } catch { | |
| if (attempt === 99) throw new Error("Lightpanda did not start"); | |
| await sleep(100); | |
| } | |
| } | |
| const browser = await chromium.connectOverCDP(CDP); | |
| const context = await browser.newContext(); | |
| const page = await context.newPage(); | |
| await page.goto(`http://127.0.0.1:${fixturePort}`, { waitUntil: "domcontentloaded" }); | |
| await page.evaluate(() => { | |
| setTimeout(() => { | |
| Reflect.apply(() => {}, null, document.getElementsByClassName("item")); | |
| }, 0); | |
| }); | |
| await sleep(10); | |
| const startedAt = performance.now(); | |
| let timer; | |
| const outcome = await Promise.race([ | |
| Promise.all([page.close(), context.close()]).then(() => "closed", (error) => `error:${error.message}`), | |
| new Promise((resolve) => { | |
| timer = setTimeout(() => resolve("timeout"), CLOSE_TIMEOUT_MS); | |
| }), | |
| ]); | |
| clearTimeout(timer); | |
| console.log({ COUNT, outcome, durationMs: Math.round(performance.now() - startedAt) }); | |
| lightpanda.kill("SIGTERM"); | |
| await browser.close().catch(() => {}); | |
| await new Promise((resolve) => fixture.close(resolve)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment