| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 5a776d4 commit 37e9092
10 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -316,6 +316,35 @@ Otherwise, the test is considered to be a failure. Test files must be | |||
| 316 | 316 | executable by Node.js, but are not required to use the `node:test` module | |
| 317 | 317 | internally. | |
| 318 | 318 | ||
| 319 | + ## `run([options])` | ||
| 320 | + | ||
| 321 | + <!-- YAML | ||
| 322 | + added: REPLACEME | ||
| 323 | + --> | ||
| 324 | + | ||
| 325 | + * `options` {Object} Configuration options for running tests. The following | ||
| 326 | + properties are supported: | ||
| 327 | + * `concurrency` {number|boolean} If a number is provided, | ||
| 328 | + then that many files would run in parallel. | ||
| 329 | + If truthy, it would run (number of cpu cores - 1) | ||
| 330 | + files in parallel. | ||
| 331 | + If falsy, it would only run one file at a time. | ||
| 332 | + If unspecified, subtests inherit this value from their parent. | ||
| 333 | + **Default:** `true`. | ||
| 334 | + * `files`: {Array} An array containing the list of files to run. | ||
| 335 | + **Default** matching files from [test runner execution model][]. | ||
| 336 | + * `signal` {AbortSignal} Allows aborting an in-progress test execution. | ||
| 337 | + * `timeout` {number} A number of milliseconds the test execution will | ||
| 338 | + fail after. | ||
| 339 | + If unspecified, subtests inherit this value from their parent. | ||
| 340 | + **Default:** `Infinity`. | ||
| 341 | + * Returns: {TapStream} | ||
| 342 | + | ||
| 343 | + ```js | ||
| 344 | + run({ files: [path.resolve('./tests/test.js')] }) | ||
| 345 | + .pipe(process.stdout); | ||
| 346 | + ``` | ||
| 347 | + | ||
| 319 | 348 | ## `test([name][, options][, fn])` | |
| 320 | 349 | ||
| 321 | 350 | <!-- YAML | |
@@ -560,6 +589,47 @@ describe('tests', async () => { | |||
| 560 | 589 | }); | |
| 561 | 590 | ``` | |
| 562 | 591 | ||
| 592 | + ## Class: `TapStream` | ||
| 593 | + | ||
| 594 | + <!-- YAML | ||
| 595 | + added: REPLACEME | ||
| 596 | + --> | ||
| 597 | + | ||
| 598 | + * Extends {ReadableStream} | ||
| 599 | + | ||
| 600 | + A successful call to [`run()`][] method will return a new {TapStream} | ||
| 601 | + object, streaming a [TAP][] output | ||
| 602 | + `TapStream` will emit events, in the order of the tests definition | ||
| 603 | + | ||
| 604 | + ### Event: `'test:diagnostic'` | ||
| 605 | + | ||
| 606 | + * `message` {string} The diagnostic message. | ||
| 607 | + | ||
| 608 | + Emitted when [`context.diagnostic`][] is called. | ||
| 609 | + | ||
| 610 | + ### Event: `'test:fail'` | ||
| 611 | + | ||
| 612 | + * `data` {Object} | ||
| 613 | + * `duration` {number} The test duration. | ||
| 614 | + * `error` {Error} The failure casing test to fail. | ||
| 615 | + * `name` {string} The test name. | ||
| 616 | + * `testNumber` {number} The ordinal number of the test. | ||
| 617 | + * `todo` {string|undefined} Present if [`context.todo`][] is called | ||
| 618 | + * `skip` {string|undefined} Present if [`context.skip`][] is called | ||
| 619 | + | ||
| 620 | + Emitted when a test fails. | ||
| 621 | + | ||
| 622 | + ### Event: `'test:pass'` | ||
| 623 | + | ||
| 624 | + * `data` {Object} | ||
| 625 | + * `duration` {number} The test duration. | ||
| 626 | + * `name` {string} The test name. | ||
| 627 | + * `testNumber` {number} The ordinal number of the test. | ||
| 628 | + * `todo` {string|undefined} Present if [`context.todo`][] is called | ||
| 629 | + * `skip` {string|undefined} Present if [`context.skip`][] is called | ||
| 630 | + | ||
| 631 | + Emitted when a test passes. | ||
| 632 | + | ||
| 563 | 633 | ## Class: `TestContext` | |
| 564 | 634 | ||
| 565 | 635 | <!-- YAML | |
@@ -825,6 +895,10 @@ added: v16.17.0 | |||
| 825 | 895 | [`--test`]: cli.md#--test | |
| 826 | 896 | [`SuiteContext`]: #class-suitecontext | |
| 827 | 897 | [`TestContext`]: #class-testcontext | |
| 898 | + [`context.diagnostic`]: #contextdiagnosticmessage | ||
| 899 | + [`context.skip`]: #contextskipmessage | ||
| 900 | + [`context.todo`]: #contexttodomessage | ||
| 901 | + [`run()`]: #runoptions | ||
| 828 | 902 | [`test()`]: #testname-options-fn | |
| 829 | 903 | [describe options]: #describename-options-fn | |
| 830 | 904 | [it options]: #testname-options-fn | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,146 +1,14 @@ | |||
| 1 | 1 | 'use strict'; | |
| 2 | - const { | ||
| 3 | - ArrayFrom, | ||
| 4 | - ArrayPrototypeFilter, | ||
| 5 | - ArrayPrototypeIncludes, | ||
| 6 | - ArrayPrototypeJoin, | ||
| 7 | - ArrayPrototypePush, | ||
| 8 | - ArrayPrototypeSlice, | ||
| 9 | - ArrayPrototypeSort, | ||
| 10 | - SafePromiseAll, | ||
| 11 | - SafeSet, | ||
| 12 | - } = primordials; | ||
| 13 | 2 | const { | |
| 14 | 3 | prepareMainThreadExecution, | |
| 15 | 4 | } = require('internal/bootstrap/pre_execution'); | |
| 16 | - const { spawn } = require('child_process'); | ||
| 17 | - const { readdirSync, statSync } = require('fs'); | ||
| 18 | - const console = require('internal/console/global'); | ||
| 19 | - const { | ||
| 20 | - codes: { | ||
| 21 | - ERR_TEST_FAILURE, | ||
| 22 | - }, | ||
| 23 | - } = require('internal/errors'); | ||
| 24 | - const { test } = require('internal/test_runner/harness'); | ||
| 25 | - const { kSubtestsFailed } = require('internal/test_runner/test'); | ||
| 26 | - const { | ||
| 27 | - isSupportedFileType, | ||
| 28 | - doesPathMatchFilter, | ||
| 29 | - } = require('internal/test_runner/utils'); | ||
| 30 | - const { basename, join, resolve } = require('path'); | ||
| 31 | - const { once } = require('events'); | ||
| 32 | - const kFilterArgs = ['--test']; | ||
| 5 | + const { run } = require('internal/test_runner/runner'); | ||
| 33 | 6 | ||
| 34 | 7 | prepareMainThreadExecution(false); | |
| 35 | 8 | markBootstrapComplete(); | |
| 36 | 9 | ||
| 37 | - // TODO(cjihrig): Replace this with recursive readdir once it lands. | ||
| 38 | - function processPath(path, testFiles, options) { | ||
| 39 | - const stats = statSync(path); | ||
| 40 | - | ||
| 41 | - if (stats.isFile()) { | ||
| 42 | - if (options.userSupplied || | ||
| 43 | - (options.underTestDir && isSupportedFileType(path)) || | ||
| 44 | - doesPathMatchFilter(path)) { | ||
| 45 | - testFiles.add(path); | ||
| 46 | - } | ||
| 47 | - } else if (stats.isDirectory()) { | ||
| 48 | - const name = basename(path); | ||
| 49 | - | ||
| 50 | - if (!options.userSupplied && name === 'node_modules') { | ||
| 51 | - return; | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - // 'test' directories get special treatment. Recursively add all .js, | ||
| 55 | - // .cjs, and .mjs files in the 'test' directory. | ||
| 56 | - const isTestDir = name === 'test'; | ||
| 57 | - const { underTestDir } = options; | ||
| 58 | - const entries = readdirSync(path); | ||
| 59 | - | ||
| 60 | - if (isTestDir) { | ||
| 61 | - options.underTestDir = true; | ||
| 62 | - } | ||
| 63 | - | ||
| 64 | - options.userSupplied = false; | ||
| 65 | - | ||
| 66 | - for (let i = 0; i < entries.length; i++) { | ||
| 67 | - processPath(join(path, entries[i]), testFiles, options); | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | - options.underTestDir = underTestDir; | ||
| 71 | - } | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - function createTestFileList() { | ||
| 75 | - const cwd = process.cwd(); | ||
| 76 | - const hasUserSuppliedPaths = process.argv.length > 1; | ||
| 77 | - const testPaths = hasUserSuppliedPaths ? | ||
| 78 | - ArrayPrototypeSlice(process.argv, 1) : [cwd]; | ||
| 79 | - const testFiles = new SafeSet(); | ||
| 80 | - | ||
| 81 | - try { | ||
| 82 | - for (let i = 0; i < testPaths.length; i++) { | ||
| 83 | - const absolutePath = resolve(testPaths[i]); | ||
| 84 | - | ||
| 85 | - processPath(absolutePath, testFiles, { userSupplied: true }); | ||
| 86 | - } | ||
| 87 | - } catch (err) { | ||
| 88 | - if (err?.code === 'ENOENT') { | ||
| 89 | - console.error(`Could not find '${err.path}'`); | ||
| 90 | - process.exit(1); | ||
| 91 | - } | ||
| 92 | - | ||
| 93 | - throw err; | ||
| 94 | - } | ||
| 95 | - | ||
| 96 | - return ArrayPrototypeSort(ArrayFrom(testFiles)); | ||
| 97 | - } | ||
| 98 | - | ||
| 99 | - function filterExecArgv(arg) { | ||
| 100 | - return !ArrayPrototypeIncludes(kFilterArgs, arg); | ||
| 101 | - } | ||
| 102 | - | ||
| 103 | - function runTestFile(path) { | ||
| 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; | ||
| 115 | - }); | ||
| 116 | - | ||
| 117 | - const { 0: { 0: code, 1: 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 | - } | ||
| 137 | - }); | ||
| 138 | - } | ||
| 139 | - | ||
| 140 | - (async function main() { | ||
| 141 | - const testFiles = createTestFileList(); | ||
| 142 | - | ||
| 143 | - for (let i = 0; i < testFiles.length; i++) { | ||
| 144 | - runTestFile(testFiles[i]); | ||
| 145 | - } | ||
| 146 | - })(); | ||
| 10 | + const tapStream = run(); | ||
| 11 | + tapStream.pipe(process.stdout); | ||
| 12 | + tapStream.once('test:fail', () => { | ||
| 13 | + process.exitCode = 1; | ||
| 14 | + }); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments