Skip to content

Commit

Permalink
chore: upgrade to Jest 28 (#113)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrazauskas authored May 6, 2022
1 parent 6237176 commit 977e592
Show file tree
Hide file tree
Showing 10 changed files with 542 additions and 1,047 deletions.
6 changes: 0 additions & 6 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
{
"editor.rulers": [80],
"files.exclude": {
"**/.git": true,
"**/node_modules": true,
"**/build": true
},
"prettier.parser": "flow",
"prettier.printWidth": 80,
"prettier.singleQuote": true,
"prettier.trailingComma": "all",
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ module.exports = createJestRunner(require.resolve('./run'));
const fs = require('fs');
const { pass, fail } = require('create-jest-runner');

module.exports = ({ testPath }) => {
/** @type {import('create-jest-runner').RunTest} */
const runTest = ({ testPath }) => {
const start = Date.now();
const contents = fs.readFileSync(testPath, 'utf8');
const end = Date.now();
Expand All @@ -86,6 +87,8 @@ module.exports = ({ testPath }) => {
test: { path: testPath, errorMessage, title: 'Check for ⚔️ 🏃' },
});
};

module.exports = runTest;
```

## Create runner from binary
Expand All @@ -97,8 +100,7 @@ yarn create jest-runner my-runner
npm init jest-runner my-runner
```

**Note:** You will have to update the package name in `package.json` of the
generated runner
**Note:** You will have to update the package name in `package.json` of the generated runner.

## Add your runner to Jest config

Expand Down
7 changes: 5 additions & 2 deletions integrationTests/runner/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ const fs = require('fs');
// eslint-disable-next-line import/extensions, import/no-unresolved -- ignore build artifact
const { pass, fail, skip, todo } = require('../..');

module.exports = ({ testPath }) => {
/** @type {import('../..').RunTest} */
const runTest = ({ testPath }) => {
const start = Date.now();
// we don't want the timestamp in teh reporter result for our snapshots
// we don't want the timestamp in the reporter result for our snapshots
const end = start;
const contents = fs.readFileSync(testPath, 'utf8');

Expand All @@ -24,3 +25,5 @@ module.exports = ({ testPath }) => {
test: { path: testPath, errorMessage, title: 'Check for ⚔️ 🏃' },
});
};

module.exports = runTest;
82 changes: 41 additions & 41 deletions lib/createJestRunner.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import type { Config } from '@jest/types';
import type { TestResult } from '@jest/test-result';
import type * as JestRunner from 'jest-runner';
import { Worker } from 'jest-worker';
import {
CallbackTestRunner,
OnTestFailure,
OnTestStart,
OnTestSuccess,
Test,
TestRunnerOptions,
TestWatcher,
} from 'jest-runner';
import { Worker, JestWorkerFarm } from 'jest-worker';
import throat from 'throat';
import type { CreateRunnerOptions, Path, TestRunner } from './types';
import type { CreateRunnerOptions, RunTestOptions } from './types';

function determineSlowTestResult(
test: JestRunner.Test,
result: TestResult,
): TestResult {
function determineSlowTestResult(test: Test, result: TestResult): TestResult {
// See: https://github.com/facebook/jest/blob/acd7c83c8365140f4ecf44a456ff7366ffa31fa2/packages/jest-runner/src/runTest.ts#L287
if (result.perfStats.runtime / 1000 > test.context.config.slowTestThreshold) {
return { ...result, perfStats: { ...result.perfStats, slow: true } };
Expand All @@ -24,24 +28,19 @@ class CancelRun extends Error {
}

export default function createRunner<
ExtraOptionsType extends Record<string, unknown>,
ExtraOptions extends Record<string, unknown>,
>(
runPath: Path,
{ getExtraOptions }: CreateRunnerOptions<ExtraOptionsType> = {},
): typeof TestRunner {
return class BaseTestRunner implements TestRunner {
constructor(
public readonly _globalConfig: Config.GlobalConfig,
public readonly _context: JestRunner.TestRunnerContext = {},
) {}

runPath: string,
{ getExtraOptions }: CreateRunnerOptions<ExtraOptions> = {},
): typeof CallbackTestRunner {
return class BaseTestRunner extends CallbackTestRunner {
runTests(
tests: Array<JestRunner.Test>,
watcher: JestRunner.TestWatcher,
onStart: JestRunner.OnTestStart,
onResult: JestRunner.OnTestSuccess,
onFailure: JestRunner.OnTestFailure,
options: JestRunner.TestRunnerOptions,
tests: Array<Test>,
watcher: TestWatcher,
onStart: OnTestStart,
onResult: OnTestSuccess,
onFailure: OnTestFailure,
options: TestRunnerOptions,
): Promise<void> {
return options.serial
? this._createInBandTestRun(
Expand All @@ -63,12 +62,12 @@ export default function createRunner<
}

_createInBandTestRun(
tests: Array<JestRunner.Test>,
watcher: JestRunner.TestWatcher,
onStart: JestRunner.OnTestStart,
onResult: JestRunner.OnTestSuccess,
onFailure: JestRunner.OnTestFailure,
options: JestRunner.TestRunnerOptions,
tests: Array<Test>,
watcher: TestWatcher,
onStart: OnTestStart,
onResult: OnTestSuccess,
onFailure: OnTestFailure,
options: TestRunnerOptions,
): Promise<void> {
const mutex = throat(1);
return tests.reduce(
Expand Down Expand Up @@ -110,29 +109,31 @@ export default function createRunner<
}

_createParallelTestRun(
tests: Array<JestRunner.Test>,
watcher: JestRunner.TestWatcher,
onStart: JestRunner.OnTestStart,
onResult: JestRunner.OnTestSuccess,
onFailure: JestRunner.OnTestFailure,
options: JestRunner.TestRunnerOptions,
tests: Array<Test>,
watcher: TestWatcher,
onStart: OnTestStart,
onResult: OnTestSuccess,
onFailure: OnTestFailure,
options: TestRunnerOptions,
): Promise<void> {
const worker = new Worker(runPath, {
exposedMethods: ['default'],
numWorkers: this._globalConfig.maxWorkers,
forkOptions: { stdio: 'inherit' },
});
}) as JestWorkerFarm<{
default: (runTestOptions: RunTestOptions) => TestResult;
}>;

const mutex = throat(this._globalConfig.maxWorkers);

const runTestInWorker = (test: JestRunner.Test) =>
const runTestInWorker = (test: Test) =>
mutex(() => {
if (watcher.isInterrupted()) {
throw new CancelRun();
}

return onStart(test).then(() => {
const baseOptions = {
const runTestOptions: RunTestOptions = {
config: test.context.config,
globalConfig: this._globalConfig,
testPath: test.path,
Expand All @@ -143,8 +144,7 @@ export default function createRunner<
extraOptions: getExtraOptions ? getExtraOptions() : {},
};

// @ts-expect-error -- the required module should have a default export
return worker.default(baseOptions);
return worker.default(runTestOptions);
});
});

Expand Down
9 changes: 4 additions & 5 deletions lib/fail.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import type { TestResult } from '@jest/test-result';
import toTestResult from './toTestResult';
import type { Path } from './types';

interface Options {
start: number;
end: number;
test: { title: string; path: Path; errorMessage?: string };
test: { title: string; path: string; errorMessage?: string };
errorMessage?: string;
}

export default function fail(options: {
start: number;
end: number;
test: { title: string; path: Path; errorMessage: string };
test: { title: string; path: string; errorMessage: string };
}): TestResult;

export default function fail(options: {
start: number;
end: number;
test: { title: string; path: Path };
test: { title: string; path: string };
errorMessage: string;
}): TestResult;

Expand All @@ -30,7 +29,7 @@ export default function fail({
}: Options): TestResult {
// TODO: Currently the `fail` function allows 2 ways to pass an error message.
// Both methods are currently in used by downstream packages.
// The current behaviour is to favour `errorMessage` over `test.errorMessage`.
// The current behavior is to favour `errorMessage` over `test.errorMessage`.
const actualErrorMessage = errorMessage || test.errorMessage;

return toTestResult({
Expand Down
2 changes: 2 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export { default as fail } from './fail';
export { default as pass } from './pass';
export { default as skip } from './skip';
export { default as todo } from './todo';

export type { RunTest, RunTestOptions } from './types';
3 changes: 1 addition & 2 deletions lib/toTestResult.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { TestResult } from '@jest/test-result';
import type { Milliseconds } from './types';

interface Options {
stats: {
Expand All @@ -13,7 +12,7 @@ interface Options {
skipped: boolean;
errorMessage?: string | null;
tests: Array<{
duration?: Milliseconds | null;
duration?: number | null;
errorMessage?: string;
testPath?: string;
title?: string;
Expand Down
56 changes: 21 additions & 35 deletions lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,28 @@
// Common type aliases for better code readability

import type {
Config as JestConfig,
TestResult as JestTestResult,
} from '@jest/types';
import type * as JestRunner from 'jest-runner';

export type Milliseconds = JestTestResult.Milliseconds;
export type Path = JestConfig.Path;

export interface TestDetail {
title: string;
path: Path;
}
import type { TestContext, TestResult } from '@jest/test-result';
import type { Config, TestRunnerOptions } from 'jest-runner';

export interface CreateRunnerOptions<
ExtraOptionsType extends Record<string, unknown>,
ExtraOptions extends Record<string, unknown>,
> {
getExtraOptions?: () => ExtraOptionsType;
getExtraOptions?: () => ExtraOptions;
}

// Copied and adapted from https://github.com/facebook/jest/blob/2dafb09d51584d3785f3280f569784ec4334b5d8/packages/jest-runner/src/index.ts#L48-L285
export declare abstract class TestRunner {
readonly _globalConfig: JestConfig.GlobalConfig;

readonly _context: JestRunner.TestRunnerContext;

constructor(
globalConfig: JestConfig.GlobalConfig,
context?: JestRunner.TestRunnerContext,
);
export type RunTestOptions<
ExtraOptions extends Record<string, unknown> = Record<string, unknown>,
> = {
config: Config.ProjectConfig;
extraOptions: ExtraOptions;
globalConfig: Config.GlobalConfig;
rawModuleMap: ReturnType<TestContext['moduleMap']['getRawModuleMap']> | null;
options: TestRunnerOptions;
testPath: string;
};

export type RunTest<
ExtraOptions extends Record<string, unknown> = Record<string, unknown>,
> = (options: RunTestOptions<ExtraOptions>) => TestResult | Promise<TestResult>;

runTests(
tests: Array<JestRunner.Test>,
watcher: JestRunner.TestWatcher,
onStart: JestRunner.OnTestStart,
onResult: JestRunner.OnTestSuccess,
onFailure: JestRunner.OnTestFailure,
options: JestRunner.TestRunnerOptions,
): Promise<void>;
export interface TestDetail {
title: string;
path: string;
}
19 changes: 7 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,46 +31,41 @@
},
"dependencies": {
"chalk": "^4.1.0",
"jest-worker": "^27.0.6",
"jest-worker": "^28.0.2",
"throat": "^6.0.1"
},
"devDependencies": {
"@babel/cli": "^7.0.0",
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-typescript": "^7.0.0",
"@jest/test-result": "^27.0.6",
"@jest/types": "^27.0.6",
"@jest/test-result": "^28.0.2",
"@tsconfig/node12": "^1.0.9",
"@types/node": "^16.11.4",
"@typescript-eslint/eslint-plugin": "^5.14.0",
"@typescript-eslint/parser": "^5.14.0",
"babel-jest": "^27.0.6",
"babel-jest": "^28.0.3",
"eslint": "^8.10.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jest": "^26.1.1",
"eslint-plugin-prettier": "^4.0.0",
"execa": "^5.0.0",
"jest": "^27.0.6",
"jest-runner": "^27.0.6",
"jest": "^28.0.3",
"jest-runner": "^28.0.3",
"prettier": "^2.0.5",
"strip-ansi": "^6.0.0",
"typescript": "^4.3.5"
},
"peerDependencies": {
"@jest/test-result": "^27.0.0",
"@jest/types": "^27.0.0",
"jest-runner": "^27.0.0"
"@jest/test-result": "^28.0.0",
"jest-runner": "^28.0.0"
},
"peerDependenciesMeta": {
"@jest/test-result": {
"optional": true
},
"@jest/types": {
"optional": true
},
"jest-runner": {
"optional": true
}
Expand Down
Loading

0 comments on commit 977e592

Please sign in to comment.