| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -337,6 +337,7 @@ changes: | |||
| 337 | 337 | * `only` {boolean} If truthy, and the test context is configured to run | |
| 338 | 338 | `only` tests, then this test will be run. Otherwise, the test is skipped. | |
| 339 | 339 | **Default:** `false`. | |
| 340 | + * `signal` {AbortSignal} Allows aborting an in-progress test | ||
| 340 | 341 | * `skip` {boolean|string} If truthy, the test is skipped. If a string is | |
| 341 | 342 | provided, that string is displayed in the test results as the reason for | |
| 342 | 343 | skipping the test. **Default:** `false`. | |
@@ -385,8 +386,9 @@ test('top level test', async (t) => { | |||
| 385 | 386 | does not have a name. | |
| 386 | 387 | * `options` {Object} Configuration options for the suite. | |
| 387 | 388 | supports the same options as `test([name][, options][, fn])` | |
| 388 | - * `fn` {Function} The function under suite. | ||
| 389 | - a synchronous function declaring all subtests and subsuites. | ||
| 389 | + * `fn` {Function|AsyncFunction} The function under suite | ||
| 390 | + declaring all subtests and subsuites. | ||
| 391 | + The first argument to this function is a [`SuiteContext`][] object. | ||
| 390 | 392 | **Default:** A no-op function. | |
| 391 | 393 | * Returns: `undefined`. | |
| 392 | 394 | ||
@@ -483,6 +485,20 @@ test('top level test', (t) => { | |||
| 483 | 485 | }); | |
| 484 | 486 | ``` | |
| 485 | 487 | ||
| 488 | + ### `context.signal` | ||
| 489 | + | ||
| 490 | + <!-- YAML | ||
| 491 | + added: REPLACEME | ||
| 492 | + --> | ||
| 493 | + | ||
| 494 | + * <AbortSignal> Can be used to abort test subtasks when the test has been aborted. | ||
| 495 | + | ||
| 496 | + ```js | ||
| 497 | + test('top level test', async (t) => { | ||
| 498 | + await fetch('some/uri', { signal: t.signal }); | ||
| 499 | + }); | ||
| 500 | + ``` | ||
| 501 | + | ||
| 486 | 502 | ### `context.skip([message])` | |
| 487 | 503 | ||
| 488 | 504 | <!-- YAML | |
@@ -573,9 +589,28 @@ test('top level test', async (t) => { | |||
| 573 | 589 | }); | |
| 574 | 590 | ``` | |
| 575 | 591 | ||
| 592 | + ## Class: `SuiteContext` | ||
| 593 | + | ||
| 594 | + <!-- YAML | ||
| 595 | + added: REPLACEME | ||
| 596 | + --> | ||
| 597 | + | ||
| 598 | + An instance of `SuiteContext` is passed to each suite function in order to | ||
| 599 | + interact with the test runner. However, the `SuiteContext` constructor is not | ||
| 600 | + exposed as part of the API. | ||
| 601 | + | ||
| 602 | + ### `context.signal` | ||
| 603 | + | ||
| 604 | + <!-- YAML | ||
| 605 | + added: REPLACEME | ||
| 606 | + --> | ||
| 607 | + | ||
| 608 | + * <AbortSignal> Can be used to abort test subtasks when the test has been aborted. | ||
| 609 | + | ||
| 576 | 610 | [TAP]: https://testanything.org/ | |
| 577 | 611 | [`--test-only`]: cli.md#--test-only | |
| 578 | 612 | [`--test`]: cli.md#--test | |
| 613 | + [`SuiteContext`]: #class-suitecontext | ||
| 579 | 614 | [`TestContext`]: #class-testcontext | |
| 580 | 615 | [`test()`]: #testname-options-fn | |
| 581 | 616 | [describe options]: #describename-options-fn | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,20 +3,18 @@ const { | |||
| 3 | 3 | ArrayFrom, | |
| 4 | 4 | ArrayPrototypeFilter, | |
| 5 | 5 | ArrayPrototypeIncludes, | |
| 6 | + ArrayPrototypeJoin, | ||
| 6 | 7 | ArrayPrototypePush, | |
| 7 | 8 | ArrayPrototypeSlice, | |
| 8 | 9 | ArrayPrototypeSort, | |
| 9 | - Promise, | ||
| 10 | - PromiseAll, | ||
| 11 | - SafeArrayIterator, | ||
| 10 | + SafePromiseAll, | ||
| 12 | 11 | SafeSet, | |
| 13 | 12 | } = primordials; | |
| 14 | 13 | const { | |
| 15 | 14 | prepareMainThreadExecution, | |
| 16 | 15 | } = require('internal/bootstrap/pre_execution'); | |
| 17 | 16 | const { spawn } = require('child_process'); | |
| 18 | 17 | const { readdirSync, statSync } = require('fs'); | |
| 19 | - const { finished } = require('internal/streams/end-of-stream'); | ||
| 20 | 18 | const console = require('internal/console/global'); | |
| 21 | 19 | const { | |
| 22 | 20 | codes: { | |
@@ -30,6 +28,7 @@ const { | |||
| 30 | 28 | doesPathMatchFilter, | |
| 31 | 29 | } = require('internal/test_runner/utils'); | |
| 32 | 30 | const { basename, join, resolve } = require('path'); | |
| 31 | + const { once } = require('events'); | ||
| 33 | 32 | const kFilterArgs = ['--test']; | |
| 34 | 33 | ||
| 35 | 34 | prepareMainThreadExecution(false); | |
@@ -102,53 +101,39 @@ function filterExecArgv(arg) { | |||
| 102 | 101 | } | |
| 103 | 102 | ||
| 104 | 103 | function runTestFile(path) { | |
| 105 | - return test(path, () => { | ||
| 106 | - return new Promise((resolve, reject) => { | ||
| 107 | - const args = ArrayPrototypeFilter(process.execArgv, filterExecArgv); | ||
| 108 | - ArrayPrototypePush(args, path); | ||
| 109 | - | ||
| 110 | - const child = spawn(process.execPath, args); | ||
| 111 | - // TODO(cjihrig): Implement a TAP parser to read the child's stdout | ||
| 112 | - // instead of just displaying it all if the child fails. | ||
| 113 | - let stdout = ''; | ||
| 114 | - let stderr = ''; | ||
| 115 | - let err; | ||
| 116 | - | ||
| 117 | - child.on('error', (error) => { | ||
| 118 | - err = error; | ||
| 119 | - }); | ||
| 120 | - | ||
| 121 | - child.stdout.setEncoding('utf8'); | ||
| 122 | - child.stderr.setEncoding('utf8'); | ||
| 123 | - | ||
| 124 | - child.stdout.on('data', (chunk) => { | ||
| 125 | - stdout += chunk; | ||
| 126 | - }); | ||
| 127 | - | ||
| 128 | - child.stderr.on('data', (chunk) => { | ||
| 129 | - stderr += chunk; | ||
| 130 | - }); | ||
| 131 | - | ||
| 132 | - child.once('exit', async (code, signal) => { | ||
| 133 | - if (code !== 0 || signal !== null) { | ||
| 134 | - if (!err) { | ||
| 135 | - await PromiseAll(new SafeArrayIterator([finished(child.stderr), finished(child.stdout)])); | ||
| 136 | - err = new ERR_TEST_FAILURE('test failed', kSubtestsFailed); | ||
| 137 | - err.exitCode = code; | ||
| 138 | - err.signal = signal; | ||
| 139 | - err.stdout = stdout; | ||
| 140 | - err.stderr = stderr; | ||
| 141 | - // The stack will not be useful since the failures came from tests | ||
| 142 | - // in a child process. | ||
| 143 | - err.stack = undefined; | ||
| 144 | - } | ||
| 145 | - | ||
| 146 | - return reject(err); | ||
| 147 | - } | ||
| 148 | - | ||
| 149 | - resolve(); | ||
| 150 | - }); | ||
| 104 | + return test(path, async (t) => { | ||
| 105 | + const args = ArrayPrototypeFilter(process.execArgv, filterExecArgv); | ||
| 106 | + ArrayPrototypePush(args, path); | ||
| 107 | + | ||
| 108 | + const child = spawn(process.execPath, args, { signal: t.signal, encoding: 'utf8' }); | ||
| 109 | + // TODO(cjihrig): Implement a TAP parser to read the child's stdout | ||
| 110 | + // instead of just displaying it all if the child fails. | ||
| 111 | + let err; | ||
| 112 | + | ||
| 113 | + child.on('error', (error) => { | ||
| 114 | + err = error; | ||
| 151 | 115 | }); | |
| 116 | + | ||
| 117 | + const { 0: { code, signal }, 1: stdout, 2: stderr } = await SafePromiseAll([ | ||
| 118 | + once(child, 'exit', { signal: t.signal }), | ||
| 119 | + child.stdout.toArray({ signal: t.signal }), | ||
| 120 | + child.stderr.toArray({ signal: t.signal }), | ||
| 121 | + ]); | ||
| 122 | + | ||
| 123 | + if (code !== 0 || signal !== null) { | ||
| 124 | + if (!err) { | ||
| 125 | + err = new ERR_TEST_FAILURE('test failed', kSubtestsFailed); | ||
| 126 | + err.exitCode = code; | ||
| 127 | + err.signal = signal; | ||
| 128 | + err.stdout = ArrayPrototypeJoin(stdout, ''); | ||
| 129 | + err.stderr = ArrayPrototypeJoin(stderr, ''); | ||
| 130 | + // The stack will not be useful since the failures came from tests | ||
| 131 | + // in a child process. | ||
| 132 | + err.stack = undefined; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + throw err; | ||
| 136 | + } | ||
| 152 | 137 | }); | |
| 153 | 138 | } | |
| 154 | 139 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments