doc: update WPT test runner README.md · nodejs/node@8126d1c
11# Web Platform Tests
223-The tests here are drivers for running the [Web Platform Tests][].
4-5-See [`test/fixtures/wpt/README.md`][] for a hash of the last
6-updated WPT commit for each module being covered here.
7-8-See the json files in [the `status` folder](./status) for prerequisites,
9-expected failures, and support status for specific tests in each module.
10-11-Currently there are still some Web Platform Tests titled `test-whatwg-*`
12-under `test/parallel` that have not been migrated to be run with the
13-WPT harness and have automatic updates. There are also a few
14-`test-whatwg-*-custom-*` tests that may need to be upstreamed.
15-This folder covers the tests that have been migrated.
3+This directory contains test runners that execute upstream
4+[Web Platform Tests][] against Node.js using the WPT harness.
5+The actual test files live in `test/fixtures/wpt`, a subset of the
6+upstream WPT repository containing only the modules relevant to Node.js.
7+Each module is updated independently using [git node wpt][], so
8+different modules may be pinned to different upstream commits.
9+10+Each module has a status file in the [`status` folder](./status) that
11+declares build requirements, expected failures, and tests to skip.
12+See [`test/fixtures/wpt/README.md`][] for the pinned WPT commit
13+hashes for each module.
16141715<a id="add-tests"></a>
18161917## How to add tests for a new module
20182119### 1. Create a status file
222023-For example, to add the URL tests, add a `test/wpt/status/url.json` file.
21+For example, to add the URL tests, add a `test/wpt/status/url.cjs` file.
242225-In the beginning, it's fine to leave an empty object `{}` in the file if
26-it's not yet clear how compliant the implementation is,
23+In the beginning, it's fine to leave an empty object `module.exports = {}`
24+in the file if it's not yet clear how compliant the implementation is,
2725the requirements and expected failures can be figured out in a later step
2826when the tests are run for the first time.
2927@@ -39,7 +37,7 @@ cd /path/to/node/project
3937git node wpt url
4038```
413942-### 3. Create the test driver
40+### 3. Create the test runner
43414442For example, for the URL tests, add a file `test/wpt/test-url.js`:
4543@@ -50,21 +48,49 @@ const { WPTRunner } = require('../common/wpt');
50485149const runner = new WPTRunner('url');
525053-// Set Node.js flags required for the tests.
54-runner.setFlags(['--expose-internals']);
55-56-// Set a script that will be executed in the worker before running the tests.
57-runner.setInitScript(`
58- const { internalBinding } = require('internal/test/binding');
59- const { DOMException } = internalBinding('messaging');
60- global.DOMException = DOMException;
61-`);
62-51+runner.pretendGlobalThisAs('Window');
6352runner.runJsTests();
6453```
655466-This driver is capable of running the tests located in `test/fixtures/wpt/url`
67-with the WPT harness while taking the status file into account.
55+The runner loads the tests from `test/fixtures/wpt/url`, applies the
56+status rules from `test/wpt/status/url.cjs`, and runs them using
57+worker threads.
58+59+#### `new WPTRunner(path[, options])`
60+61+* `path` {string} Relative path of the WPT module
62+ (e.g. `'url'`, `'html/webappapis/timers'`).
63+* `options` {Object}
64+* `concurrency` {number} Number of tests to run in parallel.
65+ Defaults to `os.availableParallelism() - 1`. Set to `1` for tests
66+ that require sequential execution (e.g. web-locks, webstorage).
67+68+#### `runner.setFlags(flags)`
69+70+* `flags` {string\[]} Node.js CLI flags passed to each worker thread
71+ (e.g. `['--expose-internals']`).
72+73+#### `runner.setInitScript(script)`
74+75+* `script` {string} JavaScript code executed in the worker before
76+ the tests run. Useful for setting up globals needed by the tests.
77+78+#### `runner.setScriptModifier(modifier)`
79+80+* `modifier` {Function} A callback `(meta) => void` invoked for each
81+ script before it is run in the worker. `meta` is an object with
82+`code` {string} and `filename` {string} properties that can be
83+ mutated.
84+85+#### `runner.pretendGlobalThisAs(name)`
86+87+* `name` {string} Currently only `'Window'` is supported. Sets up
88+`globalThis.Window` so that WPT tests checking the global scope
89+ type work correctly.
90+91+#### `runner.runJsTests()`
92+93+Starts running the tests. Must be called last, after all configuration.
68946995### 4. Run the tests
7096@@ -76,26 +102,28 @@ tools/test.py wpt/test-url
76102```
7710378104To run a specific test in WPT, for example, `url/url-searchparams.any.js`,
79-pass the file name as argument to the corresponding test driver:
105+pass the file name as argument to the corresponding test runner:
8010681107```bash
82108node test/wpt/test-url.js url-searchparams.any.js
83109```
8411085111If there are any failures, update the corresponding status file
86-(in this case, `test/wpt/status/url.json`) to make the test pass.
112+(in this case, `test/wpt/status/url.cjs`) to make the test pass.
8711388114For example, to mark `url/url-searchparams.any.js` as expected to fail,
89-add this to `test/wpt/status/url.json`:
90-91-```json
92-"url-searchparams.any.js": {
93-"fail": {
94-"expected": [
95-"test name in the WPT test case, e.g. second argument passed to test()"
96- ]
97- }
98- }
115+add this to `test/wpt/status/url.cjs`:
116+117+```js
118+module.exports = {
119+'url-searchparams.any.js': {
120+ fail: {
121+ expected: [
122+'test name in the WPT test case, e.g. second argument passed to test()',
123+ ],
124+ },
125+ },
126+};
99127```
100128101129See [Format of a status file](#status-format) for details.
@@ -110,90 +138,78 @@ The tests can be updated in a way similar to how they are added.
110138Run Step 2 and Step 4 of [adding tests for a new module](#add-tests).
111139112140The [git node wpt][] command maintains the status of the local
113-WPT subset, if no files are updated after running it for a module,
114-the local subset is up to date and there is no need to update them
115-until they are changed in the upstream.
141+WPT subset. If no files are updated after running it for a module,
142+the local subset is up to date and there is no need to create a PR.
143+When files are updated, run the tests and update the status file to
144+account for any new failures or passes before submitting.
116145117-## How it works
146+## Daily WPT report
118147119-Note: currently this test suite only supports `.js` tests. There is
120-ongoing work in the upstream to properly split out the tests into files
121-that can be run in a shell environment like Node.js.
148+A [GitHub Actions workflow][] runs every night and uploads results to
149+[wpt.fyi][]. It tests all active Node.js release lines and the latest
150+nightly build against the WPT `epochs/daily` branch, which is a daily
151+snapshot of the upstream WPT repository.
122152123-### Getting the original test files and harness from WPT
124-125-The original files and harness from WPT are downloaded and stored in
126-`test/fixtures/wpt`.
127-128-The [git node wpt][] command automate this process while maintaining a map
129-containing the hash of the last updated commit for each module in
130-`test/fixtures/wpt/versions.json` and [`test/fixtures/wpt/README.md`][].
131-It also maintains the LICENSE file in `test/fixtures/wpt`.
132-133-### Loading and running the tests
134-135-Given a module, the `WPTRunner` class in [`test/common/wpt`](../common/wpt.js)
136-loads:
137-138-* `.js` test files (for example, `test/common/wpt/url/*.js` for `url`)
139-* Status file (for example, `test/wpt/status/url.json` for `url`)
140-* The WPT harness
141-142-Then, for each test, it creates a worker thread with the globals and mocks,
143-sets up the harness result hooks, loads the metadata in the test (including
144-loading extra resources), and runs all the tests in that worker thread,
145-skipping tests that cannot be run because of lack of dependency or
146-expected failures.
153+Unlike the pinned fixtures used in CI, this workflow replaces
154+`test/fixtures/wpt` with the full `epochs/daily` checkout so that
155+results reflect the latest upstream tests. Results can be viewed on
156+the [wpt.fyi dashboard][].
147157148158<a id="status-format"></a>
149159150160## Format of a status file
151161152-```json
153-{
154-"something.scope.js": { // the file name
155-// Optional: If the requirement is not met, this test will be skipped
156-"requires": ["small-icu"], // supports: "small-icu", "full-icu", "crypto"
157-158-// Optional: the entire file will be skipped with the reason printed
159-"skip": "explain why we cannot run a test that's supposed to pass",
160-161-// Optional: failing tests
162-"fail": {
163-"note": "You may leave an optional arbitrary note e.g. with TODOs",
164-"expected": [
165-"test name in the WPT test case, e.g. second argument passed to test()",
166-"another test name"
162+The status file can be either a `.json` file or a `.cjs` module that exports
163+the same object. Using CJS allows for conditional logic and regular
164+expressions, which JSON does not support.
165+166+```js
167+module.exports = {
168+'something.scope.js': { // the file name
169+// Optional: If the requirement is not met, this test will be skipped.
170+// Supported values:
171+// 'small-icu' - requires at least small-icu intl support
172+// 'full-icu' - requires full-icu intl support
173+// 'crypto' - requires crypto (OpenSSL) support
174+// 'inspector' - requires the inspector to be available
175+ requires: ['small-icu'],
176+177+// Optional: the entire file will be skipped with the reason printed.
178+ skip: 'explain why we cannot run a test that is supposed to pass',
179+180+// Optional: failing tests.
181+ fail: {
182+// Tests that are expected to fail consistently.
183+ expected: [
184+'test name in the WPT test case, e.g. second argument passed to test()',
185+'another test name',
167186 ],
168-"flaky": [
169-"flaky test name"
170- ]
171- }
172- }
173-}
187+// Tests that fail intermittently. These are treated as expected
188+// failures but are not flagged as unexpected passes when they
189+// succeed.
190+ flaky: [
191+'flaky test name',
192+ ],
193+ },
194+ },
195+};
174196```
175197198+A test should be marked with `skip` when it cannot be run at all, for
199+example, because it depends on a browser-only Web API or a harness feature
200+that has not been ported to the Node.js runner. Use `fail` instead when
201+the test can run but produces incorrect results due to an implementation
202+bug or missing feature.
203+176204### Skipping individual subtests
177205178206To skip specific subtests within a file (rather than skipping the entire file),
179-use `skipTests` with an array of exact test names:
180-181-```json
182-{
183-"something.scope.js": {
184-"skipTests": [
185-"exact test name to skip"
186- ]
187- }
188-}
189-```
190-191-When the status file is a CJS module, regular expressions can also be used:
207+use `skipTests` with an array of exact test names or regular expressions:
192208193209```js
194210module.exports = {
195211'something.scope.js': {
196-'skipTests': [
212+ skipTests: [
197213'exact test name to skip',
198214 /regexp pattern to match/,
199215 ],
@@ -205,18 +221,31 @@ Skipped subtests are reported as `[SKIP]` in the output, recorded as `NOTRUN`
205221in the WPT report, and counted separately in the summary line.
206222207223This is useful for skipping a particular subtest that crashes the runner,
208-which would otherwise prevent the rest of the file from being run. When using
209-CJS status files, this also enables conditionally skipping slow or
210-resource-heavy subtests in CI on specific architectures.
224+which would otherwise prevent the rest of the file from being run. Using CJS
225+status files also enables conditionally skipping slow or resource-heavy
226+subtests in CI on specific architectures.
227+228+### Wildcard patterns in file names
229+230+File name keys can include a `*` character to match multiple test files
231+with a single entry. For example, to skip all `.window.js` tests:
211232212-A test may have to be skipped because it depends on another irrelevant
213-Web API, or certain harness has not been ported in our test runner yet.
214-In that case it needs to be marked with `skip` instead of `fail`.
233+```js
234+module.exports = {
235+'*.window.js': {
236+ skip: 'window tests are not relevant for Node.js',
237+ },
238+};
239+```
215240216-The status file may optionally also be a CJS module that exports the object.
217-This allows for more complex logic to be used to determine the expected status
218-of a test.
241+The `*` is converted to a `.*` regular expression, so `"subdir/*.any.js"`
242+would match all `.any.js` files under the `subdir` directory. A test file
243+can match multiple rules (both an exact match and one or more wildcard
244+patterns); all matched rules are merged.
219245246+[GitHub Actions workflow]: ../../.github/workflows/daily-wpt-fyi.yml
220247[Web Platform Tests]: https://github.com/web-platform-tests/wpt
221248[`test/fixtures/wpt/README.md`]: ../fixtures/wpt/README.md
222249[git node wpt]: https://github.com/nodejs/node-core-utils/blob/HEAD/docs/git-node.md#git-node-wpt
250+[wpt.fyi]: https://wpt.fyi
251+[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