|
1 | | -// https://github.com/nodejs/node/blob/2fd4c013c221653da2a7921d08fe1aa96aaba504/lib/internal/main/test_runner.js |
| 1 | +// https://github.com/nodejs/node/blob/59527de13d39327eb3dfa8dedc92241eb40066d5/lib/internal/main/test_runner.js |
2 | 2 | 'use strict' |
3 | | -const { |
4 | | - ArrayFrom, |
5 | | - ArrayPrototypeFilter, |
6 | | - ArrayPrototypeIncludes, |
7 | | - ArrayPrototypeJoin, |
8 | | - ArrayPrototypePush, |
9 | | - ArrayPrototypeSlice, |
10 | | - ArrayPrototypeSort, |
11 | | - SafePromiseAll, |
12 | | - SafeSet |
13 | | -} = require('#internal/per_context/primordials') |
14 | 3 | const { |
15 | 4 | prepareMainThreadExecution |
16 | | -} = require('#internal/bootstrap/pre_execution') |
17 | | -const { spawn } = require('child_process') |
18 | | -const { readdirSync, statSync } = require('fs') |
19 | | -const { |
20 | | - codes: { |
21 | | - ERR_TEST_FAILURE |
22 | | - } |
23 | | -} = require('#internal/errors') |
24 | | -const { toArray } = require('#internal/streams/operators').promiseReturningOperators |
25 | | -const { test } = require('#internal/test_runner/harness') |
26 | | -const { kSubtestsFailed } = require('#internal/test_runner/test') |
27 | | -const { |
28 | | - isSupportedFileType, |
29 | | - doesPathMatchFilter |
30 | | -} = require('#internal/test_runner/utils') |
31 | | -const { basename, join, resolve } = require('path') |
32 | | -const { once } = require('events') |
33 | | -const kFilterArgs = ['--test'] |
| 5 | +} = require('#internal/process/pre_execution') |
| 6 | +const { run } = require('#internal/test_runner/runner') |
34 | 7 |
|
35 | 8 | prepareMainThreadExecution(false) |
36 | 9 | // markBootstrapComplete(); |
37 | 10 |
|
38 | | -// TODO(cjihrig): Replace this with recursive readdir once it lands. |
39 | | -function processPath (path, testFiles, options) { |
40 | | - const stats = statSync(path) |
41 | | - |
42 | | - if (stats.isFile()) { |
43 | | - if (options.userSupplied || |
44 | | - (options.underTestDir && isSupportedFileType(path)) || |
45 | | - doesPathMatchFilter(path)) { |
46 | | - testFiles.add(path) |
47 | | - } |
48 | | - } else if (stats.isDirectory()) { |
49 | | - const name = basename(path) |
50 | | - |
51 | | - if (!options.userSupplied && name === 'node_modules') { |
52 | | - return |
53 | | - } |
54 | | - |
55 | | - // 'test' directories get special treatment. Recursively add all .js, |
56 | | - // .cjs, and .mjs files in the 'test' directory. |
57 | | - const isTestDir = name === 'test' |
58 | | - const { underTestDir } = options |
59 | | - const entries = readdirSync(path) |
60 | | - |
61 | | - if (isTestDir) { |
62 | | - options.underTestDir = true |
63 | | - } |
64 | | - |
65 | | - options.userSupplied = false |
66 | | - |
67 | | - for (let i = 0; i < entries.length; i++) { |
68 | | - processPath(join(path, entries[i]), testFiles, options) |
69 | | - } |
70 | | - |
71 | | - options.underTestDir = underTestDir |
72 | | - } |
73 | | -} |
74 | | - |
75 | | -function createTestFileList () { |
76 | | - const cwd = process.cwd() |
77 | | - const hasUserSuppliedPaths = process.argv.length > 1 |
78 | | - const testPaths = hasUserSuppliedPaths |
79 | | - ? ArrayPrototypeSlice(process.argv, 1) |
80 | | - : [cwd] |
81 | | - const testFiles = new SafeSet() |
82 | | - |
83 | | - try { |
84 | | - for (let i = 0; i < testPaths.length; i++) { |
85 | | - const absolutePath = resolve(testPaths[i]) |
86 | | - |
87 | | - processPath(absolutePath, testFiles, { userSupplied: true }) |
88 | | - } |
89 | | - } catch (err) { |
90 | | - if (err?.code === 'ENOENT') { |
91 | | - console.error(`Could not find '${err.path}'`) |
92 | | - process.exit(1) |
93 | | - } |
94 | | - |
95 | | - throw err |
96 | | - } |
97 | | - |
98 | | - return ArrayPrototypeSort(ArrayFrom(testFiles)) |
99 | | -} |
100 | | - |
101 | | -function filterExecArgv (arg) { |
102 | | - return !ArrayPrototypeIncludes(kFilterArgs, arg) |
103 | | -} |
104 | | - |
105 | | -function runTestFile (path) { |
106 | | - return test(path, async (t) => { |
107 | | - const args = ArrayPrototypeFilter(process.execArgv, filterExecArgv) |
108 | | - ArrayPrototypePush(args, path) |
109 | | - |
110 | | - const child = spawn(process.execPath, args, { signal: t.signal, encoding: 'utf8' }) |
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 err |
114 | | - |
115 | | - child.on('error', (error) => { |
116 | | - err = error |
117 | | - }) |
118 | | - |
119 | | - const { 0: { 0: code, 1: signal }, 1: stdout, 2: stderr } = await SafePromiseAll([ |
120 | | - once(child, 'exit', { signal: t.signal }), |
121 | | - toArray.call(child.stdout, { signal: t.signal }), |
122 | | - toArray.call(child.stderr, { signal: t.signal }) |
123 | | - ]) |
124 | | - |
125 | | - if (code !== 0 || signal !== null) { |
126 | | - if (!err) { |
127 | | - err = new ERR_TEST_FAILURE('test failed', kSubtestsFailed) |
128 | | - err.exitCode = code |
129 | | - err.signal = signal |
130 | | - err.stdout = ArrayPrototypeJoin(stdout, '') |
131 | | - err.stderr = ArrayPrototypeJoin(stderr, '') |
132 | | - // The stack will not be useful since the failures came from tests |
133 | | - // in a child process. |
134 | | - err.stack = undefined |
135 | | - } |
136 | | - |
137 | | - throw err |
138 | | - } |
139 | | - }) |
140 | | -} |
141 | | - |
142 | | -;(async function main () { |
143 | | - const testFiles = createTestFileList() |
144 | | - |
145 | | - for (let i = 0; i < testFiles.length; i++) { |
146 | | - runTestFile(testFiles[i]) |
147 | | - } |
148 | | -})() |
| 11 | +const tapStream = run() |
| 12 | +tapStream.pipe(process.stdout) |
| 13 | +tapStream.once('test:fail', () => { |
| 14 | + process.exitCode = 1 |
| 15 | +}) |
0 commit comments