diff --git a/README.md b/README.md index ec5b321..ed808fe 100644 --- a/README.md +++ b/README.md @@ -150,3 +150,4 @@ The harness tries to reduce these paths (example: lasso timing is end-to-end and ## License MIT © [Matin Mahmood](https://www.linkedin.com/in/matin-mahmood/) (X: [@MatinMnM](https://twitter.com/MatinMnM)) + diff --git a/package-lock.json b/package-lock.json index 65d0de6..caf70b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { - "name": "viz-lab", + "name": "hyper-scatter", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "viz-lab", + "name": "hyper-scatter", "version": "0.1.0", + "license": "MIT", "devDependencies": { "@types/node": "^20.10.0", - "puppeteer": "^24.34.0", + "puppeteer": "^24.35.0", "tsx": "^4.7.0", "typescript": "^5.3.0", "vite": "^5.0.0" @@ -483,9 +484,9 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.11.0.tgz", - "integrity": "sha512-n6oQX6mYkG8TRPuPXmbPidkUbsSRalhmaaVAQxvH1IkQy63cwsH+kOjB3e4cpCDHg0aSvsiX9bQ4s2VB6mGWUQ==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.11.1.tgz", + "integrity": "sha512-YmhAxs7XPuxN0j7LJloHpfD1ylhDuFmmwMvfy/+6nBSrETT2ycL53LrhgPtR+f+GcPSybQVuQ5inWWu5MrWCpA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1016,9 +1017,9 @@ } }, "node_modules/basic-ftp": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", - "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.1.0.tgz", + "integrity": "sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==", "dev": true, "license": "MIT", "engines": { @@ -1757,18 +1758,18 @@ } }, "node_modules/puppeteer": { - "version": "24.34.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.34.0.tgz", - "integrity": "sha512-Sdpl/zsYOsagZ4ICoZJPGZw8d9gZmK5DcxVal11dXi/1/t2eIXHjCf5NfmhDg5XnG9Nye+yo/LqMzIxie2rHTw==", + "version": "24.35.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.35.0.tgz", + "integrity": "sha512-sbjB5JnJ+3nwgSdRM/bqkFXqLxRz/vsz0GRIeTlCk+j+fGpqaF2dId9Qp25rXz9zfhqnN9s0krek1M/C2GDKtA==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "2.11.0", + "@puppeteer/browsers": "2.11.1", "chromium-bidi": "12.0.1", "cosmiconfig": "^9.0.0", "devtools-protocol": "0.0.1534754", - "puppeteer-core": "24.34.0", + "puppeteer-core": "24.35.0", "typed-query-selector": "^2.12.0" }, "bin": { @@ -1779,19 +1780,19 @@ } }, "node_modules/puppeteer-core": { - "version": "24.34.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.34.0.tgz", - "integrity": "sha512-24evawO+mUGW4mvS2a2ivwLdX3gk8zRLZr9HP+7+VT2vBQnm0oh9jJEZmUE3ePJhRkYlZ93i7OMpdcoi2qNCLg==", + "version": "24.35.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.35.0.tgz", + "integrity": "sha512-vt1zc2ME0kHBn7ZDOqLvgvrYD5bqNv5y2ZNXzYnCv8DEtZGw/zKhljlrGuImxptZ4rq+QI9dFGrUIYqG4/IQzA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "2.11.0", + "@puppeteer/browsers": "2.11.1", "chromium-bidi": "12.0.1", "debug": "^4.4.3", "devtools-protocol": "0.0.1534754", "typed-query-selector": "^2.12.0", "webdriver-bidi-protocol": "0.3.10", - "ws": "^8.18.3" + "ws": "^8.19.0" }, "engines": { "node": ">=18" @@ -2602,9 +2603,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index a7d627f..66e4554 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ }, "devDependencies": { "@types/node": "^20.10.0", - "puppeteer": "^24.34.0", + "puppeteer": "^24.35.0", "tsx": "^4.7.0", "typescript": "^5.3.0", "vite": "^5.0.0" diff --git a/src/benchmarks/run-browser-accuracy.ts b/src/benchmarks/run-browser-accuracy.ts index 9f69a66..b28e571 100644 --- a/src/benchmarks/run-browser-accuracy.ts +++ b/src/benchmarks/run-browser-accuracy.ts @@ -136,6 +136,28 @@ async function startDevServer(): Promise<{ proc: ChildProcess; url: string }> { } async function runAccuracy(page: Page): Promise<{ allPassed: boolean; summary: string; reports: any[] }> { + // Wait for VizBenchmark module to be loaded and available on window + // This is necessary because ES modules load asynchronously and networkidle0 + // doesn't guarantee module execution is complete + try { + await page.waitForFunction( + () => typeof (window as any).VizBenchmark !== 'undefined' && + typeof (window as any).VizBenchmark.runAccuracyBenchmarks === 'function', + { timeout: 30000 } // Increased timeout to 30s for slower systems + ); + } catch (err: any) { + // If wait times out, get more diagnostic info + const pageInfo = await page.evaluate(() => { + return { + vizBenchmarkExists: typeof (window as any).VizBenchmark !== 'undefined', + vizBenchmarkType: typeof (window as any).VizBenchmark, + runAccuracyBenchmarksExists: typeof (window as any).VizBenchmark?.runAccuracyBenchmarks !== 'undefined', + windowKeys: Object.keys(window).filter(k => k.includes('Viz') || k.includes('benchmark')), + }; + }); + throw new Error(`Failed to load VizBenchmark module: ${JSON.stringify(pageInfo)}\nOriginal error: ${err?.message || err}`); + } + return page.evaluate(async () => { const canvas = document.getElementById('canvas') as HTMLCanvasElement | null; if (!canvas) throw new Error('Canvas element not found'); @@ -185,6 +207,20 @@ async function main() { }); const page = await browser.newPage(); + + // Capture console errors for debugging + page.on('console', msg => { + const type = msg.type(); + if (type === 'error' || type === 'warn') { + console.log(`[Browser ${type}]:`, msg.text()); + } + }); + + // Capture page errors + page.on('pageerror', (error) => { + console.error('[Page Error]:', error); + }); + // tsx/esbuild may wrap serialized functions passed to page.evaluate() with // __name(...) calls. Define a no-op __name helper in the page context. try { diff --git a/src/benchmarks/run-browser-bench.ts b/src/benchmarks/run-browser-bench.ts index cbee51c..3da5656 100644 --- a/src/benchmarks/run-browser-bench.ts +++ b/src/benchmarks/run-browser-bench.ts @@ -175,6 +175,28 @@ async function runBenchmarks( page: Page, config: BenchConfig ): Promise { + // Wait for VizBenchmark module to be loaded and available on window + // This is necessary because ES modules load asynchronously and networkidle0 + // doesn't guarantee module execution is complete + try { + await page.waitForFunction( + () => typeof (window as any).VizBenchmark !== 'undefined' && + typeof (window as any).VizBenchmark.runBenchmarks === 'function', + { timeout: 30000 } // Increased timeout to 30s for slower systems + ); + } catch (err: any) { + // If wait times out, get more diagnostic info + const pageInfo = await page.evaluate(() => { + return { + vizBenchmarkExists: typeof (window as any).VizBenchmark !== 'undefined', + vizBenchmarkType: typeof (window as any).VizBenchmark, + runBenchmarksExists: typeof (window as any).VizBenchmark?.runBenchmarks !== 'undefined', + windowKeys: Object.keys(window).filter(k => k.includes('Viz') || k.includes('benchmark')), + }; + }); + throw new Error(`Failed to load VizBenchmark module: ${JSON.stringify(pageInfo)}\nOriginal error: ${err?.message || err}`); + } + // Optionally override canvas CSS size before starting. // Width defaults to responsive container width; height defaults to 400px in benchmark.html. await page.evaluate((canvasCfg: { width?: number; height?: number }) => { @@ -449,6 +471,19 @@ async function main() { const page = await browser.newPage(); + // Capture console errors for debugging + page.on('console', msg => { + const type = msg.type(); + if (type === 'error' || type === 'warn') { + console.log(`[Browser ${type}]:`, msg.text()); + } + }); + + // Capture page errors + page.on('pageerror', (error) => { + console.error('[Page Error]:', error); + }); + // Some bundlers/transpilers (notably esbuild) may emit a `__name(fn, name)` // helper when serializing functions. Puppeteer executes `page.evaluate` // callbacks in the *page* context, where that helper is not defined.