Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ rust-checks:
conformance-checks:
@just gha::_step conformance-ct::all
@just gha::_step wpt::parity
@just gha::_step wpt::parity-chromium
@just gha::_step demo::test
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,29 @@ jobs:
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: pnpm-store-v2-${{ runner.os }}-${{ hashFiles('conformance/driver-ct/jco/pnpm-lock.yaml', 'examples/jco-demo/pnpm-lock.yaml', 'js/componentize/wpt/parity/pnpm-lock.yaml') }}
# The WPT parity Chromium leg always runs Playwright's own build,
# pinned by playwright-core's version in the parity lockfile, so
# losses-chromium.js measures one engine everywhere. The cache key
# follows that lockfile; restore-keys lets a playwright bump start
# from the previous browsers and download only what changed.
- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ hashFiles('js/componentize/wpt/parity/pnpm-lock.yaml') }}
restore-keys: playwright-${{ runner.os }}-
- name: Install Playwright Chromium
# On a cache hit the install only verifies the browser is present;
# --with-deps (an apt run) is needed only when the browser was
# actually (re)downloaded.
run: |
cd js/componentize/wpt/parity
if [ "${{ steps.playwright-cache.outputs.cache-hit }}" = "true" ]; then
npx playwright-core install chromium
else
npx playwright-core install --with-deps chromium
fi
- run: just gha::conformance-checks
# The jco-browser adapter finds the runner's preinstalled Chrome via
# its candidate paths; CHROME_PATH overrides if ever needed.
Expand Down
11 changes: 7 additions & 4 deletions js/componentize/wpt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ unbundled. Each engine ratchets separately (`parity/losses-chromium.js`,
re-recorded with `just wpt::update-losses-chromium`): a loss set is a fact
about one engine's baseline.

The Chromium gate is currently blocked at the ratchet: some vendored test
names embed the echo server's per-run port, so the Chromium loss set does
not record stably (issue #26). Both legs complete; the gate joins CI when
the ratchet keys are stable.
The Chromium legs always run Playwright's own build, pinned by
playwright-core's version in the parity lockfile, so the loss set
measures one engine everywhere — local runs and CI alike; a Chromium
behavior shift arrives only with a deliberate playwright bump. Test
names are engine-independent by construction — `wpt-env.js` shadows
`location` with a fixed stub in every leg, so names never embed a
per-run origin.

## Vendoring policy

Expand Down
9 changes: 5 additions & 4 deletions js/componentize/wpt/justfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ update-losses: _artifacts
# baseline measures Chromium's own WebSocket, the round trip runs the
# browser-profile transpile against websocket-jco in the environment it
# targets. Ratchets separately in parity/losses-chromium.js — a loss set
# is a fact about one engine's baseline. Currently blocked at the ratchet:
# some test names embed the echo server's per-run port, so the loss set
# does not record stably (issue #26); not in CI until that resolves.
# is a fact about one engine's baseline. The browser is always
# Playwright's pinned Chromium build (install once with
# `npx playwright-core install --with-deps chromium` from parity/), so
# the loss set measures one engine everywhere.
parity-chromium: _artifacts-web
{{timeout_cmd}} node {{root}}/js/componentize/wpt/parity/run-browser.mjs

# Re-record parity/losses-chromium.js from an actual Chromium run; same
# review bar as update-losses. Blocked with parity-chromium (issue #26).
# review bar as update-losses.
update-losses-chromium: _artifacts-web
{{timeout_cmd}} node {{root}}/js/componentize/wpt/parity/run-browser.mjs --update

Expand Down
11 changes: 11 additions & 0 deletions js/componentize/wpt/parity/losses-chromium.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// The WPT parity ratchet: every test the platform baseline passes that the
// round trip (shim -> WIT -> jco -> websocket-jco) does not, keyed
// `group :: test name`. Generated by `just wpt::update-losses-chromium`; compare.mjs
// fails on any loss not listed here and on any listed loss no longer
// observed, so this file only changes deliberately and only shrinks as the
// shim serves more of the platform's behavior. Which kind each loss is —
// unserved or WIT-forced — is the shim header's deviations registry's to
// say (js/componentize/websocket.js).
export const KNOWN_LOSSES = [

];
18 changes: 5 additions & 13 deletions js/componentize/wpt/parity/run-browser.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@
// echo server directly: WebSocket is not subject to CORS, and a localhost
// `http:` page may open `ws:` connections.
//
// jco's async ABI needs JSPI; Chrome ships it enabled from 137 onward.
//
// KNOWN BLOCKED (issue #26): both legs complete, but several vendored
// tests interpolate the echo server's per-run port into their names, so
// the recorded loss set does not key stably across runs. This runner
// stays out of CI until the ratchet keys are stable.
// The browser is always Playwright's own Chromium build, pinned by
// playwright-core's version (the parity lockfile), so losses-chromium.js
// measures one engine everywhere — local runs and CI alike. Install it
// once with `npx playwright-core install --with-deps chromium` (from this
// directory). jco's async ABI needs JSPI; Chromium ships it.
//
// Usage: node run-browser.mjs [--update]

Expand All @@ -31,7 +30,6 @@ import { fileURLToPath } from "node:url";

import { chromium } from "playwright-core";

import { findChrome } from "../../../../scripts/chrome.mjs";
import { spawnEchod } from "../../../../conformance/server/echod.mjs";

const HERE = dirname(fileURLToPath(import.meta.url));
Expand Down Expand Up @@ -104,18 +102,12 @@ async function main() {
throw new Error(`missing browser-profile transpile in ${join(HERE, "generated-web")}; run "npm run transpile:web" first`);
}

const executablePath = await findChrome();
if (!executablePath) {
throw new Error("no Chrome/Chromium binary found; set CHROME_PATH to a Chrome 137+ executable");
}

const echod = await spawnEchod(join(REPO_ROOT, "target", "debug", "conformance-echod"));
const server = await startServer();
const base = `http://127.0.0.1:${server.address().port}`;
process.stderr.write(`echo server at ${echod.base}; page served from ${base}\n`);

const browser = await chromium.launch({
executablePath,
headless: true,
args: ["--no-sandbox", "--disable-dev-shm-usage"],
});
Expand Down
25 changes: 14 additions & 11 deletions js/componentize/wpt/wpt-env.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,20 @@ Object.defineProperty(globalThis, "SCHEME_DOMAIN_PORT", {
});

// A minimal `location` for suites that build negative-case URLs from the
// page origin. The values are inert (nothing serves them); identical in
// both parity legs so the comparison stays fair.
if (globalThis.location === undefined) {
globalThis.location = {
protocol: "http:",
host: "web-platform.test:8001",
hostname: "web-platform.test",
origin: "http://web-platform.test:8001",
search: "",
};
}
// page origin. The values are inert (nothing serves them) and are
// wptserve's canonical host:port, so interpolated test names match
// upstream WPT's. A module-scoped `const` deliberately shadows
// `window.location` when a leg runs in a browser page: suites that
// interpolate `location` into test names (Create-invalid-urls) must
// evaluate identical names in every leg, or the parity keys embed the
// page server's per-run ephemeral port and the legs' name sets diverge.
const location = {
protocol: "http:",
host: "web-platform.test:8001",
hostname: "web-platform.test",
origin: "http://web-platform.test:8001",
search: "",
};

function IsWebSocket() {
if (!self.WebSocket) {
Expand Down
7 changes: 4 additions & 3 deletions scripts/chrome.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Chrome/Chromium discovery shared by every headless-browser runner (the
// conformance jco-browser leg and the WPT parity browser legs).
// Node-only.
// Chrome/Chromium discovery for the conformance jco-browser leg, which
// prefers a system Chrome. (The WPT parity browser legs do not use this:
// they always launch Playwright's own pinned build, so the recorded loss
// set measures one engine everywhere.) Node-only.
import { access, readdir } from "node:fs/promises";
import { join } from "node:path";

Expand Down
Loading