| 
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 | +});  | 
0 commit comments