Skip to content

Commit 33d1166

Browse files
authored
fix(jest-test-sequencer): make --onlyFailures flag working for tests failed due to compilation errors (#15851)
1 parent cb49b2e commit 33d1166

File tree

4 files changed

+91
-43
lines changed

4 files changed

+91
-43
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
### Fixes
88

99
- `[jest-runtime]` Fix issue where user cannot utilize dynamic import despite specifying `--experimental-vm-modules` Node option ([#15842](https://github.com/jestjs/jest/pull/15842))
10+
- `[jest-test-sequencer]` Fix issue where failed tests due to compilation errors not getting re-executed even with `--onlyFailures` CLI option ([#15851](https://github.com/jestjs/jest/pull/15851))
1011

1112
### Chore & Maintenance
1213

e2e/__tests__/onlyFailuresNonWatch.test.ts

Lines changed: 65 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,72 @@ const DIR = path.resolve(tmpdir(), 'non-watch-mode-onlyFailures');
1616
beforeEach(() => cleanup(DIR));
1717
afterEach(() => cleanup(DIR));
1818

19-
test('onlyFailures flag works in non-watch mode', () => {
20-
writeFiles(DIR, {
21-
'__tests__/a.js': `
19+
const failedTestContents = [
20+
{
21+
content: {
22+
'__tests__/a.js': `
2223
test('bar', () => { expect('bar').toBe('foo'); });
2324
`,
24-
'__tests__/b.js': `
25+
'__tests__/b.js': `
2526
test('foo', () => { expect('foo').toBe('foo'); });
2627
`,
27-
'package.json': JSON.stringify({
28-
jest: {
29-
testEnvironment: 'node',
30-
},
31-
}),
32-
});
33-
34-
let stdout, stderr;
35-
36-
({stdout, stderr} = runJest(DIR));
37-
expect(stdout).toBe('');
38-
expect(stderr).toMatch('FAIL __tests__/a.js');
39-
expect(stderr).toMatch('PASS __tests__/b.js');
40-
41-
// only the failed test should run and it should fail
42-
({stdout, stderr} = runJest(DIR, ['--onlyFailures']));
43-
expect(stdout).toBe('');
44-
expect(stderr).toMatch('FAIL __tests__/a.js');
45-
expect(stderr).not.toMatch('__tests__/b.js');
46-
47-
// fix the failing test
48-
const data = "test('bar 1', () => { expect('bar').toBe('bar'); })";
49-
fs.writeFileSync(path.join(DIR, '__tests__/a.js'), data);
50-
51-
// only the failed test should run and it should pass
52-
({stdout, stderr} = runJest(DIR, ['--onlyFailures']));
53-
expect(stdout).toBe('');
54-
expect(stderr).toMatch('PASS __tests__/a.js');
55-
expect(stderr).not.toMatch('__tests__/b.js');
56-
57-
// No test should run
58-
({stdout, stderr} = runJest(DIR, ['--onlyFailures']));
59-
expect(stdout).toBe('No failed test found.');
60-
expect(stderr).toBe('');
61-
});
28+
'package.json': JSON.stringify({
29+
jest: {
30+
testEnvironment: 'node',
31+
},
32+
}),
33+
},
34+
name: 'failed test logic from bar != foo',
35+
},
36+
{
37+
content: {
38+
'__tests__/a.js': `
39+
tes('bar', () => { expect('bar').toBe('foo'); });
40+
`,
41+
'__tests__/b.js': `
42+
test('foo', () => { expect('foo').toBe('foo'); });
43+
`,
44+
'package.json': JSON.stringify({
45+
jest: {
46+
testEnvironment: 'node',
47+
},
48+
}),
49+
},
50+
name: 'failed test compilation from SyntaxError',
51+
},
52+
];
53+
54+
test.each(failedTestContents)(
55+
'onlyFailures flag works in non-watch mode due to $name',
56+
({content}) => {
57+
writeFiles(DIR, content);
58+
59+
let stdout, stderr;
60+
61+
({stdout, stderr} = runJest(DIR));
62+
expect(stdout).toBe('');
63+
expect(stderr).toMatch('FAIL __tests__/a.js');
64+
expect(stderr).toMatch('PASS __tests__/b.js');
65+
66+
// only the failed test should run and it should fail
67+
({stdout, stderr} = runJest(DIR, ['--onlyFailures']));
68+
expect(stdout).toBe('');
69+
expect(stderr).toMatch('FAIL __tests__/a.js');
70+
expect(stderr).not.toMatch('__tests__/b.js');
71+
72+
// fix the failing test
73+
const data = "test('bar 1', () => { expect('bar').toBe('bar'); })";
74+
fs.writeFileSync(path.join(DIR, '__tests__/a.js'), data);
75+
76+
// only the failed test should run and it should pass
77+
({stdout, stderr} = runJest(DIR, ['--onlyFailures']));
78+
expect(stdout).toBe('');
79+
expect(stderr).toMatch('PASS __tests__/a.js');
80+
expect(stderr).not.toMatch('__tests__/b.js');
81+
82+
// No test should run
83+
({stdout, stderr} = runJest(DIR, ['--onlyFailures']));
84+
expect(stdout).toBe('No failed test found.');
85+
expect(stderr).toBe('');
86+
},
87+
);

packages/jest-test-sequencer/src/__tests__/test_sequencer.test.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77

88
import * as path from 'path';
99
import * as mockedFs from 'graceful-fs';
10-
import type {AggregatedResult, Test, TestContext} from '@jest/test-result';
10+
import type {
11+
AggregatedResult,
12+
SerializableError,
13+
Test,
14+
TestContext,
15+
} from '@jest/test-result';
1116
import {makeGlobalConfig, makeProjectConfig} from '@jest/test-utils';
1217
import TestSequencer from '../index';
1318

@@ -137,7 +142,7 @@ test('writes the cache based on results without existing cache', async () => {
137142
throw new Error('File does not exist.');
138143
});
139144

140-
const testPaths = ['/test-a.js', '/test-b.js', '/test-c.js'];
145+
const testPaths = ['/test-a.js', '/test-b.js', '/test-c.js', '/test-d.js'];
141146
const tests = await sequencer.sort(toTests(testPaths));
142147
sequencer.cacheResults(tests, {
143148
testResults: [
@@ -163,6 +168,12 @@ test('writes the cache based on results without existing cache', async () => {
163168
perfStats: {end: 2, runtime: 1, start: 1},
164169
testFilePath: '/test-x.js',
165170
},
171+
{
172+
numFailingTests: 0,
173+
perfStats: {end: 2, runtime: 1, start: 1},
174+
testExecError: {message: 'SyntaxError'} as SerializableError,
175+
testFilePath: '/test-d.js',
176+
},
166177
],
167178
});
168179
const fileData = JSON.parse(
@@ -171,6 +182,7 @@ test('writes the cache based on results without existing cache', async () => {
171182
expect(fileData).toEqual({
172183
'/test-a.js': [SUCCESS, 1],
173184
'/test-c.js': [FAIL, 3],
185+
'/test-d.js': [FAIL, 1],
174186
});
175187
});
176188

@@ -198,7 +210,7 @@ test('writes the cache based on the results', async () => {
198210
}),
199211
);
200212

201-
const testPaths = ['/test-a.js', '/test-b.js', '/test-c.js'];
213+
const testPaths = ['/test-a.js', '/test-b.js', '/test-c.js', '/test-d.js'];
202214
const tests = await sequencer.sort(toTests(testPaths));
203215
sequencer.cacheResults(tests, {
204216
testResults: [
@@ -223,6 +235,12 @@ test('writes the cache based on the results', async () => {
223235
perfStats: {end: 2, runtime: 1, start: 1},
224236
testFilePath: '/test-x.js',
225237
},
238+
{
239+
numFailingTests: 0,
240+
perfStats: {end: 2, runtime: 1, start: 1},
241+
testExecError: {message: 'SyntaxError'} as SerializableError,
242+
testFilePath: '/test-d.js',
243+
},
226244
],
227245
});
228246
const fileData = JSON.parse(
@@ -232,6 +250,7 @@ test('writes the cache based on the results', async () => {
232250
'/test-a.js': [SUCCESS, 1],
233251
'/test-b.js': [FAIL, 1],
234252
'/test-c.js': [FAIL, 3],
253+
'/test-d.js': [FAIL, 1],
235254
});
236255
});
237256

packages/jest-test-sequencer/src/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,9 @@ export default class TestSequencer {
231231
const testRuntime =
232232
perf.runtime ?? test.duration ?? perf.end - perf.start;
233233
cache[testResult.testFilePath] = [
234-
testResult.numFailingTests > 0 ? FAIL : SUCCESS,
234+
testResult.numFailingTests > 0 || testResult.testExecError
235+
? FAIL
236+
: SUCCESS,
235237
testRuntime || 0,
236238
];
237239
}

0 commit comments

Comments
 (0)