mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
Record manifest-default features without adding A/B selection. Keep scored builds free of the optional function-name profiling switch. Exercise CLI persistence, interruption, browser failure and legacy page interactions through separate diagnostics. Share readable reports and warn when offline comparisons include failed runs. Validate with 50 focused tests, browser and CLI fault checks, two full corpus workflow runs, and headed rectangle cases. Shadow graphics and sampling calibration remain open. AI-assisted-by: GPT-6
185 lines
6.3 KiB
JavaScript
185 lines
6.3 KiB
JavaScript
// Unscored browser fault checks. Uses prepared assets; manages no services.
|
|
import assert from "node:assert/strict";
|
|
import { chromium } from "playwright";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { bounded } from "../renderer-benchmarks.js";
|
|
import { scenarios } from "../../resources/wasm-playground/scenes/index.js";
|
|
import { collectCases } from "../../resources/wasm-playground/benchmarks/contract.js";
|
|
|
|
const frontend = fileURLToPath(new URL("../../", import.meta.url));
|
|
const server = await chromium.launchServer({
|
|
headless: true,
|
|
args: ["--enable-gpu"],
|
|
});
|
|
const process = server.process();
|
|
const browser = await chromium.connect(server.wsEndpoint());
|
|
const benchmarkCase = collectCases(scenarios, 42, "rects/default/pan")[0];
|
|
const options = {
|
|
viewport: { width: 1920, height: 1080 },
|
|
dpr: 2,
|
|
timeoutMs: 30000,
|
|
moduleUrl: "http://benchmark.invalid/fault-module.js",
|
|
};
|
|
try {
|
|
for (const fault of [
|
|
"unknown-frame",
|
|
"context-loss",
|
|
"timeout",
|
|
"cancel-init",
|
|
"cancel-frame",
|
|
"blocked-wasm",
|
|
"page-crash",
|
|
"report",
|
|
]) {
|
|
const context = await browser.newContext({
|
|
viewport: options.viewport,
|
|
deviceScaleFactor: options.dpr,
|
|
});
|
|
try {
|
|
await context.route("http://benchmark.invalid/**", async (route) => {
|
|
const pathname = new URL(route.request().url()).pathname;
|
|
if (pathname === "/fault-module.js") {
|
|
await route.fulfill({
|
|
contentType: "text/javascript",
|
|
body: `
|
|
import createModule from '/js/render-wasm-benchmark.js';
|
|
export default async function() {
|
|
const module = await createModule();
|
|
if (${JSON.stringify(fault)} === 'cancel-init') await new Promise(resolve => { globalThis.releaseModule = resolve; });
|
|
const render = module._render;
|
|
module._render = (...args) => {
|
|
if (${JSON.stringify(fault)} === 'unknown-frame') return 0;
|
|
if (${JSON.stringify(fault)} === 'blocked-wasm') { while (true) {} }
|
|
if (${JSON.stringify(fault)} === 'context-loss') document.querySelector('canvas').getContext('webgl2').getExtension('WEBGL_lose_context').loseContext();
|
|
return render(...args);
|
|
};
|
|
return module;
|
|
}`,
|
|
});
|
|
return;
|
|
}
|
|
const base = path.join(
|
|
frontend,
|
|
pathname.startsWith("/wasm-playground/")
|
|
? "resources"
|
|
: "resources/public",
|
|
);
|
|
const target = path.resolve(base, `.${pathname}`);
|
|
if (!target.startsWith(`${base}/`)) return route.abort();
|
|
await route.fulfill({ path: target });
|
|
});
|
|
const page = await context.newPage();
|
|
await page.goto(
|
|
"http://benchmark.invalid/wasm-playground/benchmark.html",
|
|
);
|
|
await page.waitForFunction(() => globalThis.rendererBenchmarkReady);
|
|
if (fault === "timeout")
|
|
await page.evaluate(() => {
|
|
globalThis.requestAnimationFrame = () => 1;
|
|
});
|
|
if (fault === "cancel-frame")
|
|
await page.evaluate(() => {
|
|
globalThis.requestAnimationFrame = () => {
|
|
globalThis.framePending = true;
|
|
return 1;
|
|
};
|
|
});
|
|
if (fault === "report") {
|
|
const report = await page.evaluate((c) => {
|
|
const value = {
|
|
scope: "Diagnostic report",
|
|
metadata: {},
|
|
warnings: [],
|
|
cases: [
|
|
{
|
|
...c,
|
|
status: "complete",
|
|
unattempted: 0,
|
|
attempts: [
|
|
{ warmup: false, status: "ok", metrics: { timeToFullMs: 2 } },
|
|
],
|
|
},
|
|
],
|
|
};
|
|
globalThis.rendererBenchmark.showResult(value);
|
|
return {
|
|
result: globalThis.rendererBenchmarkResult,
|
|
text: document.querySelector("pre").textContent,
|
|
};
|
|
}, benchmarkCase);
|
|
assert.equal(
|
|
report.result.cases[0].attempts[0].metrics.timeToFullMs,
|
|
2,
|
|
);
|
|
assert.match(report.text, /median 2\.000/);
|
|
assert.match(report.text, /1 valid, 0 invalid/);
|
|
} else if (fault === "page-crash") {
|
|
const crashed = page.waitForEvent("crash");
|
|
const cdp = await context.newCDPSession(page);
|
|
void cdp.send("Page.crash").catch(() => {});
|
|
await bounded(crashed, 5000);
|
|
await assert.rejects(
|
|
page.evaluate(() => 1),
|
|
/crash|closed/i,
|
|
);
|
|
} else {
|
|
// Attach rejection handling immediately; the watchdog may finish before injection.
|
|
const outcome = bounded(
|
|
page.evaluate(
|
|
([c, o]) => globalThis.rendererBenchmark.runAttempt(c, o),
|
|
[benchmarkCase, options],
|
|
),
|
|
fault === "blocked-wasm" || fault === "timeout" ? 2500 : 10000,
|
|
).then(
|
|
(value) => ({ value }),
|
|
(error) => ({ error }),
|
|
);
|
|
if (fault === "cancel-init" || fault === "cancel-frame") {
|
|
await page.waitForFunction(
|
|
(key) => Boolean(globalThis[key]),
|
|
fault === "cancel-init" ? "releaseModule" : "framePending",
|
|
);
|
|
await page.evaluate(() => {
|
|
globalThis.rendererBenchmark.dispose();
|
|
globalThis.releaseModule?.();
|
|
});
|
|
}
|
|
const result = await outcome;
|
|
if (fault === "blocked-wasm" || fault === "timeout")
|
|
assert.match(result.error?.message ?? "", /watchdog/);
|
|
else {
|
|
assert.equal(result.error, undefined);
|
|
assert.equal(result.value.status, "failed");
|
|
assert.match(
|
|
result.value.error,
|
|
fault === "unknown-frame"
|
|
? /Unexpected frame type/
|
|
: fault === "context-loss"
|
|
? /context lost/
|
|
: /canceled|Stale/,
|
|
);
|
|
}
|
|
}
|
|
console.log(`PASS ${fault} (unscored)`);
|
|
} finally {
|
|
await bounded(context.close(), 5000);
|
|
}
|
|
}
|
|
} finally {
|
|
try {
|
|
await bounded(browser.close(), 5000);
|
|
} catch {
|
|
process.kill("SIGKILL");
|
|
}
|
|
try {
|
|
await bounded(server.close(), 5000);
|
|
} catch {
|
|
process.kill("SIGKILL");
|
|
}
|
|
assert.ok(
|
|
process.exitCode !== null || process.signalCode !== null,
|
|
"browser process must exit",
|
|
);
|
|
}
|