--- enabled: true touches: [oracle/suites/server.mjs, oracle/suites/run.mjs, oracle/suites/wpt.mjs, oracle/suites/testdriver.mjs, oracle/suites/testdriver.test.mjs, docs/conformance-oracles.md] depends-on: [] --- # `testdriver-playwright-input`: run WPT's `testdriver.js` tests through Playwright The conformance-suite runner skips every test that needs input it cannot give. `oracle/suites/wpt.mjs` `discover()` tags a page that loads `/resources/testdriver.js` with `skip: 'testdriver'` and a `-manual` page with `skip: 'manual'`, and `oracle/suites/run.mjs` writes those as `SKIP` records without running them. In WPT `html/canvas` that is 23 tests: 16 manual and 7 `testdriver.js` (`docs/conformance-oracles.md` → "What could not run, and why", and the "WPT html/canvas" section's own count). WPT's `testdriver.js` does not act itself. It calls `window.test_driver_internal`, which each runner fills from a vendor script (`/resources/testdriver-vendor.js`) wired to its own automation. This spec supplies that wiring from Playwright's input APIs, so those tests run in all three engines like any other. No generated function is built here, so the provisional rule for lifting hand-written logic into a generated function (filed in the roster as an open decision) does not apply. **Scope.** In: a `testdriver-vendor.js` served by `oracle/suites/server.mjs` in place of WPT's empty one, the way it already replaces `/resources/testharnessreport.js` (`TESTHARNESSREPORT`); it forwards each `test_driver_internal` call to a binding the runner exposes on every page (`page.exposeBinding`, set where `run.mjs` creates a page), and `oracle/suites/testdriver.mjs` carries each call out. Cover what the canvas tests call: `click` (at the in-view centre point `testdriver.js` computes), `send_keys`, `action_sequence` for pointer and key sources (`page.mouse`, `page.keyboard`), `bless` (it goes through `click`), and `set_permission` where Playwright's `context.grantPermissions` has the permission for that engine. An unimplemented call rejects with a message naming it, so the test fails visibly instead of hanging until timeout. `discover()` stops skipping `testdriver` tests. Each of the 16 `-manual` canvas tests is read and classified in `docs/conformance-oracles.md`. A test that only waits on input `testdriver.js` can give (a click, a key) is either run through the same bridge or listed as runnable with one sentence saying what it waits on. A test that asks a person to judge output stays skipped, with its reason. Out: cross-frame and cross-origin contexts (`test_driver.set_test_context` from a child frame), window management, virtual authenticators, device posture, anything a Playwright engine has no API for (recorded per call, per engine); the 4 `webaudio` testdriver tests, which the roster keeps with the audio work (`specs/audio-null-sink.md`); any change to `oracle/oracle.mjs` or the geometry dump. **Tests.** `oracle/suites/testdriver.test.mjs`, run with `node --test`: start `startServer()` over a temporary directory holding two small pages, one using `test_driver.click` and one using `test_driver.send_keys`, drive each in Chromium through the same binding `run.mjs` installs, and check that each test's `__wpt_done` result passes. Add a third page that calls a method the bridge does not implement and check that it fails quickly with that method's name in the message. Keep it to one engine so it runs anywhere Chromium is installed. The full run is the measurement below. **Measurement.** On a build lane, with the checkout from `node oracle/suites/fetch.mjs wpt`, run `node oracle/suites/run.mjs canvas --out=oracle/suites/results/canvas.jsonl` (or only the recovered tests with `--ids=FILE`, layered over the last full run) and `summarize.mjs`. Update `docs/conformance-oracles.md`: the "WPT html/canvas" counts (tests run, not run), the usable share, the `manual` row of the area table, and "What could not run, and why", which should end up listing only what is still skipped and why. Record per recovered test whether all three engines, two, one or none pass. A recovered test the engines split on is still a result. **Shared files.** None of these files is named by another enabled or queued spec. The disabled `specs/audio-null-sink.md` names `oracle/**` and `docs/conformance-oracles.md`, so the two must not run at once. **Gates.** `cargo test --workspace` passes (nothing in Rust changes). `node --test oracle/suites/testdriver.test.mjs` passes. `fragment_check --random` stays 227/227 and `bench/seam-floor.sh`'s floors hold; neither reads these files, so a change there means something outside this spec's `touches` moved.