| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -236,6 +236,7 @@ class StatusRule { | |||
| 236 | 236 | this.requires = value.requires || []; | |
| 237 | 237 | this.fail = value.fail; | |
| 238 | 238 | this.skip = value.skip; | |
| 239 | + this.skipTests = value.skipTests; | ||
| 239 | 240 | if (pattern) { | |
| 240 | 241 | this.pattern = this.transformPattern(pattern); | |
| 241 | 242 | } | |
@@ -312,6 +313,7 @@ class WPTTestSpec { | |||
| 312 | 313 | this.failedTests = []; | |
| 313 | 314 | this.flakyTests = []; | |
| 314 | 315 | this.skipReasons = []; | |
| 316 | + this.skippedTests = []; | ||
| 315 | 317 | for (const item of rules) { | |
| 316 | 318 | if (item.requires.length) { | |
| 317 | 319 | for (const req of item.requires) { | |
@@ -328,6 +330,9 @@ class WPTTestSpec { | |||
| 328 | 330 | if (item.skip) { | |
| 329 | 331 | this.skipReasons.push(item.skip); | |
| 330 | 332 | } | |
| 333 | + if (Array.isArray(item.skipTests)) { | ||
| 334 | + this.skippedTests.push(...item.skipTests); | ||
| 335 | + } | ||
| 331 | 336 | } | |
| 332 | 337 | ||
| 333 | 338 | this.failedTests = [...new Set(this.failedTests)]; | |
@@ -347,6 +352,22 @@ class WPTTestSpec { | |||
| 347 | 352 | return meta.variant?.map((variant) => new WPTTestSpec(mod, filename, rules, variant)) || [spec]; | |
| 348 | 353 | } | |
| 349 | 354 | ||
| 355 | + /** | ||
| 356 | + * Check if a subtest should be skipped by name. | ||
| 357 | + * @param {string} name | ||
| 358 | + * @returns {boolean} | ||
| 359 | + */ | ||
| 360 | + isSkippedTest(name) { | ||
| 361 | + for (const matcher of this.skippedTests) { | ||
| 362 | + if (typeof matcher === 'string') { | ||
| 363 | + if (name === matcher) return true; | ||
| 364 | + } else if (matcher.test(name)) { | ||
| 365 | + return true; | ||
| 366 | + } | ||
| 367 | + } | ||
| 368 | + return false; | ||
| 369 | + } | ||
| 370 | + | ||
| 350 | 371 | getRelativePath() { | |
| 351 | 372 | return path.join(this.module, this.filename); | |
| 352 | 373 | } | |
@@ -684,6 +705,7 @@ class WPTRunner { | |||
| 684 | 705 | }, | |
| 685 | 706 | scriptsToRun, | |
| 686 | 707 | needsGc: !!meta.script?.find((script) => script === '/common/gc.js'), | |
| 708 | + skippedTests: spec.skippedTests, | ||
| 687 | 709 | }, | |
| 688 | 710 | }); | |
| 689 | 711 | this.inProgress.add(spec); | |
@@ -694,6 +716,8 @@ class WPTRunner { | |||
| 694 | 716 | switch (message.type) { | |
| 695 | 717 | case 'result': | |
| 696 | 718 | return this.resultCallback(spec, message.result, reportResult); | |
| 719 | + case 'skip': | ||
| 720 | + return this.skipTest(spec, { name: message.name }, reportResult); | ||
| 697 | 721 | case 'completion': | |
| 698 | 722 | return this.completionCallback(spec, message.status, reportResult); | |
| 699 | 723 | default: | |
@@ -751,6 +775,7 @@ class WPTRunner { | |||
| 751 | 775 | const failures = []; | |
| 752 | 776 | let expectedFailures = 0; | |
| 753 | 777 | let skipped = 0; | |
| 778 | + let skippedTests = 0; | ||
| 754 | 779 | for (const [key, item] of Object.entries(this.results)) { | |
| 755 | 780 | if (item.fail?.unexpected) { | |
| 756 | 781 | failures.push(key); | |
@@ -761,6 +786,9 @@ class WPTRunner { | |||
| 761 | 786 | if (item.skip) { | |
| 762 | 787 | skipped++; | |
| 763 | 788 | } | |
| 789 | + if (item.skipTests) { | ||
| 790 | + skippedTests += item.skipTests.length; | ||
| 791 | + } | ||
| 764 | 792 | } | |
| 765 | 793 | ||
| 766 | 794 | const unexpectedPasses = []; | |
@@ -801,7 +829,8 @@ class WPTRunner { | |||
| 801 | 829 | console.log(`Ran ${ran}/${total} tests, ${skipped} skipped,`, | |
| 802 | 830 | `${passed} passed, ${expectedFailures} expected failures,`, | |
| 803 | 831 | `${failures.length} unexpected failures,`, | |
| 804 | - `${unexpectedPasses.length} unexpected passes`); | ||
| 832 | + `${unexpectedPasses.length} unexpected passes` + | ||
| 833 | + (skippedTests ? `, ${skippedTests} subtests skipped` : '')); | ||
| 805 | 834 | if (failures.length > 0) { | |
| 806 | 835 | const file = path.join('test', 'wpt', 'status', `${this.path}.json`); | |
| 807 | 836 | throw new Error( | |
@@ -890,8 +919,16 @@ class WPTRunner { | |||
| 890 | 919 | let result = this.results[spec.filename]; | |
| 891 | 920 | result ||= this.results[spec.filename] = {}; | |
| 892 | 921 | if (item.status === kSkip) { | |
| 893 | - // { filename: { skip: 'reason' } } | ||
| 894 | - result[kSkip] = item.reason; | ||
| 922 | + if (item.name) { | ||
| 923 | + // Subtest-level skip: { filename: { skipTests: [ ... ] } } | ||
| 924 | + result.skipTests ||= []; | ||
| 925 | + if (!result.skipTests.includes(item.name)) { | ||
| 926 | + result.skipTests.push(item.name); | ||
| 927 | + } | ||
| 928 | + } else { | ||
| 929 | + // File-level skip: { filename: { skip: 'reason' } } | ||
| 930 | + result[kSkip] = item.reason; | ||
| 931 | + } | ||
| 895 | 932 | } else { | |
| 896 | 933 | // { filename: { fail: { expected: [ ... ], | |
| 897 | 934 | // unexpected: [ ... ] } }} | |
@@ -910,6 +947,15 @@ class WPTRunner { | |||
| 910 | 947 | reportResult?.addSubtest(test.name, 'PASS'); | |
| 911 | 948 | } | |
| 912 | 949 | ||
| 950 | + skipTest(spec, test, reportResult) { | ||
| 951 | + console.log(`[SKIP] ${test.name}`); | ||
| 952 | + reportResult?.addSubtest(test.name, 'NOTRUN'); | ||
| 953 | + this.addTestResult(spec, { | ||
| 954 | + name: test.name, | ||
| 955 | + status: kSkip, | ||
| 956 | + }); | ||
| 957 | + } | ||
| 958 | + | ||
| 913 | 959 | fail(spec, test, status, reportResult) { | |
| 914 | 960 | const expected = spec.failedTests.includes(test.name); | |
| 915 | 961 | if (expected) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -42,6 +42,32 @@ runInThisContext(workerData.harness.code, { | |||
| 42 | 42 | importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER, | |
| 43 | 43 | }); | |
| 44 | 44 | ||
| 45 | + // If there are skip patterns, wrap test functions to prevent execution of | ||
| 46 | + // matching tests. This must happen after testharness.js is loaded but before | ||
| 47 | + // the test scripts run. | ||
| 48 | + if (workerData.skippedTests?.length) { | ||
| 49 | + function isSkipped(name) { | ||
| 50 | + for (const matcher of workerData.skippedTests) { | ||
| 51 | + if (typeof matcher === 'string') { | ||
| 52 | + if (name === matcher) return true; | ||
| 53 | + } else if (matcher.test(name)) { | ||
| 54 | + return true; | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | + return false; | ||
| 58 | + } | ||
| 59 | + for (const fn of ['test', 'async_test', 'promise_test']) { | ||
| 60 | + const original = globalThis[fn]; | ||
| 61 | + globalThis[fn] = function(func, name, ...rest) { | ||
| 62 | + if (typeof name === 'string' && isSkipped(name)) { | ||
| 63 | + parentPort.postMessage({ type: 'skip', name }); | ||
| 64 | + return; | ||
| 65 | + } | ||
| 66 | + return original.call(this, func, name, ...rest); | ||
| 67 | + }; | ||
| 68 | + } | ||
| 69 | + } | ||
| 70 | + | ||
| 45 | 71 | // eslint-disable-next-line no-undef | |
| 46 | 72 | add_result_callback((result) => { | |
| 47 | 73 | parentPort.postMessage({ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -155,7 +155,7 @@ expected failures. | |||
| 155 | 155 | // Optional: If the requirement is not met, this test will be skipped | |
| 156 | 156 | "requires": ["small-icu"], // supports: "small-icu", "full-icu", "crypto" | |
| 157 | 157 | ||
| 158 | - // Optional: the test will be skipped with the reason printed | ||
| 158 | + // Optional: the entire file will be skipped with the reason printed | ||
| 159 | 159 | "skip": "explain why we cannot run a test that's supposed to pass", | |
| 160 | 160 | ||
| 161 | 161 | // Optional: failing tests | |
@@ -173,6 +173,42 @@ expected failures. | |||
| 173 | 173 | } | |
| 174 | 174 | ``` | |
| 175 | 175 | ||
| 176 | + ### Skipping individual subtests | ||
| 177 | + | ||
| 178 | + To 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: | ||
| 192 | + | ||
| 193 | + ```js | ||
| 194 | + module.exports = { | ||
| 195 | + 'something.scope.js': { | ||
| 196 | + 'skipTests': [ | ||
| 197 | + 'exact test name to skip', | ||
| 198 | + /regexp pattern to match/, | ||
| 199 | + ], | ||
| 200 | + }, | ||
| 201 | + }; | ||
| 202 | + ``` | ||
| 203 | + | ||
| 204 | + Skipped subtests are reported as `[SKIP]` in the output, recorded as `NOTRUN` | ||
| 205 | + in the WPT report, and counted separately in the summary line. | ||
| 206 | + | ||
| 207 | + This 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. | ||
| 211 | + | ||
| 176 | 212 | A test may have to be skipped because it depends on another irrelevant | |
| 177 | 213 | Web API, or certain harness has not been ported in our test runner yet. | |
| 178 | 214 | In that case it needs to be marked with `skip` instead of `fail`. | |
| Back | FazBrowse Home | New Git URL |
0 commit comments