summaryrefslogtreecommitdiff
path: root/tools/wpt/runner.ts
diff options
context:
space:
mode:
Diffstat (limited to 'tools/wpt/runner.ts')
-rw-r--r--tools/wpt/runner.ts133
1 files changed, 133 insertions, 0 deletions
diff --git a/tools/wpt/runner.ts b/tools/wpt/runner.ts
new file mode 100644
index 000000000..28b2db0ee
--- /dev/null
+++ b/tools/wpt/runner.ts
@@ -0,0 +1,133 @@
+import { delay, join, readLines, ROOT_PATH } from "../util.js";
+import { assert, ManifestTestOptions, release, 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"], {
+ 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) {
+ 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(2);
+ await proc.status();
+ proc.close();
+ }
+}
+
+export interface TestResult {
+ cases: TestCaseResult[];
+ status: number;
+ stderr: string;
+}
+
+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,
+): Promise<TestResult> {
+ const bundle = await generateBundle(url);
+ const tempFile = await Deno.makeTempFile({
+ prefix: "wpt-bundle-",
+ suffix: ".js",
+ });
+ await Deno.writeTextFile(tempFile, bundle);
+
+ const proc = Deno.run({
+ cmd: [
+ join(ROOT_PATH, `./target/${release ? "release" : "debug"}/deno`),
+ "run",
+ "-A",
+ "--location",
+ url.toString(),
+ tempFile,
+ "[]",
+ ],
+ env: {
+ NO_COLOR: "1",
+ },
+ stdout: "null",
+ stderr: "piped",
+ });
+
+ const cases = [];
+ let stderr = "";
+
+ 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 {
+ stderr += line + "\n";
+ }
+ }
+
+ const { code } = await proc.status();
+ return {
+ status: code,
+ cases,
+ stderr,
+ };
+}
+
+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 = [];
+ for (const script of scripts) {
+ const src = script.getAttribute("src");
+ if (src === "/resources/testharnessreport.js") {
+ scriptContents.push(
+ await Deno.readTextFile(
+ join(ROOT_PATH, "./tools/wpt/testharnessreport.js"),
+ ),
+ );
+ } else if (src) {
+ const res = await fetch(new URL(src, location));
+ scriptContents.push(await res.text());
+ } else {
+ scriptContents.push(script.textContent);
+ }
+ }
+ return scriptContents.join("\n");
+}