node/test/wpt/README.md
Filip Skokan 4563cb31d6
doc: update WPT test runner README.md
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62680
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
2026-04-12 19:49:17 +00:00

251 lines
8.2 KiB
Markdown

# Web Platform Tests
This directory contains test runners that execute upstream
[Web Platform Tests][] against Node.js using the WPT harness.
The actual test files live in `test/fixtures/wpt`, a subset of the
upstream WPT repository containing only the modules relevant to Node.js.
Each module is updated independently using [git node wpt][], so
different modules may be pinned to different upstream commits.
Each module has a status file in the [`status` folder](./status) that
declares build requirements, expected failures, and tests to skip.
See [`test/fixtures/wpt/README.md`][] for the pinned WPT commit
hashes for each module.
<a id="add-tests"></a>
## How to add tests for a new module
### 1. Create a status file
For example, to add the URL tests, add a `test/wpt/status/url.cjs` file.
In the beginning, it's fine to leave an empty object `module.exports = {}`
in the file if it's not yet clear how compliant the implementation is,
the requirements and expected failures can be figured out in a later step
when the tests are run for the first time.
See [Format of a status file](#status-format) for details.
### 2. Pull the WPT files
Use the [git node wpt][] command to download the WPT files into
`test/fixtures/wpt`. For example, to add URL tests:
```bash
cd /path/to/node/project
git node wpt url
```
### 3. Create the test runner
For example, for the URL tests, add a file `test/wpt/test-url.js`:
```js
'use strict';
const { WPTRunner } = require('../common/wpt');
const runner = new WPTRunner('url');
runner.pretendGlobalThisAs('Window');
runner.runJsTests();
```
The runner loads the tests from `test/fixtures/wpt/url`, applies the
status rules from `test/wpt/status/url.cjs`, and runs them using
worker threads.
#### `new WPTRunner(path[, options])`
* `path` {string} Relative path of the WPT module
(e.g. `'url'`, `'html/webappapis/timers'`).
* `options` {Object}
* `concurrency` {number} Number of tests to run in parallel.
Defaults to `os.availableParallelism() - 1`. Set to `1` for tests
that require sequential execution (e.g. web-locks, webstorage).
#### `runner.setFlags(flags)`
* `flags` {string\[]} Node.js CLI flags passed to each worker thread
(e.g. `['--expose-internals']`).
#### `runner.setInitScript(script)`
* `script` {string} JavaScript code executed in the worker before
the tests run. Useful for setting up globals needed by the tests.
#### `runner.setScriptModifier(modifier)`
* `modifier` {Function} A callback `(meta) => void` invoked for each
script before it is run in the worker. `meta` is an object with
`code` {string} and `filename` {string} properties that can be
mutated.
#### `runner.pretendGlobalThisAs(name)`
* `name` {string} Currently only `'Window'` is supported. Sets up
`globalThis.Window` so that WPT tests checking the global scope
type work correctly.
#### `runner.runJsTests()`
Starts running the tests. Must be called last, after all configuration.
### 4. Run the tests
Run the test using `tools/test.py` and see if there are any failures.
For example, to run all the URL tests under `test/fixtures/wpt/url`:
```bash
tools/test.py wpt/test-url
```
To run a specific test in WPT, for example, `url/url-searchparams.any.js`,
pass the file name as argument to the corresponding test runner:
```bash
node test/wpt/test-url.js url-searchparams.any.js
```
If there are any failures, update the corresponding status file
(in this case, `test/wpt/status/url.cjs`) to make the test pass.
For example, to mark `url/url-searchparams.any.js` as expected to fail,
add this to `test/wpt/status/url.cjs`:
```js
module.exports = {
'url-searchparams.any.js': {
fail: {
expected: [
'test name in the WPT test case, e.g. second argument passed to test()',
],
},
},
};
```
See [Format of a status file](#status-format) for details.
### 5. Commit the changes and submit a Pull Request
See [the contributing guide](../../CONTRIBUTING.md).
## How to update tests for a module
The tests can be updated in a way similar to how they are added.
Run Step 2 and Step 4 of [adding tests for a new module](#add-tests).
The [git node wpt][] command maintains the status of the local
WPT subset. If no files are updated after running it for a module,
the local subset is up to date and there is no need to create a PR.
When files are updated, run the tests and update the status file to
account for any new failures or passes before submitting.
## Daily WPT report
A [GitHub Actions workflow][] runs every night and uploads results to
[wpt.fyi][]. It tests all active Node.js release lines and the latest
nightly build against the WPT `epochs/daily` branch, which is a daily
snapshot of the upstream WPT repository.
Unlike the pinned fixtures used in CI, this workflow replaces
`test/fixtures/wpt` with the full `epochs/daily` checkout so that
results reflect the latest upstream tests. Results can be viewed on
the [wpt.fyi dashboard][].
<a id="status-format"></a>
## Format of a status file
The status file can be either a `.json` file or a `.cjs` module that exports
the same object. Using CJS allows for conditional logic and regular
expressions, which JSON does not support.
```js
module.exports = {
'something.scope.js': { // the file name
// Optional: If the requirement is not met, this test will be skipped.
// Supported values:
// 'small-icu' - requires at least small-icu intl support
// 'full-icu' - requires full-icu intl support
// 'crypto' - requires crypto (OpenSSL) support
// 'inspector' - requires the inspector to be available
requires: ['small-icu'],
// Optional: the entire file will be skipped with the reason printed.
skip: 'explain why we cannot run a test that is supposed to pass',
// Optional: failing tests.
fail: {
// Tests that are expected to fail consistently.
expected: [
'test name in the WPT test case, e.g. second argument passed to test()',
'another test name',
],
// Tests that fail intermittently. These are treated as expected
// failures but are not flagged as unexpected passes when they
// succeed.
flaky: [
'flaky test name',
],
},
},
};
```
A test should be marked with `skip` when it cannot be run at all, for
example, because it depends on a browser-only Web API or a harness feature
that has not been ported to the Node.js runner. Use `fail` instead when
the test can run but produces incorrect results due to an implementation
bug or missing feature.
### Skipping individual subtests
To skip specific subtests within a file (rather than skipping the entire file),
use `skipTests` with an array of exact test names or regular expressions:
```js
module.exports = {
'something.scope.js': {
skipTests: [
'exact test name to skip',
/regexp pattern to match/,
],
},
};
```
Skipped subtests are reported as `[SKIP]` in the output, recorded as `NOTRUN`
in the WPT report, and counted separately in the summary line.
This is useful for skipping a particular subtest that crashes the runner,
which would otherwise prevent the rest of the file from being run. Using CJS
status files also enables conditionally skipping slow or resource-heavy
subtests in CI on specific architectures.
### Wildcard patterns in file names
File name keys can include a `*` character to match multiple test files
with a single entry. For example, to skip all `.window.js` tests:
```js
module.exports = {
'*.window.js': {
skip: 'window tests are not relevant for Node.js',
},
};
```
The `*` is converted to a `.*` regular expression, so `"subdir/*.any.js"`
would match all `.any.js` files under the `subdir` directory. A test file
can match multiple rules (both an exact match and one or more wildcard
patterns); all matched rules are merged.
[GitHub Actions workflow]: ../../.github/workflows/daily-wpt-fyi.yml
[Web Platform Tests]: https://github.com/web-platform-tests/wpt
[`test/fixtures/wpt/README.md`]: ../fixtures/wpt/README.md
[git node wpt]: https://github.com/nodejs/node-core-utils/blob/HEAD/docs/git-node.md#git-node-wpt
[wpt.fyi]: https://wpt.fyi
[wpt.fyi dashboard]: https://wpt.fyi/results/?label=master&label=experimental&product=node.js&product=chrome&product=firefox&product=safari&product=ladybird&product=servo&q=node.js%3A%21missing