|
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 | markBootstrapComplete |
16 | 5 | } = require('internal/process/pre_execution'); |
17 | | -const { spawn } = require('child_process'); |
18 | | -const { readdirSync, statSync } = require('fs'); |
19 | | -const console = require('internal/console/global'); |
20 | | -const { |
21 | | - codes: { |
22 | | - ERR_TEST_FAILURE, |
23 | | - }, |
24 | | -} = require('internal/errors'); |
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']; |
| 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) : [cwd]; |
80 | | - const testFiles = new SafeSet(); |
81 | | - |
82 | | - try { |
83 | | - for (let i = 0; i < testPaths.length; i++) { |
84 | | - const absolutePath = resolve(testPaths[i]); |
85 | | - |
86 | | - processPath(absolutePath, testFiles, { userSupplied: true }); |
87 | | - } |
88 | | - } catch (err) { |
89 | | - if (err?.code === 'ENOENT') { |
90 | | - console.error(`Could not find '${err.path}'`); |
91 | | - process.exit(1); |
92 | | - } |
93 | | - |
94 | | - throw err; |
95 | | - } |
96 | | - |
97 | | - return ArrayPrototypeSort(ArrayFrom(testFiles)); |
98 | | -} |
99 | | - |
100 | | -function filterExecArgv(arg) { |
101 | | - return !ArrayPrototypeIncludes(kFilterArgs, arg); |
102 | | -} |
103 | | - |
104 | | -function runTestFile(path) { |
105 | | - return test(path, async (t) => { |
106 | | - const args = ArrayPrototypeFilter(process.execArgv, filterExecArgv); |
107 | | - ArrayPrototypePush(args, path); |
108 | | - |
109 | | - const child = spawn(process.execPath, args, { signal: t.signal, encoding: 'utf8' }); |
110 | | - // TODO(cjihrig): Implement a TAP parser to read the child's stdout |
111 | | - // instead of just displaying it all if the child fails. |
112 | | - let err; |
113 | | - |
114 | | - child.on('error', (error) => { |
115 | | - err = error; |
116 | | - }); |
117 | | - |
118 | | - const { 0: { 0: code, 1: signal }, 1: stdout, 2: stderr } = await SafePromiseAll([ |
119 | | - once(child, 'exit', { signal: t.signal }), |
120 | | - child.stdout.toArray({ signal: t.signal }), |
121 | | - child.stderr.toArray({ signal: t.signal }), |
122 | | - ]); |
123 | | - |
124 | | - if (code !== 0 || signal !== null) { |
125 | | - if (!err) { |
126 | | - err = new ERR_TEST_FAILURE('test failed', kSubtestsFailed); |
127 | | - err.exitCode = code; |
128 | | - err.signal = signal; |
129 | | - err.stdout = ArrayPrototypeJoin(stdout, ''); |
130 | | - err.stderr = ArrayPrototypeJoin(stderr, ''); |
131 | | - // The stack will not be useful since the failures came from tests |
132 | | - // in a child process. |
133 | | - err.stack = undefined; |
134 | | - } |
135 | | - |
136 | | - throw err; |
137 | | - } |
138 | | - }); |
139 | | -} |
140 | | - |
141 | | -(async function main() { |
142 | | - const testFiles = createTestFileList(); |
143 | | - |
144 | | - for (let i = 0; i < testFiles.length; i++) { |
145 | | - runTestFile(testFiles[i]); |
146 | | - } |
147 | | -})(); |
| 11 | +const tapStream = run(); |
| 12 | +tapStream.pipe(process.stdout); |
| 13 | +tapStream.once('test:fail', () => { |
| 14 | + process.exitCode = 1; |
| 15 | +}); |
0 commit comments