1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 15:24:46 -05:00
denoland-deno/tools/wpt/runner.ts
2022-01-20 16:10:16 +09:00

199 lines
4.7 KiB
TypeScript

// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { delay, join, readLines, ROOT_PATH, toFileUrl } from "../util.js";
import { assert, denoBinary, ManifestTestOptions, runPy } from "./utils.ts";
import { DOMParser } from "https://deno.land/x/deno_dom@v0.1.3-alpha2/deno-dom-wasm.ts";
export async function runWithTestUtil<T>(
verbose: boolean,
f: () => Promise<T>,
): Promise<T> {
const proc = runPy([
"wpt",
"serve",
"--config",
"../../tools/wpt/config.json",
], {
stdout: verbose ? "inherit" : "piped",
stderr: verbose ? "inherit" : "piped",
});
const start = performance.now();
while (true) {
await delay(1000);
try {
const req = await fetch("http://localhost:8000/");
await req.body?.cancel();
if (req.status == 200) {
break;
}
} catch (_err) {
// do nothing if this fails
}
const passedTime = performance.now() - start;
if (passedTime > 15000) {
proc.kill("SIGINT");
await proc.status();
proc.close();
throw new Error("Timed out while trying to start wpt test util.");
}
}
if (verbose) console.log(`Started wpt test util.`);
try {
return await f();
} finally {
if (verbose) console.log("Killing wpt test util.");
proc.kill("SIGINT");
await proc.status();
proc.close();
}
}
export interface TestResult {
cases: TestCaseResult[];
harnessStatus: TestHarnessStatus | null;
duration: number;
status: number;
stderr: string;
}
export interface TestHarnessStatus {
status: number;
message: string | null;
stack: string | null;
}
export interface TestCaseResult {
name: string;
passed: boolean;
status: number;
message: string | null;
stack: string | null;
}
export async function runSingleTest(
url: URL,
_options: ManifestTestOptions,
reporter: (result: TestCaseResult) => void,
inspectBrk: boolean,
): Promise<TestResult> {
const bundle = await generateBundle(url);
const tempFile = await Deno.makeTempFile({
prefix: "wpt-bundle-",
suffix: ".js",
});
try {
await Deno.writeTextFile(tempFile, bundle);
const startTime = new Date().getTime();
const cmd = [
denoBinary(),
"run",
];
cmd.push(
"-A",
"--unstable",
);
if (inspectBrk) {
cmd.push("--inspect-brk");
}
cmd.push(
"--enable-testing-features-do-not-use",
"--location",
url.toString(),
"--cert",
join(ROOT_PATH, `./tools/wpt/certs/cacert.pem`),
tempFile,
"[]",
);
const proc = Deno.run({
cmd,
env: {
NO_COLOR: "1",
},
stdout: "null",
stderr: "piped",
});
const cases = [];
let stderr = "";
let harnessStatus = null;
const lines = readLines(proc.stderr);
for await (const line of lines) {
if (line.startsWith("{")) {
const data = JSON.parse(line);
const result = { ...data, passed: data.status == 0 };
cases.push(result);
reporter(result);
} else if (line.startsWith("#$#$#{")) {
harnessStatus = JSON.parse(line.slice(5));
} else {
stderr += line + "\n";
console.error(line);
}
}
const duration = new Date().getTime() - startTime;
const { code } = await proc.status();
return {
status: code,
harnessStatus,
duration,
cases,
stderr,
};
} finally {
await Deno.remove(tempFile);
}
}
async function generateBundle(location: URL): Promise<string> {
const res = await fetch(location);
const body = await res.text();
const doc = new DOMParser().parseFromString(body, "text/html");
assert(doc, "document should have been parsed");
const scripts = doc.getElementsByTagName("script");
const scriptContents = [];
let inlineScriptCount = 0;
for (const script of scripts) {
const src = script.getAttribute("src");
if (src === "/resources/testharnessreport.js") {
const url = toFileUrl(
join(ROOT_PATH, "./tools/wpt/testharnessreport.js"),
);
const contents = await Deno.readTextFile(url);
scriptContents.push([url.href, contents]);
} else if (src) {
const url = new URL(src, location);
const res = await fetch(url);
if (res.ok) {
const contents = await res.text();
scriptContents.push([url.href, contents]);
}
} else {
const url = new URL(`#${inlineScriptCount}`, location);
inlineScriptCount++;
scriptContents.push([url.href, script.textContent]);
}
}
return scriptContents.map(([url, contents]) => `
(function() {
const [_,err] = Deno.core.evalContext(${JSON.stringify(contents)}, ${
JSON.stringify(url)
});
if (err !== null) {
throw err?.thrown;
}
})();`).join("\n");
}