90 lines
2.6 KiB
TypeScript
90 lines
2.6 KiB
TypeScript
import { readFile } from "node:fs/promises";
|
|
|
|
const evidencePath =
|
|
"artifacts/tests/browser-capabilities/results.xml";
|
|
const xml = await readFile(evidencePath, "utf8");
|
|
const failures: string[] = [];
|
|
const rootAttributes =
|
|
/<testsuites\b([^>]*)>/u.exec(xml)?.[1] ?? "";
|
|
const root = attributes(rootAttributes);
|
|
|
|
for (const field of ["failures", "errors", "skipped"] as const) {
|
|
if (root[field] !== "0") {
|
|
failures.push(`root ${field} must be zero`);
|
|
}
|
|
}
|
|
if (!positiveInteger(root.tests)) {
|
|
failures.push("root tests must be positive");
|
|
}
|
|
|
|
const casesByEngine = new Map<string, Set<string>>();
|
|
for (const match of xml.matchAll(
|
|
/<testsuite\b([^>]*)>([\s\S]*?)<\/testsuite>/gu,
|
|
)) {
|
|
const suite = attributes(match[1] ?? "");
|
|
const engine = suite.hostname;
|
|
if (!engine) continue;
|
|
const cases =
|
|
casesByEngine.get(engine) ?? new Set<string>();
|
|
for (const testCase of (match[2] ?? "").matchAll(
|
|
/<testcase\b([^>]*)>/gu,
|
|
)) {
|
|
const data = attributes(testCase[1] ?? "");
|
|
if (data.classname && data.name) {
|
|
cases.add(`${data.classname}::${data.name}`);
|
|
}
|
|
}
|
|
casesByEngine.set(engine, cases);
|
|
}
|
|
|
|
const expectedEngines = ["chromium", "firefox", "webkit"] as const;
|
|
const baseline = casesByEngine.get(expectedEngines[0]);
|
|
for (const engine of expectedEngines) {
|
|
const cases = casesByEngine.get(engine);
|
|
if (!cases || cases.size === 0) {
|
|
failures.push(`${engine} has no executed browser-capability cases`);
|
|
continue;
|
|
}
|
|
if (
|
|
baseline &&
|
|
(cases.size !== baseline.size ||
|
|
[...baseline].some((testCase) => !cases.has(testCase)))
|
|
) {
|
|
failures.push(`${engine} case set differs from chromium`);
|
|
}
|
|
}
|
|
for (const engine of casesByEngine.keys()) {
|
|
if (!expectedEngines.includes(engine as (typeof expectedEngines)[number])) {
|
|
failures.push(`unexpected browser project ${engine}`);
|
|
}
|
|
}
|
|
if (/<skipped\b/u.test(xml) || /<failure\b/u.test(xml)) {
|
|
failures.push("browser-capability evidence contains skipped/failure nodes");
|
|
}
|
|
|
|
if (failures.length > 0) {
|
|
process.stderr.write(
|
|
`Browser capability evidence failed:\n- ${failures.join("\n- ")}\n`,
|
|
);
|
|
process.exit(1);
|
|
}
|
|
process.stdout.write(
|
|
`Browser capability evidence: PASS (${baseline?.size ?? 0} cases x ${expectedEngines.length} engines, zero skipped)\n`,
|
|
);
|
|
|
|
function attributes(source: string): Record<string, string> {
|
|
return Object.fromEntries(
|
|
[...source.matchAll(/([A-Za-z][A-Za-z0-9_-]*)="([^"]*)"/gu)].map(
|
|
(match) => [match[1] ?? "", match[2] ?? ""],
|
|
),
|
|
);
|
|
}
|
|
|
|
function positiveInteger(value: string | undefined): boolean {
|
|
return (
|
|
typeof value === "string" &&
|
|
/^\d+$/u.test(value) &&
|
|
Number(value) > 0
|
|
);
|
|
}
|