81 lines
5.0 KiB
JavaScript
81 lines
5.0 KiB
JavaScript
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
|
|
import { WP4_07_PERFORMANCE_BUDGETS } from "../tests/visual-performance/wp4-07-fixture.mjs";
|
|
|
|
const evidenceIndex = process.argv.indexOf("--evidence");
|
|
const phaseIndex = process.argv.indexOf("--phase");
|
|
const evidenceDirectory = resolve(evidenceIndex >= 0 ? process.argv[evidenceIndex + 1] : "");
|
|
const phase = phaseIndex >= 0 ? process.argv[phaseIndex + 1] : "green";
|
|
if (evidenceIndex < 0 || !process.argv[evidenceIndex + 1] || !["green", "red"].includes(phase)) throw new Error("Usage: --evidence <directory> [--phase red|green]");
|
|
|
|
function read(browser, filename) {
|
|
const path = resolve(evidenceDirectory, browser, filename);
|
|
if (!existsSync(path)) throw new Error(`missing ${browser}/${filename}`);
|
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
}
|
|
|
|
const browserResults = {};
|
|
let greenInputsEligible = true;
|
|
for (const browser of ["chrome", "edge"]) {
|
|
const raw = read(browser, "performance-raw.json");
|
|
const memory = read(browser, "memory.json");
|
|
const dom = read(browser, "dom-count.json");
|
|
const environment = read(browser, "environment.json");
|
|
greenInputsEligible = greenInputsEligible && raw.eligible_for_green === true && raw.harness_mode === "real";
|
|
if (raw.interaction.length !== 5 || raw.autosave_serialization.length !== 5 || raw.export_1080x1920.length !== 5 || raw.editor_reopen.samples_ms.length !== 5) {
|
|
throw new Error(`${browser} did not retain exactly five measured samples per budget`);
|
|
}
|
|
if (raw.interaction.some((run) => run.duration_ms < WP4_07_PERFORMANCE_BUDGETS.interaction_duration_ms)) {
|
|
throw new Error(`${browser} shortened a ten-second interaction measurement`);
|
|
}
|
|
const checks = {
|
|
autosave_serialization: raw.autosave_serialization.every((run) => run.p95_ms <= WP4_07_PERFORMANCE_BUDGETS.autosave_serialization_p95_ms_max),
|
|
canvas_frame: raw.interaction.every((run) => run.frame_p95_ms <= WP4_07_PERFORMANCE_BUDGETS.canvas_frame_p95_ms_max),
|
|
continuous_unresponsive: raw.interaction.every((run) => run.frame_max_ms < WP4_07_PERFORMANCE_BUDGETS.continuous_unresponsive_ms_max_exclusive),
|
|
dom_bounded: dom.bounded_by_viewport_and_two_screens === true && dom.top_count < dom.catalog_count && dom.bottom_count < dom.catalog_count,
|
|
editor_reopen: raw.editor_reopen.max_ms <= WP4_07_PERFORMANCE_BUDGETS.editor_reopen_ms_max,
|
|
export_duration: raw.export_1080x1920.every((run) => run.duration_ms <= WP4_07_PERFORMANCE_BUDGETS.export_1080x1920_ms_max),
|
|
export_failure_isolated: raw.export_failure.observed_error === "export_asset_unavailable"
|
|
&& JSON.stringify(raw.export_failure.saves_before) === JSON.stringify(raw.export_failure.saves_after),
|
|
export_memory: memory.export_peak_additional_bytes.every((value) => value <= WP4_07_PERFORMANCE_BUDGETS.export_peak_additional_bytes_max),
|
|
long_task: raw.interaction.every((run) => run.long_task_max_ms <= WP4_07_PERFORMANCE_BUDGETS.long_task_ms_max),
|
|
pointer_to_frame: raw.interaction.every((run) => run.pointer_to_frame_p95_ms <= WP4_07_PERFORMANCE_BUDGETS.pointer_to_frame_p95_ms_max),
|
|
};
|
|
browserResults[browser] = {
|
|
checks,
|
|
environment,
|
|
fixture_sha256: raw.fixture_sha256,
|
|
metrics: {
|
|
autosave_serialization: raw.autosave_serialization,
|
|
editor_reopen: raw.editor_reopen,
|
|
export_1080x1920: raw.export_1080x1920,
|
|
interaction: raw.interaction,
|
|
},
|
|
status: Object.values(checks).every(Boolean) ? "within_budget" : "budget_exceeded",
|
|
};
|
|
}
|
|
const passed = Object.values(browserResults).every((result) => result.status === "within_budget");
|
|
const report = {
|
|
browsers: browserResults,
|
|
eligible_for_green: phase === "green" && greenInputsEligible,
|
|
normative_budgets: WP4_07_PERFORMANCE_BUDGETS,
|
|
phase,
|
|
status: passed ? "within_budget" : "budget_exceeded",
|
|
};
|
|
writeFileSync(resolve(evidenceDirectory, "performance.json"), `${JSON.stringify(report, null, 2)}\n`);
|
|
writeFileSync(resolve(evidenceDirectory, "memory.json"), `${JSON.stringify({
|
|
browsers: Object.fromEntries(["chrome", "edge"].map((browser) => [browser, read(browser, "memory.json")])),
|
|
limit_bytes: WP4_07_PERFORMANCE_BUDGETS.export_peak_additional_bytes_max,
|
|
}, null, 2)}\n`);
|
|
writeFileSync(resolve(evidenceDirectory, "dom-count.json"), `${JSON.stringify({
|
|
browsers: Object.fromEntries(["chrome", "edge"].map((browser) => [browser, read(browser, "dom-count.json")])),
|
|
required_catalog_count: 1_407,
|
|
}, null, 2)}\n`);
|
|
writeFileSync(resolve(evidenceDirectory, "environment.json"), `${JSON.stringify({
|
|
browsers: Object.fromEntries(["chrome", "edge"].map((browser) => [browser, read(browser, "environment.json")])),
|
|
fixture_hashes_match: browserResults.chrome.fixture_sha256 === browserResults.edge.fixture_sha256,
|
|
}, null, 2)}\n`);
|
|
console.log(JSON.stringify({ browser_statuses: Object.fromEntries(Object.entries(browserResults).map(([name, result]) => [name, result.status])), phase, status: report.status }, null, 2));
|
|
if (phase === "green" && (!greenInputsEligible || !passed)) process.exit(1);
|