Skip to content

Commit c5a8369

Browse files
authored
feat: migrate lib to typescript (#40)
1 parent 346c650 commit c5a8369

23 files changed

+449
-222
lines changed

.babelrc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
"node": "10"
88
}
99
}
10+
],
11+
[
12+
"@babel/preset-typescript",
13+
{
14+
"allowDeclareFields": true
15+
}
1016
]
1117
]
1218
}

.eslintignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
**/node_modules
22
build
33
.yarn/
4-
# remove after migrating to TS
5-
types/

.eslintrc.json

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,26 @@
22
"extends": [
33
"airbnb-base",
44
"plugin:@typescript-eslint/recommended",
5+
"plugin:import/typescript",
56
"plugin:prettier/recommended"
67
],
78
"plugins": ["jest"],
89
"rules": {
9-
"no-underscore-dangle": "off",
10+
"import/export": "off",
11+
"import/extensions": [
12+
"error",
13+
"ignorePackages",
14+
{
15+
"js": "never",
16+
"mjs": "never",
17+
"jsx": "never",
18+
"ts": "never"
19+
}
20+
],
1021
"max-classes-per-file": "off",
11-
"@typescript-eslint/prefer-ts-expect-error": "error",
12-
// TODO: turn on after migrating to TS
13-
"@typescript-eslint/no-var-requires": "off",
14-
"@typescript-eslint/explicit-module-boundary-types": "off"
22+
"no-underscore-dangle": "off",
23+
"no-useless-constructor": "off",
24+
"@typescript-eslint/prefer-ts-expect-error": "error"
1525
},
1626
"env": {
1727
"jest/globals": true
@@ -28,6 +38,14 @@
2838
"rules": {
2939
"no-console": "off"
3040
}
41+
},
42+
{
43+
// TODO: remove after migrating to TS
44+
"files": "**/*.js",
45+
"rules": {
46+
"@typescript-eslint/no-var-requires": "off",
47+
"@typescript-eslint/explicit-module-boundary-types": "off"
48+
}
3149
}
3250
]
3351
}

.github/workflows/nodejs.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ jobs:
2323
run: yarn
2424
- name: build
2525
run: yarn build
26+
- name: build types
27+
run: yarn build-types
2628
- name: run eslint
2729
run: yarn lint
2830
- name: run prettier
@@ -46,6 +48,8 @@ jobs:
4648
run: yarn
4749
- name: build
4850
run: yarn build
51+
- name: build types
52+
run: yarn build-types
4953
- name: run tests
5054
run: yarn test
5155
env:
@@ -68,6 +72,8 @@ jobs:
6872
run: yarn
6973
- name: build
7074
run: yarn build
75+
- name: build types
76+
run: yarn build-types
7177
- name: run tests
7278
run: yarn test
7379
env:

integrationTests/runner/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// eslint-disable-next-line import/extensions, import/no-unresolved -- ignore build artifact
12
const { createJestRunner } = require('../..');
23

34
module.exports = createJestRunner(require.resolve('./run'));

integrationTests/runner/run.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const fs = require('fs');
2+
// eslint-disable-next-line import/extensions, import/no-unresolved -- ignore build artifact
23
const { pass, fail, skip, todo } = require('../..');
34

45
module.exports = ({ testPath }) => {

lib/createJestRunner.js renamed to lib/createJestRunner.ts

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,37 @@
1-
import throat from 'throat';
1+
import type * as JestResult from '@jest/test-result';
2+
import type { Config } from '@jest/types';
3+
import type * as JestRunner from 'jest-runner';
24
import { Worker } from 'jest-worker';
5+
import throat from 'throat';
6+
import type { CreateRunnerOptions, Path, TestRunner } from './types';
37

48
class CancelRun extends Error {
5-
constructor(message) {
9+
constructor(message?: string) {
610
super(message);
711
this.name = 'CancelRun';
812
}
913
}
1014

11-
const createRunner = (runPath, { getExtraOptions } = {}) => {
12-
class BaseTestRunner {
13-
constructor(globalConfig) {
14-
this._globalConfig = globalConfig;
15-
}
16-
17-
runTests(tests, watcher, onStart, onResult, onFailure, options) {
15+
export default function createRunner<
16+
ExtraOptionsType extends Record<string, unknown>,
17+
>(
18+
runPath: Path,
19+
{ getExtraOptions }: CreateRunnerOptions<ExtraOptionsType> = {},
20+
): typeof TestRunner {
21+
return class BaseTestRunner implements TestRunner {
22+
constructor(
23+
public readonly _globalConfig: Config.GlobalConfig,
24+
public readonly _context: JestRunner.TestRunnerContext = {},
25+
) {}
26+
27+
runTests(
28+
tests: Array<JestRunner.Test>,
29+
watcher: JestRunner.TestWatcher,
30+
onStart: JestRunner.OnTestStart,
31+
onResult: JestRunner.OnTestSuccess,
32+
onFailure: JestRunner.OnTestFailure,
33+
options: JestRunner.TestRunnerOptions,
34+
): Promise<void> {
1835
return options.serial
1936
? this._createInBandTestRun(
2037
tests,
@@ -35,13 +52,13 @@ const createRunner = (runPath, { getExtraOptions } = {}) => {
3552
}
3653

3754
_createInBandTestRun(
38-
tests,
39-
watcher,
40-
onStart,
41-
onResult,
42-
onFailure,
43-
options,
44-
) {
55+
tests: Array<JestRunner.Test>,
56+
watcher: JestRunner.TestWatcher,
57+
onStart: JestRunner.OnTestStart,
58+
onResult: JestRunner.OnTestSuccess,
59+
onFailure: JestRunner.OnTestFailure,
60+
options: JestRunner.TestRunnerOptions,
61+
): Promise<void> {
4562
const mutex = throat(1);
4663
return tests.reduce(
4764
(promise, test) =>
@@ -53,7 +70,7 @@ const createRunner = (runPath, { getExtraOptions } = {}) => {
5370
}
5471

5572
return onStart(test).then(() => {
56-
// eslint-disable-next-line import/no-dynamic-require, global-require
73+
// eslint-disable-next-line import/no-dynamic-require, global-require, @typescript-eslint/no-var-requires
5774
const runner = require(runPath);
5875
const baseOptions = {
5976
config: test.context.config,
@@ -81,13 +98,13 @@ const createRunner = (runPath, { getExtraOptions } = {}) => {
8198
}
8299

83100
_createParallelTestRun(
84-
tests,
85-
watcher,
86-
onStart,
87-
onResult,
88-
onFailure,
89-
options,
90-
) {
101+
tests: Array<JestRunner.Test>,
102+
watcher: JestRunner.TestWatcher,
103+
onStart: JestRunner.OnTestStart,
104+
onResult: JestRunner.OnTestSuccess,
105+
onFailure: JestRunner.OnTestFailure,
106+
options: JestRunner.TestRunnerOptions,
107+
): Promise<void> {
91108
const worker = new Worker(runPath, {
92109
exposedMethods: ['default'],
93110
numWorkers: this._globalConfig.maxWorkers,
@@ -96,7 +113,7 @@ const createRunner = (runPath, { getExtraOptions } = {}) => {
96113

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

99-
const runTestInWorker = test =>
116+
const runTestInWorker = (test: JestRunner.Test) =>
100117
mutex(() => {
101118
if (watcher.isInterrupted()) {
102119
throw new CancelRun();
@@ -114,12 +131,16 @@ const createRunner = (runPath, { getExtraOptions } = {}) => {
114131
extraOptions: getExtraOptions ? getExtraOptions() : {},
115132
};
116133

134+
// @ts-expect-error -- the required module should have a default export
117135
return worker.default(baseOptions);
118136
});
119137
});
120138

121-
const onError = (err, test) =>
122-
onFailure(test, err).then(() => {
139+
const onError = (
140+
err: JestResult.SerializableError,
141+
test: JestRunner.Test,
142+
) => {
143+
return onFailure(test, err).then(() => {
123144
if (err.type === 'ProcessTerminatedError') {
124145
// eslint-disable-next-line no-console
125146
console.error(
@@ -129,6 +150,7 @@ const createRunner = (runPath, { getExtraOptions } = {}) => {
129150
process.exit(1);
130151
}
131152
});
153+
};
132154

133155
const onInterrupt = new Promise((_, reject) => {
134156
watcher.on('change', state => {
@@ -146,13 +168,11 @@ const createRunner = (runPath, { getExtraOptions } = {}) => {
146168
),
147169
);
148170

149-
const cleanup = () => worker.end();
171+
const cleanup = () => {
172+
worker.end();
173+
};
150174

151175
return Promise.race([runAllTests, onInterrupt]).then(cleanup, cleanup);
152176
}
153-
}
154-
155-
return BaseTestRunner;
156-
};
157-
158-
export default createRunner;
177+
};
178+
}

lib/fail.js

Lines changed: 0 additions & 18 deletions
This file was deleted.

lib/fail.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type { TestResult } from '@jest/test-result';
2+
import toTestResult from './toTestResult';
3+
import type { Path } from './types';
4+
5+
interface Options {
6+
start: number;
7+
end: number;
8+
test: { title: string; path: Path; errorMessage?: string };
9+
errorMessage?: string;
10+
}
11+
12+
export default function fail(options: {
13+
start: number;
14+
end: number;
15+
test: { title: string; path: Path; errorMessage: string };
16+
}): TestResult;
17+
18+
export default function fail(options: {
19+
start: number;
20+
end: number;
21+
test: { title: string; path: Path };
22+
errorMessage: string;
23+
}): TestResult;
24+
25+
export default function fail({
26+
start,
27+
end,
28+
test,
29+
errorMessage,
30+
}: Options): TestResult {
31+
// TODO: Currently the `fail` function allows 2 ways to pass an error message.
32+
// Both methods are currently in used by downstream packages.
33+
// The current behaviour is to favour `errorMessage` over `test.errorMessage`.
34+
const actualErrorMessage = errorMessage || test.errorMessage;
35+
36+
return toTestResult({
37+
errorMessage: actualErrorMessage,
38+
stats: {
39+
failures: 1,
40+
pending: 0,
41+
passes: 0,
42+
todo: 0,
43+
start,
44+
end,
45+
},
46+
skipped: false,
47+
tests: [
48+
{ duration: end - start, ...test, errorMessage: actualErrorMessage },
49+
],
50+
jestTestPath: test.path,
51+
});
52+
}
File renamed without changes.

lib/pass.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

lib/pass.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { TestResult } from '@jest/test-result';
2+
import toTestResult from './toTestResult';
3+
import type { TestDetail } from './types';
4+
5+
interface Options {
6+
start: number;
7+
end: number;
8+
test: TestDetail;
9+
}
10+
11+
export default function pass({ start, end, test }: Options): TestResult {
12+
return toTestResult({
13+
stats: {
14+
failures: 0,
15+
pending: 0,
16+
passes: 1,
17+
todo: 0,
18+
start,
19+
end,
20+
},
21+
skipped: false,
22+
tests: [{ duration: end - start, ...test }],
23+
jestTestPath: test.path,
24+
});
25+
}

lib/skip.js

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)