diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index be718fe..928cbd2 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -101,7 +101,7 @@ jobs:
# Owns the rev derivation, the rev-keyed tools cache, the
# install, and the pins gate; conformance-ct::_ct-tools
# recognizes the stamped install and does not repeat it.
- uses: polymorph-components/polymorph-test/actions/setup@eabd159de34e38a6f2f32204ceb52392555f32d8
+ uses: polymorph-components/polymorph-test/actions/setup@aca1008344f754db1c2b88da05cb5999333f8d6a
with:
js-locks: |
conformance/driver-ct/jco/package-lock.json
@@ -161,7 +161,7 @@ jobs:
# input polices the `uses:` refs against the pin.
- name: Publish the conformance matrix
if: always() && hashFiles('conformance/driver-ct/results/*.jsonl') != ''
- uses: polymorph-components/polymorph-test/actions/aggregate@eabd159de34e38a6f2f32204ceb52392555f32d8
+ uses: polymorph-components/polymorph-test/actions/aggregate@aca1008344f754db1c2b88da05cb5999333f8d6a
with:
lock: conformance/guest-ct/tests.lock
manifest: conformance/driver-ct/targets.toml
@@ -176,7 +176,7 @@ jobs:
- name: Publish the signing conformance matrix
if: always() && hashFiles('conformance/driver-ct/results/*.jsonl') != ''
- uses: polymorph-components/polymorph-test/actions/aggregate@eabd159de34e38a6f2f32204ceb52392555f32d8
+ uses: polymorph-components/polymorph-test/actions/aggregate@aca1008344f754db1c2b88da05cb5999333f8d6a
with:
lock: conformance/signing-guest-ct/tests.lock
manifest: conformance/driver-ct/targets-signing.toml
diff --git a/Cargo.lock b/Cargo.lock
index 8298748..617e0b2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -336,7 +336,7 @@ dependencies = [
[[package]]
name = "component-test-core"
version = "0.1.0"
-source = "git+https://github.com/polymorph-components/polymorph-test?rev=eabd159de34e38a6f2f32204ceb52392555f32d8#eabd159de34e38a6f2f32204ceb52392555f32d8"
+source = "git+https://github.com/polymorph-components/polymorph-test?rev=aca1008344f754db1c2b88da05cb5999333f8d6a#aca1008344f754db1c2b88da05cb5999333f8d6a"
dependencies = [
"arcstr",
"serde",
@@ -345,7 +345,7 @@ dependencies = [
[[package]]
name = "component-test-formats"
version = "0.1.0"
-source = "git+https://github.com/polymorph-components/polymorph-test?rev=eabd159de34e38a6f2f32204ceb52392555f32d8#eabd159de34e38a6f2f32204ceb52392555f32d8"
+source = "git+https://github.com/polymorph-components/polymorph-test?rev=aca1008344f754db1c2b88da05cb5999333f8d6a#aca1008344f754db1c2b88da05cb5999333f8d6a"
dependencies = [
"anyhow",
"component-test-core",
@@ -360,7 +360,7 @@ dependencies = [
[[package]]
name = "component-test-results"
version = "0.1.0"
-source = "git+https://github.com/polymorph-components/polymorph-test?rev=eabd159de34e38a6f2f32204ceb52392555f32d8#eabd159de34e38a6f2f32204ceb52392555f32d8"
+source = "git+https://github.com/polymorph-components/polymorph-test?rev=aca1008344f754db1c2b88da05cb5999333f8d6a#aca1008344f754db1c2b88da05cb5999333f8d6a"
dependencies = [
"anyhow",
"component-test-core",
@@ -371,7 +371,7 @@ dependencies = [
[[package]]
name = "component-test-runner"
version = "0.1.0"
-source = "git+https://github.com/polymorph-components/polymorph-test?rev=eabd159de34e38a6f2f32204ceb52392555f32d8#eabd159de34e38a6f2f32204ceb52392555f32d8"
+source = "git+https://github.com/polymorph-components/polymorph-test?rev=aca1008344f754db1c2b88da05cb5999333f8d6a#aca1008344f754db1c2b88da05cb5999333f8d6a"
dependencies = [
"anyhow",
"component-test-core",
@@ -387,7 +387,7 @@ dependencies = [
[[package]]
name = "component-test-sdk"
version = "0.1.0"
-source = "git+https://github.com/polymorph-components/polymorph-test?rev=eabd159de34e38a6f2f32204ceb52392555f32d8#eabd159de34e38a6f2f32204ceb52392555f32d8"
+source = "git+https://github.com/polymorph-components/polymorph-test?rev=aca1008344f754db1c2b88da05cb5999333f8d6a#aca1008344f754db1c2b88da05cb5999333f8d6a"
dependencies = [
"component-test-core",
"component-test-sdk-macro",
@@ -399,7 +399,7 @@ dependencies = [
[[package]]
name = "component-test-sdk-macro"
version = "0.1.0"
-source = "git+https://github.com/polymorph-components/polymorph-test?rev=eabd159de34e38a6f2f32204ceb52392555f32d8#eabd159de34e38a6f2f32204ceb52392555f32d8"
+source = "git+https://github.com/polymorph-components/polymorph-test?rev=aca1008344f754db1c2b88da05cb5999333f8d6a#aca1008344f754db1c2b88da05cb5999333f8d6a"
dependencies = [
"component-test-core",
"proc-macro2",
@@ -2457,7 +2457,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
- "getrandom 0.4.3",
+ "getrandom 0.3.4",
"once_cell",
"rustix",
"windows-sys 0.61.2",
diff --git a/Cargo.toml b/Cargo.toml
index 639760c..5d2c892 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,8 +26,8 @@ resolver = "2"
# override — see AGENTS.md "Build & run". Publishing component-test
# to a registry retires this arrangement.
[workspace.dependencies]
-component-test-sdk = { git = "https://github.com/polymorph-components/polymorph-test", rev = "eabd159de34e38a6f2f32204ceb52392555f32d8" }
-component-test-runner = { git = "https://github.com/polymorph-components/polymorph-test", rev = "eabd159de34e38a6f2f32204ceb52392555f32d8" }
+component-test-sdk = { git = "https://github.com/polymorph-components/polymorph-test", rev = "aca1008344f754db1c2b88da05cb5999333f8d6a" }
+component-test-runner = { git = "https://github.com/polymorph-components/polymorph-test", rev = "aca1008344f754db1c2b88da05cb5999333f8d6a" }
# The mutation run's profile (`just mutants`): dependencies optimized —
# wasmtime and the RustCrypto cores are compiled once, at baseline, and make
diff --git a/conformance/README.md b/conformance/README.md
index b8d97d8..b3a3fd1 100644
--- a/conformance/README.md
+++ b/conformance/README.md
@@ -111,7 +111,7 @@ the lockfiles, runs the targets, and aggregates:
- **jco-browser** (`run-browser`): the same transpiles and host module with
the case loop running in headless Chromium (`driver-ct/jco/harness.mjs`
in-page, driven by `run-browser.mjs` over
- `scripts/browser-page-driver.mjs`); missing `sha1-checked` and, for
+ the upstream browser driver); missing `sha1-checked` and, for
the signing suite, the fail-closed RSA private-key mints
(`rsa-sign`, `rsa-oaep-decrypt`). Optional: it gates in CI (the runner
image ships Chrome) and runs locally only with `CONFORMANCE_BROWSER=1`;
diff --git a/conformance/driver-ct/jco/browser-imports.mjs b/conformance/driver-ct/jco/browser-imports.mjs
new file mode 100644
index 0000000..00ac999
--- /dev/null
+++ b/conformance/driver-ct/jco/browser-imports.mjs
@@ -0,0 +1,16 @@
+// The browser worker's import-object module: the shared builder
+// (host-imports.mjs) over the preview2-shim browser build. Loaded by
+// the upstream browser-worker via URL, so every specifier is a server
+// path over the repository-root server.
+import { suiteImports as buildImports } from "./host-imports.mjs";
+import * as cli from "./node_modules/@bytecodealliance/preview2-shim/lib/browser/cli.js";
+import * as clocks from "./node_modules/@bytecodealliance/preview2-shim/lib/browser/clocks.js";
+import * as io from "./node_modules/@bytecodealliance/preview2-shim/lib/browser/io.js";
+import * as random from "./node_modules/@bytecodealliance/preview2-shim/lib/browser/random.js";
+import * as filesystem from "./node_modules/@bytecodealliance/preview2-shim/lib/browser/filesystem.js";
+
+/** The suites read no environment; the shim namespaces are the whole
+ * configuration. */
+export async function suiteImports() {
+ return buildImports({ cli, clocks, io, random, filesystem });
+}
diff --git a/conformance/driver-ct/jco/package-lock.json b/conformance/driver-ct/jco/package-lock.json
index ef767ba..8bb0a2c 100644
--- a/conformance/driver-ct/jco/package-lock.json
+++ b/conformance/driver-ct/jco/package-lock.json
@@ -8,7 +8,7 @@
"dependencies": {
"@bytecodealliance/jco-transpile": "https://github.com/lann/jco/releases/download/jco-transpile-0.6.2-fa6990d/bytecodealliance-jco-transpile-0.6.2.tgz",
"@bytecodealliance/preview2-shim": "0.17.9",
- "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#eabd159de34e38a6f2f32204ceb52392555f32d8",
+ "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#aca1008344f754db1c2b88da05cb5999333f8d6a",
"playwright-core": "1.62.1"
}
},
@@ -451,8 +451,8 @@
},
"node_modules/@polymorph/component-test-js": {
"version": "0.2.0",
- "resolved": "git+ssh://git@github.com/polymorph-components/polymorph-test.git#eabd159de34e38a6f2f32204ceb52392555f32d8",
- "integrity": "sha512-s0WkYdtIS1chajOwsrjC5vfpYY8bg4sQ9FGNKtWWU0D8ST7EpoZOBEYP1R9JrFzxp4MKLYxbu+GQeYW+Akh1Hw==",
+ "resolved": "git+ssh://git@github.com/polymorph-components/polymorph-test.git#aca1008344f754db1c2b88da05cb5999333f8d6a",
+ "integrity": "sha512-Idrza14qMhT4vQLRUNX/lLVammu/Lqu+NgawlM+IBuQQRZpeFJsNLLZg1NsHqPsqKX4tzlS1rkw8kXze7ChLYQ==",
"license": "Apache-2.0 WITH LLVM-exception",
"bin": {
"component-test-jco-transpile": "js/jco-transpile.mjs"
diff --git a/conformance/driver-ct/jco/package.json b/conformance/driver-ct/jco/package.json
index 1c827a1..187a3ce 100644
--- a/conformance/driver-ct/jco/package.json
+++ b/conformance/driver-ct/jco/package.json
@@ -12,7 +12,7 @@
"dependencies": {
"@bytecodealliance/jco-transpile": "https://github.com/lann/jco/releases/download/jco-transpile-0.6.2-fa6990d/bytecodealliance-jco-transpile-0.6.2.tgz",
"@bytecodealliance/preview2-shim": "0.17.9",
- "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#eabd159de34e38a6f2f32204ceb52392555f32d8",
+ "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#aca1008344f754db1c2b88da05cb5999333f8d6a",
"playwright-core": "1.62.1"
}
}
diff --git a/conformance/driver-ct/jco/run-browser.mjs b/conformance/driver-ct/jco/run-browser.mjs
index 040f699..0d96593 100644
--- a/conformance/driver-ct/jco/run-browser.mjs
+++ b/conformance/driver-ct/jco/run-browser.mjs
@@ -1,25 +1,32 @@
-// jco-browser driver for the ported conformance suites: serves the
-// repository root over localhost (so the transpiled guests' relative
-// imports of js/jco/webcrypto.js and the driver's context.js resolve),
-// runs both suites' case loops inside headless Chromium via the shared
-// page harness (harness.mjs, the same module runner.mjs drives under
-// Node), and writes results/jco-browser.jsonl +
-// results/jco-browser-signing.jsonl.
+// jco-browser driver for the ported conformance suites: both suites'
+// case loops run inside headless Chromium via the upstream page driver
+// — page, worker pool, stall watchdog, and Chrome ladder all live in
+// @polymorph/component-test-js — and write results/jco-browser.jsonl +
+// results/jco-browser-signing.jsonl. This file is the frame: core-URL
+// enumeration, per-suite configuration, results writing.
//
// Gates in CI (the Actions runner image ships Chrome); locally it needs
// a Chrome/Chromium install and runs only when opted in with
// CONFORMANCE_BROWSER=1 (`just conformance-ct::all`), or directly with
// `just conformance-ct::run-browser`.
-import { access, mkdir, writeFile } from "node:fs/promises";
-import { join } from "node:path";
+import { readdir } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { parseArgs } from "node:util";
-import { runPageHarness } from "../../../scripts/browser-page-driver.mjs";
-import { envelope } from "@polymorph/component-test-js/harness";
+import {
+ buildHarnessPage,
+ findChrome,
+ runPageHarness,
+} from "@polymorph/component-test-js/browser-driver";
+import { writeResultsFile } from "@polymorph/component-test-js/node-runner";
const REPO_ROOT = fileURLToPath(new URL("../../../", import.meta.url));
const RESULTS_DIR = fileURLToPath(new URL("../results/", import.meta.url));
+const BASE = "/conformance/driver-ct/jco";
+// Stall bound for the driver's inactivity watchdog: the pool
+// heartbeats per suite and per 25 rows, so quiet time is bounded by a
+// batch of the slowest cases.
+const STALL_TIMEOUT_MS = 90_000;
// The per-suite missing-features declarations are passed by the justfile
// (like jco-node's --missing), keeping them next to the jco-node ones and
@@ -33,16 +40,27 @@ const { values } = parseArgs({
},
});
+// Both suites run under one target key in their respective aggregates,
+// so the report (and the results file) is keyed per entry.
+const common = {
+ target: values.target,
+ importsUrl: `${BASE}/browser-imports.mjs`,
+ // The driver's test-context (diagnostic sink wiring), not the
+ // upstream default.
+ contextUrl: `/conformance/driver-ct/context.js`,
+};
const SUITES = [
{
+ ...common,
+ key: "jco-browser",
suite: "conformance-guest-ct",
missing: values.missing.split(",").filter(Boolean),
- out: "jco-browser.jsonl",
},
{
+ ...common,
+ key: "jco-browser-signing",
suite: "conformance-signing-guest-ct",
missing: values["missing-signing"].split(",").filter(Boolean),
- out: "jco-browser-signing.jsonl",
},
];
@@ -50,169 +68,38 @@ const SUITES = [
// however many cores the composition needs), so the page never fetches
// a missing file — a 404 would be tolerated but pollutes the console
// the driver mirrors.
-import { readdir } from "node:fs/promises";
for (const entry of SUITES) {
- const names = await readdir(new URL("./generated/", import.meta.url));
- entry.cores = names
+ const names = (await readdir(new URL("./generated/", import.meta.url))).sort();
+ entry.moduleUrl = `${BASE}/generated/${entry.suite}.js`;
+ entry.coreUrls = names
.filter((n) => n.startsWith(`${entry.suite}.core`) && n.endsWith(".wasm"))
- .sort();
+ .map((n) => `${BASE}/generated/${n}`);
}
-// The in-page harness: spawns a pool of module Web Workers
-// (worker-browser.mjs), each running one shard of a suite's case loop
-// with its own instance of the transpiled suite, instantiated with
-// imports bound at run time (host-imports.mjs: js/jco/webcrypto.js —
-// the browser-first host, feature-detecting per call — the driver's
-// test-context, and the preview2-shim browser build, all by relative
-// path: module workers cannot see a page's import map).
-// Rows come back tagged with their suite-order index and are re-sorted
-// before reporting.
-//
-// Heartbeats feed the Node-side stall watchdog: fire-and-forget (a
-// closing page must not turn a heartbeat into an unhandled rejection),
-// throttled to one per twenty-five rows.
-const BASE = "/conformance/driver-ct/jco";
-const harness = (suites) => `
-
-
polymorph:webcrypto conformance (component-test stack)
-`;
+const playwright = await import("playwright-core");
+const outcome = await runPageHarness({
+ playwright,
+ engine: "chromium",
+ executablePath: await findChrome(),
+ repoRoot: REPO_ROOT,
+ html: buildHarnessPage({
+ title: "polymorph:webcrypto conformance (component-test stack)",
+ config: { suites: SUITES },
+ }),
+ stallTimeoutMs: STALL_TIMEOUT_MS,
+});
-/** Locate a Chromium/Chrome binary: CHROME_PATH, common system names, then
- * the Playwright browser cache. */
-async function findChrome() {
- const { env } = process;
- const candidates = [];
- if (env.CHROME_PATH) candidates.push(env.CHROME_PATH);
- for (const name of ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]) {
- for (const dir of ["/usr/bin", "/usr/local/bin", "/opt/homebrew/bin"]) {
- candidates.push(join(dir, name));
- }
- }
- const cache = join(env.HOME ?? "", ".cache", "ms-playwright");
- try {
- const { readdir } = await import("node:fs/promises");
- for (const entry of (await readdir(cache)).sort().reverse()) {
- if (entry.startsWith("chromium_headless_shell-")) {
- candidates.push(join(cache, entry, "chrome-linux", "headless_shell"));
- } else if (entry.startsWith("chromium-")) {
- candidates.push(join(cache, entry, "chrome-linux", "chrome"));
- }
- }
- } catch {
- // No playwright cache.
- }
- for (const candidate of candidates) {
- try {
- await access(candidate);
- return candidate;
- } catch {
- // Try the next candidate.
- }
- }
- throw new Error(
- "no Chromium/Chrome binary found: set CHROME_PATH or install one " +
- "(e.g. `npx playwright-core install chromium`)",
+let failed = 0;
+for (const { key } of SUITES) {
+ const run = outcome[key];
+ if (!run) throw new Error(`the page reported no run for ${key}`);
+ const outPath = await writeResultsFile({ dir: RESULTS_DIR, target: key, lines: run.lines });
+ const c = run.counts;
+ process.stderr.write(
+ `${values.target} ${key}: ${c.passed} passed, ${c.failed} failed, ` +
+ `${c.skipped} skipped, ${c.na} not applicable, ${c.total} total ` +
+ `(wrote ${outPath})\n`,
);
+ failed += c.failed;
}
-
-// Stall bound for the driver's inactivity watchdog: the harness
-// heartbeats at least once per twenty-five rows, so quiet time is
-// bounded by a batch of the slowest cases.
-const STALL_TIMEOUT_MS = 90_000;
-
-async function main() {
- const playwright = await import("playwright-core");
- const outcome = await runPageHarness({
- playwright,
- engine: "chromium",
- executablePath: await findChrome(),
- repoRoot: REPO_ROOT,
- html: harness(SUITES),
- stallTimeoutMs: STALL_TIMEOUT_MS,
- });
-
- await mkdir(RESULTS_DIR, { recursive: true });
- let failed = 0;
- for (const { suite, out } of SUITES) {
- const run = outcome[suite];
- if (!run) throw new Error(`the page reported no run for suite ${suite}`);
- const lines = [
- JSON.stringify(envelope(values.target, suite)), // lockfile identity: wasm file stem
- ...run.events.map((event) => JSON.stringify(event)),
- '{"segment-end":true}',
- ];
- await writeFile(join(RESULTS_DIR, out), lines.join("\n") + "\n");
- const c = run.counts;
- console.error(
- `${values.target} ${suite}: ${c.passed} passed, ${c.failed} failed, ` +
- `${c.skipped} skipped, ${c.na} not applicable, ${c.total} total ` +
- `(wrote results/${out})`,
- );
- failed += c.failed;
- }
- process.exit(failed === 0 ? 0 : 1);
-}
-
-main().catch((err) => {
- console.error("jco-browser driver failed:", err);
- process.exit(1);
-});
+process.exit(failed === 0 ? 0 : 1);
diff --git a/conformance/driver-ct/jco/worker-browser.mjs b/conformance/driver-ct/jco/worker-browser.mjs
deleted file mode 100644
index c28a1b8..0000000
--- a/conformance/driver-ct/jco/worker-browser.mjs
+++ /dev/null
@@ -1,57 +0,0 @@
-// The Web Worker half of the jco-browser driver (run-browser.mjs): its
-// own instance of the transpiled suite runs one shard of the case loop,
-// streaming each results-JSONL event back with its suite-order index,
-// then the shard's counts. The browser counterpart of worker-node.mjs.
-// Relative specifiers throughout: module workers cannot see the page's
-// import map, so the wasi shim (browser build), the harness core, and
-// the host module all resolve by path.
-import { inventoryLookup, runCases } from "./node_modules/@polymorph/component-test-js/js/viewer/harness.mjs";
-import * as cli from "./node_modules/@bytecodealliance/preview2-shim/lib/browser/cli.js";
-import * as clocks from "./node_modules/@bytecodealliance/preview2-shim/lib/browser/clocks.js";
-import * as io from "./node_modules/@bytecodealliance/preview2-shim/lib/browser/io.js";
-import * as random from "./node_modules/@bytecodealliance/preview2-shim/lib/browser/random.js";
-import * as filesystem from "./node_modules/@bytecodealliance/preview2-shim/lib/browser/filesystem.js";
-import { Context } from "../context.js";
-import { instantiateSuite } from "./host-imports.mjs";
-
-// A rejection escaping the awaited chain (e.g. a platform quirk
-// surfacing through the transpiled guest's async plumbing) would
-// otherwise leave the worker silently wedged: unhandled rejections fire
-// neither the catch below nor the page's worker.onerror.
-self.onunhandledrejection = (event) => {
- event.preventDefault?.();
- self.postMessage({ kind: "error", error: String(event.reason?.stack ?? event.reason) });
-};
-
-self.onmessage = async ({ data }) => {
- const { suite, missing, cores, shard } = data;
- try {
- const coreBytes = [];
- const modules = new Map();
- for (const core of cores) {
- const res = await fetch(new URL(`./generated/${core}`, import.meta.url));
- if (!res.ok) throw new Error(`fetching ${core}: ${res.status}`);
- const bytes = new Uint8Array(await res.arrayBuffer());
- coreBytes.push(bytes);
- modules.set(core, await WebAssembly.compile(bytes));
- }
- const tagsOf = inventoryLookup(coreBytes);
- const { instantiate } = await import(`./generated/${suite}.js`);
- const tests = await instantiateSuite({
- instantiate,
- modules,
- wasi: { cli, clocks, io, random, filesystem },
- });
- const counts = await runCases({
- cases: await tests.all(),
- Context,
- tagsOf,
- missing,
- shard,
- emit: (event, index) => self.postMessage({ kind: "event", index, event }),
- });
- self.postMessage({ kind: "counts", counts });
- } catch (err) {
- self.postMessage({ kind: "error", error: String(err?.stack ?? err) });
- }
-};
diff --git a/conformance/driver-ct/justfile b/conformance/driver-ct/justfile
index 814ae0b..ff8e5d4 100644
--- a/conformance/driver-ct/justfile
+++ b/conformance/driver-ct/justfile
@@ -254,7 +254,7 @@ run-composed: build build-provider _ct-tools
# The jco-browser target: the same transpiles and the same host module,
# with the case loop running inside headless Chromium (browser WebCrypto)
-# via the shared page driver (scripts/browser-page-driver.mjs). The
+# via the upstream page driver (@polymorph/component-test-js). The
# --missing declarations mirror targets.toml / targets-signing.toml's
# jco-browser entries, which the aggregate cross-checks: the browser
# cannot serve sha1-checked, and the host fails the gated RSA
diff --git a/examples/jco-demo/package-lock.json b/examples/jco-demo/package-lock.json
index 45a743f..4cf2c85 100644
--- a/examples/jco-demo/package-lock.json
+++ b/examples/jco-demo/package-lock.json
@@ -9,7 +9,7 @@
"version": "0.1.0",
"devDependencies": {
"@bytecodealliance/jco-transpile": "https://github.com/lann/jco/releases/download/jco-transpile-0.6.2-fa6990d/bytecodealliance-jco-transpile-0.6.2.tgz",
- "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#eabd159de34e38a6f2f32204ceb52392555f32d8"
+ "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#aca1008344f754db1c2b88da05cb5999333f8d6a"
}
},
"node_modules/@bytecodealliance/jco-transpile": {
@@ -473,8 +473,8 @@
},
"node_modules/@polymorph/component-test-js": {
"version": "0.2.0",
- "resolved": "git+ssh://git@github.com/polymorph-components/polymorph-test.git#eabd159de34e38a6f2f32204ceb52392555f32d8",
- "integrity": "sha512-s0WkYdtIS1chajOwsrjC5vfpYY8bg4sQ9FGNKtWWU0D8ST7EpoZOBEYP1R9JrFzxp4MKLYxbu+GQeYW+Akh1Hw==",
+ "resolved": "git+ssh://git@github.com/polymorph-components/polymorph-test.git#aca1008344f754db1c2b88da05cb5999333f8d6a",
+ "integrity": "sha512-Idrza14qMhT4vQLRUNX/lLVammu/Lqu+NgawlM+IBuQQRZpeFJsNLLZg1NsHqPsqKX4tzlS1rkw8kXze7ChLYQ==",
"dev": true,
"license": "Apache-2.0 WITH LLVM-exception",
"bin": {
diff --git a/examples/jco-demo/package.json b/examples/jco-demo/package.json
index 936988d..963c2c1 100644
--- a/examples/jco-demo/package.json
+++ b/examples/jco-demo/package.json
@@ -12,6 +12,6 @@
},
"devDependencies": {
"@bytecodealliance/jco-transpile": "https://github.com/lann/jco/releases/download/jco-transpile-0.6.2-fa6990d/bytecodealliance-jco-transpile-0.6.2.tgz",
- "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#eabd159de34e38a6f2f32204ceb52392555f32d8"
+ "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#aca1008344f754db1c2b88da05cb5999333f8d6a"
}
}
diff --git a/js/componentize/wpt/parity/package-lock.json b/js/componentize/wpt/parity/package-lock.json
index add1582..8d1ff67 100644
--- a/js/componentize/wpt/parity/package-lock.json
+++ b/js/componentize/wpt/parity/package-lock.json
@@ -10,7 +10,7 @@
"devDependencies": {
"@bytecodealliance/jco-transpile": "https://github.com/lann/jco/releases/download/jco-transpile-0.6.2-fa6990d/bytecodealliance-jco-transpile-0.6.2.tgz",
"@bytecodealliance/preview2-shim": "^0.19.0",
- "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#eabd159de34e38a6f2f32204ceb52392555f32d8",
+ "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#aca1008344f754db1c2b88da05cb5999333f8d6a",
"playwright-core": "^1.62.1"
}
},
@@ -475,8 +475,8 @@
},
"node_modules/@polymorph/component-test-js": {
"version": "0.2.0",
- "resolved": "git+ssh://git@github.com/polymorph-components/polymorph-test.git#eabd159de34e38a6f2f32204ceb52392555f32d8",
- "integrity": "sha512-s0WkYdtIS1chajOwsrjC5vfpYY8bg4sQ9FGNKtWWU0D8ST7EpoZOBEYP1R9JrFzxp4MKLYxbu+GQeYW+Akh1Hw==",
+ "resolved": "git+ssh://git@github.com/polymorph-components/polymorph-test.git#aca1008344f754db1c2b88da05cb5999333f8d6a",
+ "integrity": "sha512-Idrza14qMhT4vQLRUNX/lLVammu/Lqu+NgawlM+IBuQQRZpeFJsNLLZg1NsHqPsqKX4tzlS1rkw8kXze7ChLYQ==",
"dev": true,
"license": "Apache-2.0 WITH LLVM-exception",
"bin": {
diff --git a/js/componentize/wpt/parity/package.json b/js/componentize/wpt/parity/package.json
index 2057cba..c8db37d 100644
--- a/js/componentize/wpt/parity/package.json
+++ b/js/componentize/wpt/parity/package.json
@@ -18,6 +18,6 @@
"@bytecodealliance/jco-transpile": "https://github.com/lann/jco/releases/download/jco-transpile-0.6.2-fa6990d/bytecodealliance-jco-transpile-0.6.2.tgz",
"@bytecodealliance/preview2-shim": "^0.19.0",
"playwright-core": "^1.62.1",
- "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#eabd159de34e38a6f2f32204ceb52392555f32d8"
+ "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#aca1008344f754db1c2b88da05cb5999333f8d6a"
}
}
diff --git a/js/componentize/wpt/parity/run-browser.mjs b/js/componentize/wpt/parity/run-browser.mjs
index 75fddac..7027409 100644
--- a/js/componentize/wpt/parity/run-browser.mjs
+++ b/js/componentize/wpt/parity/run-browser.mjs
@@ -4,7 +4,7 @@
// writes the two record files the comparator consumes to ../build/
// (parity-baseline-.json, parity-roundtrip-.json).
// The serve/launch/watchdog machinery is the shared page driver
-// (scripts/browser-page-driver.mjs).
+// (@polymorph/component-test-js/browser-driver).
//
// `--engine firefox` (default) or `--engine chromium` selects the browser:
// always Playwright's own build (pinned by playwright-core's version, so
@@ -17,7 +17,7 @@ import { mkdir, writeFile } from "node:fs/promises";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
-import { runPageHarness } from "../../../../scripts/browser-page-driver.mjs";
+import { runPageHarness } from "@polymorph/component-test-js/browser-driver";
const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "..");
const OUT_DIR = join(REPO_ROOT, "js", "componentize", "wpt", "build");
diff --git a/js/jco/package-lock.json b/js/jco/package-lock.json
index 86c0cfb..73e1f35 100644
--- a/js/jco/package-lock.json
+++ b/js/jco/package-lock.json
@@ -9,7 +9,7 @@
"version": "0.1.0",
"devDependencies": {
"@bytecodealliance/jco-transpile": "0.5.2",
- "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#eabd159de34e38a6f2f32204ceb52392555f32d8",
+ "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#aca1008344f754db1c2b88da05cb5999333f8d6a",
"typescript": "^5.9.3"
}
},
@@ -467,8 +467,8 @@
},
"node_modules/@polymorph/component-test-js": {
"version": "0.2.0",
- "resolved": "git+ssh://git@github.com/polymorph-components/polymorph-test.git#eabd159de34e38a6f2f32204ceb52392555f32d8",
- "integrity": "sha512-s0WkYdtIS1chajOwsrjC5vfpYY8bg4sQ9FGNKtWWU0D8ST7EpoZOBEYP1R9JrFzxp4MKLYxbu+GQeYW+Akh1Hw==",
+ "resolved": "git+ssh://git@github.com/polymorph-components/polymorph-test.git#aca1008344f754db1c2b88da05cb5999333f8d6a",
+ "integrity": "sha512-Idrza14qMhT4vQLRUNX/lLVammu/Lqu+NgawlM+IBuQQRZpeFJsNLLZg1NsHqPsqKX4tzlS1rkw8kXze7ChLYQ==",
"dev": true,
"license": "Apache-2.0 WITH LLVM-exception",
"bin": {
diff --git a/js/jco/package.json b/js/jco/package.json
index 9c447ed..1260792 100644
--- a/js/jco/package.json
+++ b/js/jco/package.json
@@ -13,6 +13,6 @@
"devDependencies": {
"@bytecodealliance/jco-transpile": "0.5.2",
"typescript": "^5.9.3",
- "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#eabd159de34e38a6f2f32204ceb52392555f32d8"
+ "@polymorph/component-test-js": "github:polymorph-components/polymorph-test#aca1008344f754db1c2b88da05cb5999333f8d6a"
}
}
diff --git a/scripts/browser-page-driver.mjs b/scripts/browser-page-driver.mjs
deleted file mode 100644
index ca24886..0000000
--- a/scripts/browser-page-driver.mjs
+++ /dev/null
@@ -1,159 +0,0 @@
-// Shared Playwright page driver for the repository's browser gates,
-// today the WPT parity browser adapter (js/componentize/
-// wpt/parity/run-browser.mjs). It serves the repository root over
-// localhost with a caller-supplied harness page at "/", runs that page in
-// a headless Playwright engine, and resolves with whatever the page
-// reports.
-//
-// This module imports only Node builtins; the caller passes in its own
-// playwright-core module, since each npm tree pins its own version.
-//
-// The page contract: the harness calls `window.__progress(note)` as work
-// streams (the heartbeat the stall watchdog observes) and
-// `window.__report(outcome)` exactly once at the end, with `{ error }`
-// carrying an in-page failure.
-
-import { createServer } from "node:http";
-import { readFile } from "node:fs/promises";
-import { join, extname } from "node:path";
-
-const MIME = {
- ".html": "text/html",
- ".js": "text/javascript",
- ".mjs": "text/javascript",
- ".wasm": "application/wasm",
- ".map": "application/json",
-};
-
-/** Serve `repoRoot` statically (so the transpiled guests' relative imports
- * resolve) plus the harness page at "/". */
-function serve(repoRoot, html) {
- const server = createServer(async (req, res) => {
- const path = new URL(req.url, "http://localhost").pathname;
- if (path === "/") {
- res.writeHead(200, { "content-type": "text/html" });
- res.end(html);
- return;
- }
- try {
- const file = join(repoRoot, path);
- const body = await readFile(file);
- res.writeHead(200, {
- "content-type": MIME[extname(file)] ?? "application/octet-stream",
- });
- res.end(body);
- } catch {
- res.writeHead(404);
- res.end("not found");
- }
- });
- return new Promise((resolve) => {
- server.listen(0, "127.0.0.1", () => resolve(server));
- });
-}
-
-function launchBrowser(playwright, engine, executablePath, timeout) {
- if (engine === "firefox") {
- // Gecko's JSPI pref: the transpiled guests suspend on JSPI, which
- // Firefox has not yet shipped by default.
- return playwright.firefox.launch({
- headless: true,
- timeout,
- firefoxUserPrefs: {
- "javascript.options.wasm_js_promise_integration": true,
- },
- });
- }
- const options = { headless: true, timeout };
- if (executablePath !== undefined) options.executablePath = executablePath;
- return playwright[engine].launch(options);
-}
-
-/**
- * Run a harness page to completion and return what it reported.
- *
- * Watchdog bounds: browser launch and page load get hard timeouts; the run
- * itself is bounded by *inactivity* — the harness heartbeats as results
- * stream in, so a stall means the page hung (a wedged worker, a deadlocked
- * JSPI suspension, an uncaught error nothing was listening for), and the
- * watchdog fails fast with the last heartbeat naming where.
- * `stallTimeoutMs` is per-caller: the tolerable quiet time depends on the
- * harness's heartbeat cadence.
- *
- * @param {object} options
- * @param {object} options.playwright The caller's playwright-core module.
- * @param {string} options.engine "chromium" | "firefox" | "webkit".
- * @param {string} [options.executablePath] A specific browser binary,
- * instead of Playwright's own build of the engine.
- * @param {string} options.repoRoot Directory the static server serves.
- * @param {string} options.html The harness document served at "/".
- * @param {number} options.stallTimeoutMs Max quiet time between heartbeats.
- * @param {number} [options.launchTimeoutMs]
- * @param {number} [options.loadTimeoutMs]
- * @returns {Promise