Skip to content

Commit 9633a26

Browse files
authored
feat: support reporters written in ESM (#11427)
1 parent 59f42d8 commit 9633a26

File tree

7 files changed

+72
-31
lines changed

7 files changed

+72
-31
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
### Features
44

5-
- `[jest-config, jest-haste-map, jest-resolve, jest-runner, jest-runtime, jest-test-sequencer, jest-transform, jest-types]` [**BREAKING**] Add custom HasteMap class implementation config option ([#11107](https://github.com/facebook/jest/pull/11107))
65
- `[babel-jest]` Add async transformation ([#11192](https://github.com/facebook/jest/pull/11192))
76
- `[jest-changed-files]` Use '--' to separate paths from revisions ([#11160](https://github.com/facebook/jest/pull/11160))
87
- `[jest-circus]` [**BREAKING**] Fail tests when multiple `done()` calls are made ([#10624](https://github.com/facebook/jest/pull/10624))
@@ -13,13 +12,15 @@
1312
- `[jest-config, jest-runtime]` Support ESM for files other than `.js` and `.mjs` ([#10823](https://github.com/facebook/jest/pull/10823))
1413
- `[jest-config, jest-runtime]` [**BREAKING**] Use "modern" implementation as default for fake timers ([#10874](https://github.com/facebook/jest/pull/10874) & [#11197](https://github.com/facebook/jest/pull/11197))
1514
- `[jest-config` Allow passing `forceNodeFilesystemAPI` through to `jest-haste-map` ([#11264](https://github.com/facebook/jest/pull/11264))
15+
- `[jest-config, jest-haste-map, jest-resolve, jest-runner, jest-runtime, jest-test-sequencer, jest-transform, jest-types]` [**BREAKING**] Add custom HasteMap class implementation config option ([#11107](https://github.com/facebook/jest/pull/11107))
1616
- `[jest-core]` make `TestWatcher` extend `emittery` ([#10324](https://github.com/facebook/jest/pull/10324))
1717
- `[jest-core]` Run failed tests interactively the same way we do with snapshots ([#10858](https://github.com/facebook/jest/pull/10858))
1818
- `[jest-core]` more `TestSequencer` methods can be async ([#10980](https://github.com/facebook/jest/pull/10980))
1919
- `[jest-core]` Add support for `testSequencer` written in ESM ([#11207](https://github.com/facebook/jest/pull/11207))
2020
- `[jest-core]` Add support for `globalSetup` and `globalTeardown` written in ESM ([#11267](https://github.com/facebook/jest/pull/11267))
2121
- `[jest-core]` Add support for `watchPlugins` written in ESM ([#11315](https://github.com/facebook/jest/pull/11315))
2222
- `[jest-core]` Add support for `runner` written in ESM ([#11232](https://github.com/facebook/jest/pull/11232))
23+
- `[jest-core]` Add support for `reporters` written in ESM ([#11427](https://github.com/facebook/jest/pull/11427))
2324
- `[jest-each]` Add support for interpolation with object properties ([#11388](https://github.com/facebook/jest/pull/11388))
2425
- `[jest-environment-node]` Add AbortController to globals ([#11182](https://github.com/facebook/jest/pull/11182))
2526
- `[@jest/fake-timers]` Update to `@sinonjs/fake-timers` to v7 ([#11198](https://github.com/facebook/jest/pull/11198))
@@ -117,6 +118,7 @@
117118
- `[babel-jest]` [**BREAKING**] Migrate to ESM ([#11193](https://github.com/facebook/jest/pull/11193))
118119
- `[docs]` Correct example using `browser-resolve` ([#11140](https://github.com/facebook/jest/pull/11140))
119120
- `[docs]` Clarify `timers` configuration property ([#11376](https://github.com/facebook/jest/pull/11376))
121+
- `[jest, jest-core]` [**BREAKING**] Replace `TestScheduler` export with `createTestScheduler` ([#11427](https://github.com/facebook/jest/pull/11427))
120122
- `[jest-config]` [**BREAKING**] Remove `enabledTestsMap` config, use `filter` instead ([#10787](https://github.com/facebook/jest/pull/10787))
121123
- `[jest-console]` [**BREAKING**] Move `root` into `config` and take `GlobalConfig` as mandatory parameter for `getConsoleOutput` ([#10126](https://github.com/facebook/jest/pull/10126))
122124
- `[jest-console]` Export LogEntry ([#11017](https://github.com/facebook/jest/pull/11017))

e2e/__tests__/customReporters.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import {tmpdir} from 'os';
99
import * as path from 'path';
1010
import {wrap} from 'jest-snapshot-serializer-raw';
11+
import {onNodeVersions} from '@jest/test-utils';
1112
import {cleanup, extractSummary, writeFiles} from '../Utils';
1213
import runJest from '../runJest';
1314

@@ -159,4 +160,29 @@ describe('Custom Reporters Integration', () => {
159160
expect(stderr).toMatch(/ON_RUN_START_ERROR/);
160161
expect(exitCode).toBe(1);
161162
});
163+
164+
onNodeVersions('^12.17.0 || >=13.2.0', () => {
165+
test('supports reporter written in ESM', () => {
166+
writeFiles(DIR, {
167+
'__tests__/test.test.js': `test('test', () => {});`,
168+
'package.json': JSON.stringify({
169+
jest: {
170+
reporters: ['default', '<rootDir>/reporter.mjs'],
171+
testEnvironment: 'node',
172+
},
173+
}),
174+
'reporter.mjs': `
175+
export default class Reporter {
176+
onRunStart() {
177+
throw new Error('ON_RUN_START_ERROR');
178+
}
179+
};
180+
`,
181+
});
182+
183+
const {stderr, exitCode} = runJest(DIR);
184+
expect(stderr).toMatch(/ON_RUN_START_ERROR/);
185+
expect(exitCode).toBe(1);
186+
});
187+
});
162188
});

packages/jest-core/src/TestScheduler.ts

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {formatExecError} from 'jest-message-util';
3131
import TestRunner, {Test} from 'jest-runner';
3232
import type {Context} from 'jest-runtime';
3333
import snapshot = require('jest-snapshot');
34-
import {interopRequireDefault} from 'jest-util';
34+
import {requireOrImportModule} from 'jest-util';
3535
import ReporterDispatcher from './ReporterDispatcher';
3636
import type TestWatcher from './TestWatcher';
3737
import {shouldRunInBand} from './testSchedulerHelper';
@@ -49,7 +49,20 @@ export type TestSchedulerContext = {
4949
changedFiles?: Set<Config.Path>;
5050
sourcesRelatedToTestsInChangedFiles?: Set<Config.Path>;
5151
};
52-
export default class TestScheduler {
52+
53+
export async function createTestScheduler(
54+
globalConfig: Config.GlobalConfig,
55+
options: TestSchedulerOptions,
56+
context: TestSchedulerContext,
57+
): Promise<TestScheduler> {
58+
const scheduler = new TestScheduler(globalConfig, options, context);
59+
60+
await scheduler._setupReporters();
61+
62+
return scheduler;
63+
}
64+
65+
class TestScheduler {
5366
private readonly _dispatcher: ReporterDispatcher;
5467
private readonly _globalConfig: Config.GlobalConfig;
5568
private readonly _options: TestSchedulerOptions;
@@ -64,7 +77,6 @@ export default class TestScheduler {
6477
this._globalConfig = globalConfig;
6578
this._options = options;
6679
this._context = context;
67-
this._setupReporters();
6880
}
6981

7082
addReporter(reporter: Reporter): void {
@@ -337,7 +349,7 @@ export default class TestScheduler {
337349
);
338350
}
339351

340-
private _setupReporters() {
352+
async _setupReporters() {
341353
const {collectCoverage, notify, reporters} = this._globalConfig;
342354
const isDefault = this._shouldAddDefaultReporters(reporters);
343355

@@ -366,7 +378,7 @@ export default class TestScheduler {
366378
}
367379

368380
if (reporters && Array.isArray(reporters)) {
369-
this._addCustomReporters(reporters);
381+
await this._addCustomReporters(reporters);
370382
}
371383
}
372384

@@ -390,17 +402,16 @@ export default class TestScheduler {
390402
this.addReporter(new SummaryReporter(this._globalConfig));
391403
}
392404

393-
private _addCustomReporters(
405+
private async _addCustomReporters(
394406
reporters: Array<string | Config.ReporterConfig>,
395407
) {
396-
reporters.forEach(reporter => {
408+
for (const reporter of reporters) {
397409
const {options, path} = this._getReporterProps(reporter);
398410

399-
if (path === 'default') return;
411+
if (path === 'default') continue;
400412

401413
try {
402-
// TODO: Use `requireAndTranspileModule` for Jest 26
403-
const Reporter = interopRequireDefault(require(path)).default;
414+
const Reporter = await requireOrImportModule<any>(path, true);
404415
this.addReporter(new Reporter(this._globalConfig, options));
405416
} catch (error) {
406417
error.message =
@@ -410,7 +421,7 @@ export default class TestScheduler {
410421
error.message;
411422
throw error;
412423
}
413-
});
424+
}
414425
}
415426

416427
/**

packages/jest-core/src/__tests__/TestScheduler.test.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import {SummaryReporter} from '@jest/reporters';
1010
import {makeProjectConfig} from '@jest/test-utils';
11-
import TestScheduler from '../TestScheduler';
11+
import {createTestScheduler} from '../TestScheduler';
1212
import * as testSchedulerHelper from '../testSchedulerHelper';
1313

1414
jest.mock('@jest/reporters');
@@ -35,8 +35,8 @@ beforeEach(() => {
3535
spyShouldRunInBand.mockClear();
3636
});
3737

38-
test('config for reporters supports `default`', () => {
39-
const undefinedReportersScheduler = new TestScheduler(
38+
test('config for reporters supports `default`', async () => {
39+
const undefinedReportersScheduler = await createTestScheduler(
4040
{
4141
reporters: undefined,
4242
},
@@ -45,7 +45,7 @@ test('config for reporters supports `default`', () => {
4545
const numberOfReporters =
4646
undefinedReportersScheduler._dispatcher._reporters.length;
4747

48-
const stringDefaultReportersScheduler = new TestScheduler(
48+
const stringDefaultReportersScheduler = await createTestScheduler(
4949
{
5050
reporters: ['default'],
5151
},
@@ -55,7 +55,7 @@ test('config for reporters supports `default`', () => {
5555
numberOfReporters,
5656
);
5757

58-
const defaultReportersScheduler = new TestScheduler(
58+
const defaultReportersScheduler = await createTestScheduler(
5959
{
6060
reporters: [['default', {}]],
6161
},
@@ -65,7 +65,7 @@ test('config for reporters supports `default`', () => {
6565
numberOfReporters,
6666
);
6767

68-
const emptyReportersScheduler = new TestScheduler(
68+
const emptyReportersScheduler = await createTestScheduler(
6969
{
7070
reporters: [],
7171
},
@@ -74,8 +74,8 @@ test('config for reporters supports `default`', () => {
7474
expect(emptyReportersScheduler._dispatcher._reporters.length).toBe(0);
7575
});
7676

77-
test('.addReporter() .removeReporter()', () => {
78-
const scheduler = new TestScheduler({}, {});
77+
test('.addReporter() .removeReporter()', async () => {
78+
const scheduler = await createTestScheduler({}, {});
7979
const reporter = new SummaryReporter();
8080
scheduler.addReporter(reporter);
8181
expect(scheduler._dispatcher._reporters).toContain(reporter);
@@ -84,7 +84,7 @@ test('.addReporter() .removeReporter()', () => {
8484
});
8585

8686
test('schedule tests run in parallel per default', async () => {
87-
const scheduler = new TestScheduler({}, {});
87+
const scheduler = await createTestScheduler({}, {});
8888
const test = {
8989
context: {
9090
config: makeProjectConfig({
@@ -107,7 +107,7 @@ test('schedule tests run in parallel per default', async () => {
107107
});
108108

109109
test('schedule tests run in serial if the runner flags them', async () => {
110-
const scheduler = new TestScheduler({}, {});
110+
const scheduler = await createTestScheduler({}, {});
111111
const test = {
112112
context: {
113113
config: makeProjectConfig({
@@ -130,7 +130,7 @@ test('schedule tests run in serial if the runner flags them', async () => {
130130
});
131131

132132
test('should bail after `n` failures', async () => {
133-
const scheduler = new TestScheduler({bail: 2}, {});
133+
const scheduler = await createTestScheduler({bail: 2}, {});
134134
const test = {
135135
context: {
136136
config: makeProjectConfig({
@@ -162,7 +162,7 @@ test('should bail after `n` failures', async () => {
162162
});
163163

164164
test('should not bail if less than `n` failures', async () => {
165-
const scheduler = new TestScheduler({bail: 2}, {});
165+
const scheduler = await createTestScheduler({bail: 2}, {});
166166
const test = {
167167
context: {
168168
config: makeProjectConfig({
@@ -194,7 +194,7 @@ test('should not bail if less than `n` failures', async () => {
194194
});
195195

196196
test('should set runInBand to run in serial', async () => {
197-
const scheduler = new TestScheduler({}, {});
197+
const scheduler = await createTestScheduler({}, {});
198198
const test = {
199199
context: {
200200
config: makeProjectConfig({
@@ -220,7 +220,7 @@ test('should set runInBand to run in serial', async () => {
220220
});
221221

222222
test('should set runInBand to not run in serial', async () => {
223-
const scheduler = new TestScheduler({}, {});
223+
const scheduler = await createTestScheduler({}, {});
224224
const test = {
225225
context: {
226226
config: makeProjectConfig({

packages/jest-core/src/jest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
export {default as SearchSource} from './SearchSource';
9-
export {default as TestScheduler} from './TestScheduler';
9+
export {createTestScheduler} from './TestScheduler';
1010
export {default as TestWatcher} from './TestWatcher';
1111
export {runCLI} from './cli';
1212
export {default as getVersion} from './version';

packages/jest-core/src/runJest.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {requireOrImportModule, tryRealpath} from 'jest-util';
2424
import {JestHook, JestHookEmitter} from 'jest-watcher';
2525
import type FailedTestsCache from './FailedTestsCache';
2626
import SearchSource from './SearchSource';
27-
import TestScheduler, {TestSchedulerContext} from './TestScheduler';
27+
import {TestSchedulerContext, createTestScheduler} from './TestScheduler';
2828
import type TestWatcher from './TestWatcher';
2929
import collectNodeHandles, {HandleCollectionResult} from './collectHandles';
3030
import getNoTestsFoundMessage from './getNoTestsFoundMessage';
@@ -268,11 +268,13 @@ export default async function runJest({
268268
}
269269
}
270270

271-
const results = await new TestScheduler(
271+
const scheduler = await createTestScheduler(
272272
globalConfig,
273273
{startRun},
274274
testSchedulerContext,
275-
).scheduleTests(allTests, testWatcher);
275+
);
276+
277+
const results = await scheduler.scheduleTests(allTests, testWatcher);
276278

277279
await sequencer.cacheResults(allTests, results);
278280

packages/jest/src/jest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77

88
export {
99
SearchSource,
10-
TestScheduler,
1110
TestWatcher,
11+
createTestScheduler,
1212
getVersion,
1313
runCLI,
1414
} from '@jest/core';

0 commit comments

Comments
 (0)