Skip to content

Commit e7bb929

Browse files
committed
test_runner: scope file-level hooks per file in --test-isolation=none
1 parent 35fed19 commit e7bb929

File tree

5 files changed

+45
-65
lines changed

5 files changed

+45
-65
lines changed

lib/internal/test_runner/runner.js

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const {
7979
kSubtestsFailed,
8080
kTestCodeFailure,
8181
kTestTimeoutFailure,
82+
Suite,
8283
Test,
8384
} = require('internal/test_runner/test');
8485
const { FastBuffer } = require('internal/buffer');
@@ -905,35 +906,21 @@ function run(options = kEmptyObject) {
905906
const testFile = testFiles[i];
906907
const fileURL = pathToFileURL(resolve(cwd, testFile));
907908
const parent = i === 0 ? undefined : parentURL;
908-
let threw = false;
909-
let importError;
910909

911910
root.entryFile = resolve(testFile);
912911
debug('loading test file:', fileURL.href);
913-
try {
912+
913+
// Wrap each file in an implicit suite so that top-level hooks
914+
// (e.g. beforeEach, afterEach) are scoped to the file and do
915+
// not leak across test files.
916+
const fileSuite = root.createSubtest(Suite, testFile, kEmptyObject, async () => {
914917
await cascadedLoader.import(fileURL, parent, { __proto__: null });
915-
} catch (err) {
916-
threw = true;
917-
importError = err;
918-
}
919-
920-
debug(
921-
'loaded "%s": top level test count before = %d and after = %d',
922-
testFile,
923-
topLevelTestCount,
924-
root.subtests.length,
925-
);
926-
if (topLevelTestCount === root.subtests.length) {
927-
// This file had no tests in it. Add the placeholder test.
928-
const subtest = root.createSubtest(Test, testFile, kEmptyObject, undefined, {
929-
__proto__: null,
930-
loc: [1, 1, resolve(testFile)],
931-
});
932-
if (threw) {
933-
subtest.fail(importError);
934-
}
935-
startSubtestAfterBootstrap(subtest);
936-
}
918+
}, {
919+
__proto__: null,
920+
loc: [1, 1, resolve(testFile)],
921+
});
922+
await fileSuite.buildSuite;
923+
startSubtestAfterBootstrap(fileSuite);
937924

938925
topLevelTestCount = root.subtests.length;
939926
}

test/parallel/test-runner-no-isolation-different-cwd.mjs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,22 @@ const stream = run({
99
});
1010

1111

12-
stream.on('test:pass', mustCall(4));
12+
stream.on('test:pass', mustCall(6));
1313
// eslint-disable-next-line no-unused-vars
1414
for await (const _ of stream);
1515
allowGlobals(globalThis.GLOBAL_ORDER);
1616
assert.deepStrictEqual(globalThis.GLOBAL_ORDER, [
17-
'before one: <root>',
1817
'suite one',
19-
'before two: <root>',
2018
'suite two',
19+
'before one: one.test.js',
2120
'beforeEach one: suite one - test',
22-
'beforeEach two: suite one - test',
2321
'suite one - test',
2422
'afterEach one: suite one - test',
25-
'afterEach two: suite one - test',
23+
'after one: one.test.js',
24+
'before two: two.test.js',
2625
'before suite two: suite two',
27-
'beforeEach one: suite two - test',
2826
'beforeEach two: suite two - test',
2927
'suite two - test',
30-
'afterEach one: suite two - test',
3128
'afterEach two: suite two - test',
32-
'after one: <root>',
33-
'after two: <root>',
29+
'after two: two.test.js',
3430
]);

test/parallel/test-runner-no-isolation-filtering.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ test('works with --test-only', () => {
2323
assert.strictEqual(child.status, 0);
2424
assert.strictEqual(child.signal, null);
2525
assert.match(stdout, /# tests 2/);
26-
assert.match(stdout, /# suites 2/);
26+
assert.match(stdout, /# suites 4/);
2727
assert.match(stdout, /# pass 2/);
2828
assert.match(stdout, /ok 1 - suite one/);
2929
assert.match(stdout, /ok 1 - suite one - test/);
30-
assert.match(stdout, /ok 2 - suite two/);
30+
assert.match(stdout, /ok 1 - suite two/);
3131
assert.match(stdout, /ok 1 - suite two - test/);
3232
});
3333

@@ -45,11 +45,11 @@ test('works without --test-only', () => {
4545
assert.strictEqual(child.status, 0);
4646
assert.strictEqual(child.signal, null);
4747
assert.match(stdout, /# tests 2/);
48-
assert.match(stdout, /# suites 2/);
48+
assert.match(stdout, /# suites 4/);
4949
assert.match(stdout, /# pass 2/);
5050
assert.match(stdout, /ok 1 - suite one/);
5151
assert.match(stdout, /ok 1 - suite one - test/);
52-
assert.match(stdout, /ok 2 - suite two/);
52+
assert.match(stdout, /ok 1 - suite two/);
5353
assert.match(stdout, /ok 1 - suite two - test/);
5454
});
5555

@@ -68,7 +68,7 @@ test('works with --test-name-pattern', () => {
6868
assert.strictEqual(child.status, 0);
6969
assert.strictEqual(child.signal, null);
7070
assert.match(stdout, /# tests 0/);
71-
assert.match(stdout, /# suites 0/);
71+
assert.match(stdout, /# suites 1/);
7272
});
7373

7474
test('works with --test-skip-pattern', () => {
@@ -86,7 +86,7 @@ test('works with --test-skip-pattern', () => {
8686
assert.strictEqual(child.status, 0);
8787
assert.strictEqual(child.signal, null);
8888
assert.match(stdout, /# tests 1/);
89-
assert.match(stdout, /# suites 1/);
89+
assert.match(stdout, /# suites 2/);
9090
assert.match(stdout, /# pass 1/);
9191
assert.match(stdout, /ok 1 - suite two - test/);
9292
});

test/parallel/test-runner-no-isolation-hooks.mjs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,34 @@ const testFiles = [
1212
fixtures.path('test-runner', 'no-isolation', 'two.test.js'),
1313
];
1414

15+
// Each file is wrapped in an implicit suite when using isolation: 'none',
16+
// so file-level hooks are scoped to their file. Global hooks (registered
17+
// via --import/--require) still run for all tests.
18+
const file1 = fixtures.path('test-runner', 'no-isolation', 'one.test.js');
19+
const file2 = fixtures.path('test-runner', 'no-isolation', 'two.test.js');
1520
const order = [
1621
'before(): global',
17-
18-
'before one: <root>',
1922
'suite one',
20-
21-
'before two: <root>',
2223
'suite two',
2324

25+
`before one: ${file1}`,
2426
'beforeEach(): global',
2527
'beforeEach one: suite one - test',
26-
'beforeEach two: suite one - test',
27-
2828
'suite one - test',
29-
'afterEach(): global',
3029
'afterEach one: suite one - test',
31-
'afterEach two: suite one - test',
30+
'afterEach(): global',
31+
`after one: ${file1}`,
3232

33+
`before two: ${file2}`,
3334
'before suite two: suite two',
3435
'beforeEach(): global',
35-
'beforeEach one: suite two - test',
3636
'beforeEach two: suite two - test',
37-
3837
'suite two - test',
39-
'afterEach(): global',
40-
'afterEach one: suite two - test',
4138
'afterEach two: suite two - test',
39+
'afterEach(): global',
40+
`after two: ${file2}`,
4241

4342
'after(): global',
44-
'after one: <root>',
45-
'after two: <root>',
4643
].join('\n');
4744

4845
test('use --import (CJS) to define global hooks', async (t) => {

test/parallel/test-runner-no-isolation.mjs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,30 @@ const stream = run({
1212
});
1313

1414
stream.on('test:fail', mustNotCall());
15-
stream.on('test:pass', mustCall(4));
15+
stream.on('test:pass', mustCall(6));
1616
// eslint-disable-next-line no-unused-vars
1717
for await (const _ of stream);
1818
allowGlobals(globalThis.GLOBAL_ORDER);
19+
20+
// Each file is wrapped in an implicit suite when using isolation: 'none',
21+
// so top-level hooks (before, beforeEach, etc.) are scoped to the file
22+
// and do not leak across test files.
23+
const file1 = fixtures.path('test-runner', 'no-isolation', 'one.test.js');
24+
const file2 = fixtures.path('test-runner', 'no-isolation', 'two.test.js');
1925
assert.deepStrictEqual(globalThis.GLOBAL_ORDER, [
20-
'before one: <root>',
2126
'suite one',
22-
'before two: <root>',
2327
'suite two',
2428

29+
`before one: ${file1}`,
2530
'beforeEach one: suite one - test',
26-
'beforeEach two: suite one - test',
2731
'suite one - test',
2832
'afterEach one: suite one - test',
29-
'afterEach two: suite one - test',
33+
`after one: ${file1}`,
3034

35+
`before two: ${file2}`,
3136
'before suite two: suite two',
32-
33-
'beforeEach one: suite two - test',
3437
'beforeEach two: suite two - test',
3538
'suite two - test',
36-
'afterEach one: suite two - test',
3739
'afterEach two: suite two - test',
38-
39-
'after one: <root>',
40-
'after two: <root>',
40+
`after two: ${file2}`,
4141
]);

0 commit comments

Comments
 (0)