1/**
2 * Smoke-check a deployed URL in headless Chrome: load it and wait for the
3 * boot-time solve to finish — either from the cloud cache or computed locally.
4 * Talks to the real cache. Usage: node scripts/check-live.mjs [url]
5 */
6import puppeteer from 'puppeteer-core';
8const url = process.argv[2] ?? 'https://concept-collection.github.io/turing-surface-cache/';
9const browser = await puppeteer.launch({
10 executablePath: process.env.CHROME_PATH ?? '/usr/bin/google-chrome',
11 args: ['--headless=new', '--no-sandbox', '--enable-unsafe-webgpu',
12 '--use-webgpu-adapter=swiftshader', '--enable-unsafe-swiftshader'],
13 // A wait is one CDP call lasting as long as the wait, so the default 180 s
14 // cap on a call is what a slow run trips over first.
15 protocolTimeout: 900_000,
16});
17const page = await browser.newPage();
18await page.setViewport({ width: 1100, height: 900 });
19const problems = [];
20page.on('pageerror', (e) => problems.push(`pageerror: ${e.message}`));
21page.on('requestfailed', (r) => {
22 // The cache lookup 404s by design when the selection is not cached.
23 if (!r.url().startsWith('https://tempory.net/')) {
24 problems.push(`request failed: ${r.url()}`);
25 }
26});
27page.on('console', (m) => {
28 if (m.type() === 'error' && !/GL Driver|favicon|tempory\.net/.test(m.text())) {
29 problems.push(`console error: ${m.text()}`);
30 }
31});
33try {
34 await page.goto(url, { waitUntil: 'load', timeout: 60_000 });
35 // Nothing computes without the button, so any selection is safe to idle on.
36 await page.waitForSelector('#tend');
37 // Terminal statuses only — "checking the cloud cache…" is transient. A
38 // miss settles on empty windows asking for the button; nothing computes
39 // during this check.
40 await page.waitForFunction(
41 () => /from the cloud cache|press Compute solution|failed/.test(
42 document.getElementById('status')?.textContent ?? '') ||
43 (document.getElementById('err')?.textContent?.length ?? 0) > 4,
44 { timeout: 600_000 },
45 );
46 console.log('status:', await page.$eval('#status', (el) => el.textContent));
47 const err = await page.$eval('#err', (el) => el.textContent);
48 if (err) problems.push(`err: ${err}`);
49 const panels = await page.$$eval('.sphere-box canvas', (els) => els.length);
50 console.log('sphere canvases:', panels);
51 if (panels !== 2) problems.push(`expected 2 sphere canvases, got ${panels}`);
52 if (problems.length) {
53 console.log('PROBLEMS:');
54 for (const p of new Set(problems)) console.log(' ' + p);
55 process.exitCode = 1;
56 } else {
57 console.log('LIVE CHECK: PASS');
58 }
59} catch (e) {
60 console.error(`LIVE CHECK FAIL: ${e.message}`);
61 for (const p of new Set(problems)) console.error(' ' + p);
62 process.exitCode = 1;
63} finally {
64 await browser.close();
65}