1'use strict';
2
3require('../common');
4const assert = require('assert');
5const { spawnSync } = require('child_process');
6const { join } = require('path');
7const { readdirSync } = require('fs');
8const fixtures = require('../common/fixtures');
9const testFixtures = fixtures.path('test-runner');
10
11{
12  // File not found.
13  const args = ['--test', 'a-random-file-that-does-not-exist.js'];
14  const child = spawnSync(process.execPath, args);
15
16  assert.strictEqual(child.status, 1);
17  assert.strictEqual(child.signal, null);
18  assert.strictEqual(child.stdout.toString(), '');
19  assert.match(child.stderr.toString(), /^Could not find/);
20}
21
22{
23  // Default behavior. node_modules is ignored. Files that don't match the
24  // pattern are ignored except in test/ directories.
25  const args = ['--test'];
26  const child = spawnSync(process.execPath, args, { cwd: join(testFixtures, 'default-behavior') });
27
28  assert.strictEqual(child.status, 1);
29  assert.strictEqual(child.signal, null);
30  assert.strictEqual(child.stderr.toString(), '');
31  const stdout = child.stdout.toString();
32  assert.match(stdout, /ok 1 - this should pass/);
33  assert.match(stdout, /not ok 2 - this should fail/);
34  assert.match(stdout, /ok 3 - .+subdir.+subdir_test\.js/);
35  assert.match(stdout, /ok 4 - this should pass/);
36  assert.match(stdout, /ok 5 - this should be skipped/);
37  assert.match(stdout, /ok 6 - this should be executed/);
38}
39
40{
41  // Same but with a prototype mutation in require scripts.
42  const args = ['--require', join(testFixtures, 'protoMutation.js'), '--test'];
43  const child = spawnSync(process.execPath, args, { cwd: join(testFixtures, 'default-behavior') });
44
45  const stdout = child.stdout.toString();
46  assert.match(stdout, /ok 1 - this should pass/);
47  assert.match(stdout, /not ok 2 - this should fail/);
48  assert.match(stdout, /ok 3 - .+subdir.+subdir_test\.js/);
49  assert.match(stdout, /ok 4 - this should pass/);
50  assert.match(stdout, /ok 5 - this should be skipped/);
51  assert.match(stdout, /ok 6 - this should be executed/);
52  assert.strictEqual(child.status, 1);
53  assert.strictEqual(child.signal, null);
54  assert.strictEqual(child.stderr.toString(), '');
55}
56
57{
58  // User specified files that don't match the pattern are still run.
59  const args = ['--test', join(testFixtures, 'index.js')];
60  const child = spawnSync(process.execPath, args, { cwd: testFixtures });
61
62  assert.strictEqual(child.status, 1);
63  assert.strictEqual(child.signal, null);
64  assert.strictEqual(child.stderr.toString(), '');
65  const stdout = child.stdout.toString();
66  assert.match(stdout, /not ok 1 - .+index\.js/);
67}
68
69{
70  // Searches node_modules if specified.
71  const args = ['--test', join(testFixtures, 'default-behavior/node_modules')];
72  const child = spawnSync(process.execPath, args);
73
74  assert.strictEqual(child.status, 1);
75  assert.strictEqual(child.signal, null);
76  assert.strictEqual(child.stderr.toString(), '');
77  const stdout = child.stdout.toString();
78  assert.match(stdout, /not ok 1 - .+test-nm\.js/);
79}
80
81{
82  // The current directory is used by default.
83  const args = ['--test'];
84  const options = { cwd: join(testFixtures, 'default-behavior') };
85  const child = spawnSync(process.execPath, args, options);
86
87  assert.strictEqual(child.status, 1);
88  assert.strictEqual(child.signal, null);
89  assert.strictEqual(child.stderr.toString(), '');
90  const stdout = child.stdout.toString();
91  assert.match(stdout, /ok 1 - this should pass/);
92  assert.match(stdout, /not ok 2 - this should fail/);
93  assert.match(stdout, /ok 3 - .+subdir.+subdir_test\.js/);
94  assert.match(stdout, /ok 4 - this should pass/);
95  assert.match(stdout, /ok 5 - this should be skipped/);
96  assert.match(stdout, /ok 6 - this should be executed/);
97}
98
99{
100  // Flags that cannot be combined with --test.
101  const flags = [
102    ['--check', '--test'],
103    ['--interactive', '--test'],
104    ['--eval', 'console.log("should not print")', '--test'],
105    ['--print', 'console.log("should not print")', '--test'],
106  ];
107
108  flags.forEach((args) => {
109    const child = spawnSync(process.execPath, args);
110
111    assert.notStrictEqual(child.status, 0);
112    assert.strictEqual(child.signal, null);
113    assert.strictEqual(child.stdout.toString(), '');
114    const stderr = child.stderr.toString();
115    assert.match(stderr, /--test/);
116  });
117}
118
119{
120  // Test combined stream outputs
121  const args = [
122    '--test',
123    'test/fixtures/test-runner/default-behavior/index.test.js',
124    'test/fixtures/test-runner/nested.js',
125    'test/fixtures/test-runner/invalid-tap.js',
126  ];
127  const child = spawnSync(process.execPath, args);
128
129
130  assert.strictEqual(child.status, 1);
131  assert.strictEqual(child.signal, null);
132  assert.strictEqual(child.stderr.toString(), '');
133  const stdout = child.stdout.toString();
134  assert.match(stdout, /# Subtest: this should pass/);
135  assert.match(stdout, /ok 1 - this should pass/);
136  assert.match(stdout, / {2}---/);
137  assert.match(stdout, / {2}duration_ms: .*/);
138  assert.match(stdout, / {2}\.\.\./);
139
140  assert.match(stdout, /# Subtest: .+invalid-tap\.js/);
141  assert.match(stdout, /# invalid tap output/);
142  assert.match(stdout, /ok 2 - .+invalid-tap\.js/);
143
144  assert.match(stdout, /# Subtest: level 0a/);
145  assert.match(stdout, / {4}# Subtest: level 1a/);
146  assert.match(stdout, / {4}ok 1 - level 1a/);
147  assert.match(stdout, / {4}# Subtest: level 1b/);
148  assert.match(stdout, / {4}not ok 2 - level 1b/);
149  assert.match(stdout, / {6}code: 'ERR_TEST_FAILURE'/);
150  assert.match(stdout, / {6}stack: |-'/);
151  assert.match(stdout, / {8}TestContext\.<anonymous> .*/);
152  assert.match(stdout, / {4}# Subtest: level 1c/);
153  assert.match(stdout, / {4}ok 3 - level 1c # SKIP aaa/);
154  assert.match(stdout, / {4}# Subtest: level 1d/);
155  assert.match(stdout, / {4}ok 4 - level 1d/);
156  assert.match(stdout, /not ok 3 - level 0a/);
157  assert.match(stdout, / {2}error: '1 subtest failed'/);
158  assert.match(stdout, /# Subtest: level 0b/);
159  assert.match(stdout, /not ok 4 - level 0b/);
160  assert.match(stdout, / {2}error: 'level 0b error'/);
161  assert.match(stdout, /# tests 8/);
162  assert.match(stdout, /# suites 0/);
163  assert.match(stdout, /# pass 4/);
164  assert.match(stdout, /# fail 3/);
165  assert.match(stdout, /# cancelled 0/);
166  assert.match(stdout, /# skipped 1/);
167  assert.match(stdout, /# todo 0/);
168}
169
170{
171  // Test user logging in tests.
172  const args = [
173    '--test',
174    'test/fixtures/test-runner/user-logs.js',
175  ];
176  const child = spawnSync(process.execPath, args);
177
178  assert.strictEqual(child.status, 0);
179  assert.strictEqual(child.signal, null);
180  assert.strictEqual(child.stderr.toString(), '');
181  const stdout = child.stdout.toString();
182  assert.match(stdout, /# stderr 1/);
183  assert.match(stdout, /# stderr 2/);
184  assert.match(stdout, /# stdout 3/);
185  assert.match(stdout, /# stderr 6/);
186  assert.match(stdout, /# not ok 1 - fake test/);
187  assert.match(stdout, /# stderr 5/);
188  assert.match(stdout, /# stdout 4/);
189  assert.match(stdout, /# Subtest: a test/);
190  assert.match(stdout, /ok 1 - a test/);
191  assert.match(stdout, /# tests 1/);
192  assert.match(stdout, /# pass 1/);
193}
194
195{
196  // Use test with --loader and --require.
197  // This case is common since vscode uses --require to load the debugger.
198  const args = ['--no-warnings',
199                '--experimental-loader', 'data:text/javascript,',
200                '--require', fixtures.path('empty.js'),
201                '--test', join(testFixtures, 'default-behavior', 'index.test.js')];
202  const child = spawnSync(process.execPath, args);
203
204  assert.strictEqual(child.stderr.toString(), '');
205  assert.strictEqual(child.status, 0);
206  assert.strictEqual(child.signal, null);
207  const stdout = child.stdout.toString();
208  assert.match(stdout, /ok 1 - this should pass/);
209}
210
211{
212  // --test-shard option validation
213  const args = ['--test', '--test-shard=1', join(testFixtures, 'index.js')];
214  const child = spawnSync(process.execPath, args, { cwd: testFixtures });
215
216  assert.strictEqual(child.status, 1);
217  assert.strictEqual(child.signal, null);
218  assert.match(child.stderr.toString(), /The argument '--test-shard' must be in the form of <index>\/<total>\. Received '1'/);
219  const stdout = child.stdout.toString();
220  assert.strictEqual(stdout, '');
221}
222
223{
224  // --test-shard option validation
225  const args = ['--test', '--test-shard=1/2/3', join(testFixtures, 'index.js')];
226  const child = spawnSync(process.execPath, args, { cwd: testFixtures });
227
228  assert.strictEqual(child.status, 1);
229  assert.strictEqual(child.signal, null);
230  assert.match(child.stderr.toString(), /The argument '--test-shard' must be in the form of <index>\/<total>\. Received '1\/2\/3'/);
231  const stdout = child.stdout.toString();
232  assert.strictEqual(stdout, '');
233}
234
235{
236  // --test-shard option validation
237  const args = ['--test', '--test-shard=0/3', join(testFixtures, 'index.js')];
238  const child = spawnSync(process.execPath, args, { cwd: testFixtures });
239
240  assert.strictEqual(child.status, 1);
241  assert.strictEqual(child.signal, null);
242  assert.match(child.stderr.toString(), /The value of "options\.shard\.index" is out of range\. It must be >= 1 && <= 3 \("options\.shard\.total"\)\. Received 0/);
243  const stdout = child.stdout.toString();
244  assert.strictEqual(stdout, '');
245}
246
247{
248  // --test-shard option validation
249  const args = ['--test', '--test-shard=0xf/20abcd', join(testFixtures, 'index.js')];
250  const child = spawnSync(process.execPath, args, { cwd: testFixtures });
251
252  assert.strictEqual(child.status, 1);
253  assert.strictEqual(child.signal, null);
254  assert.match(child.stderr.toString(), /The argument '--test-shard' must be in the form of <index>\/<total>\. Received '0xf\/20abcd'/);
255  const stdout = child.stdout.toString();
256  assert.strictEqual(stdout, '');
257}
258
259{
260  // --test-shard option validation
261  const args = ['--test', '--test-shard=hello', join(testFixtures, 'index.js')];
262  const child = spawnSync(process.execPath, args, { cwd: testFixtures });
263
264  assert.strictEqual(child.status, 1);
265  assert.strictEqual(child.signal, null);
266  assert.match(child.stderr.toString(), /The argument '--test-shard' must be in the form of <index>\/<total>\. Received 'hello'/);
267  const stdout = child.stdout.toString();
268  assert.strictEqual(stdout, '');
269}
270
271{
272  // --test-shard option, first shard
273  const shardsTestPath = join(testFixtures, 'shards');
274  const allShardsTestsFiles = readdirSync(shardsTestPath).map((file) => join(shardsTestPath, file));
275  const args = [
276    '--test',
277    '--test-shard=1/2',
278    ...allShardsTestsFiles,
279  ];
280  const child = spawnSync(process.execPath, args);
281
282  assert.strictEqual(child.status, 0);
283  assert.strictEqual(child.signal, null);
284  assert.strictEqual(child.stderr.toString(), '');
285  const stdout = child.stdout.toString();
286  assert.match(stdout, /# Subtest: a\.cjs this should pass/);
287  assert.match(stdout, /ok 1 - a\.cjs this should pass/);
288
289  assert.match(stdout, /# Subtest: c\.cjs this should pass/);
290  assert.match(stdout, /ok 2 - c\.cjs this should pass/);
291
292  assert.match(stdout, /# Subtest: e\.cjs this should pass/);
293  assert.match(stdout, /ok 3 - e\.cjs this should pass/);
294
295  assert.match(stdout, /# Subtest: g\.cjs this should pass/);
296  assert.match(stdout, /ok 4 - g\.cjs this should pass/);
297
298  assert.match(stdout, /# Subtest: i\.cjs this should pass/);
299  assert.match(stdout, /ok 5 - i\.cjs this should pass/);
300
301  assert.match(stdout, /# tests 5/);
302  assert.match(stdout, /# pass 5/);
303  assert.match(stdout, /# fail 0/);
304  assert.match(stdout, /# skipped 0/);
305}
306
307{
308  // --test-shard option, last shard
309  const shardsTestPath = join(testFixtures, 'shards');
310  const allShardsTestsFiles = readdirSync(shardsTestPath).map((file) => join(shardsTestPath, file));
311  const args = [
312    '--test',
313    '--test-shard=2/2',
314    ...allShardsTestsFiles,
315  ];
316  const child = spawnSync(process.execPath, args);
317
318  assert.strictEqual(child.status, 0);
319  assert.strictEqual(child.signal, null);
320  assert.strictEqual(child.stderr.toString(), '');
321  const stdout = child.stdout.toString();
322  assert.match(stdout, /# Subtest: b\.cjs this should pass/);
323  assert.match(stdout, /ok 1 - b\.cjs this should pass/);
324
325  assert.match(stdout, /# Subtest: d\.cjs this should pass/);
326  assert.match(stdout, /ok 2 - d\.cjs this should pass/);
327
328  assert.match(stdout, /# Subtest: f\.cjs this should pass/);
329  assert.match(stdout, /ok 3 - f\.cjs this should pass/);
330
331  assert.match(stdout, /# Subtest: h\.cjs this should pass/);
332  assert.match(stdout, /ok 4 - h\.cjs this should pass/);
333
334  assert.match(stdout, /# Subtest: j\.cjs this should pass/);
335  assert.match(stdout, /ok 5 - j\.cjs this should pass/);
336
337  assert.match(stdout, /# tests 5/);
338  assert.match(stdout, /# pass 5/);
339  assert.match(stdout, /# fail 0/);
340  assert.match(stdout, /# skipped 0/);
341}
342