Skip to content

Commit

Permalink
Migrate jest-runner to typescript (#7968)
Browse files Browse the repository at this point in the history
  • Loading branch information
natealcedo authored and SimenB committed Feb 25, 2019
1 parent 5d48312 commit af669ef
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 95 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -56,6 +56,7 @@
- `[expect]`: Migrate to TypeScript ([#7919](https://github.com/facebook/jest/pull/7919))
- `[jest-circus]`: Migrate to TypeScript ([#7916](https://github.com/facebook/jest/pull/7916))
- `[jest-phabricator]`: Migrate to TypeScript ([#7965](https://github.com/facebook/jest/pull/7965))
- `[jest-runner]`: Migrate to TypeScript ([#7968](https://github.com/facebook/jest/pull/7968))

### Performance

Expand Down
3 changes: 3 additions & 0 deletions packages/jest-runner/package.json
Expand Up @@ -8,7 +8,9 @@
},
"license": "MIT",
"main": "build/index.js",
"types": "build/index.d.ts",
"dependencies": {
"@jest/types": "^24.1.0",
"chalk": "^2.4.2",
"exit": "^0.1.2",
"graceful-fs": "^4.1.15",
Expand All @@ -18,6 +20,7 @@
"jest-jasmine2": "^24.1.0",
"jest-leak-detector": "^24.0.0",
"jest-message-util": "^24.0.0",
"jest-resolve": "^24.1.0",
"jest-runtime": "^24.1.0",
"jest-util": "^24.0.0",
"jest-worker": "^24.0.0",
Expand Down
1 change: 0 additions & 1 deletion packages/jest-runner/src/__tests__/testRunner.test.js
Expand Up @@ -7,7 +7,6 @@
*/

import {TestWatcher} from '@jest/core';
// eslint-disable-next-line import/default
import TestRunner from '../index';

let mockWorkerFarm;
Expand Down
Expand Up @@ -3,37 +3,36 @@
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import type {GlobalConfig} from 'types/Config';
import type {
import {Config, TestResult} from '@jest/types';
import exit from 'exit';
import throat from 'throat';
import Worker from 'jest-worker';
import runTest from './runTest';
import {worker} from './testWorker';
import {
OnTestFailure,
OnTestStart,
OnTestSuccess,
Test,
TestRunnerContext,
TestRunnerOptions,
TestWatcher,
} from 'types/TestRunner';

import typeof {worker} from './testWorker';

import exit from 'exit';
import runTest from './runTest';
import throat from 'throat';
import Worker from 'jest-worker';
WatcherState,
} from './types';

const TEST_WORKER_PATH = require.resolve('./testWorker');

type WorkerInterface = Worker & {worker: worker};
interface WorkerInterface extends Worker {
worker: typeof worker;
}

class TestRunner {
_globalConfig: GlobalConfig;
_context: TestRunnerContext;
private _globalConfig: Config.GlobalConfig;
private _context: TestRunnerContext;

constructor(globalConfig: GlobalConfig, context?: TestRunnerContext) {
constructor(globalConfig: Config.GlobalConfig, context?: TestRunnerContext) {
this._globalConfig = globalConfig;
this._context = context || {};
}
Expand All @@ -57,7 +56,7 @@ class TestRunner {
));
}

async _createInBandTestRun(
private async _createInBandTestRun(
tests: Array<Test>,
watcher: TestWatcher,
onStart: OnTestStart,
Expand Down Expand Up @@ -91,19 +90,19 @@ class TestRunner {
);
}

async _createParallelTestRun(
private async _createParallelTestRun(
tests: Array<Test>,
watcher: TestWatcher,
onStart: OnTestStart,
onResult: OnTestSuccess,
onFailure: OnTestFailure,
) {
const worker: WorkerInterface = new Worker(TEST_WORKER_PATH, {
const worker = new Worker(TEST_WORKER_PATH, {
exposedMethods: ['worker'],
forkOptions: {stdio: 'pipe'},
maxRetries: 3,
numWorkers: this._globalConfig.maxWorkers,
});
}) as WorkerInterface;

if (worker.getStdout()) worker.getStdout().pipe(process.stdout);
if (worker.getStderr()) worker.getStderr().pipe(process.stderr);
Expand All @@ -112,7 +111,7 @@ class TestRunner {

// Send test suites to workers continuously instead of all at once to track
// the start time of individual tests.
const runTestInWorker = test =>
const runTestInWorker = (test: Test) =>
mutex(async () => {
if (watcher.isInterrupted()) {
return Promise.reject();
Expand All @@ -131,7 +130,7 @@ class TestRunner {
});
});

const onError = async (err, test) => {
const onError = async (err: TestResult.SerializableError, test: Test) => {
await onFailure(test, err);
if (err.type === 'ProcessTerminatedError') {
console.error(
Expand All @@ -143,7 +142,7 @@ class TestRunner {
};

const onInterrupt = new Promise((_, reject) => {
watcher.on('change', state => {
watcher.on('change', (state: WatcherState) => {
if (state.interrupted) {
reject(new CancelRun());
}
Expand All @@ -164,10 +163,10 @@ class TestRunner {
}

class CancelRun extends Error {
constructor(message: ?string) {
constructor(message?: string) {
super(message);
this.name = 'CancelRun';
}
}

module.exports = TestRunner;
export = TestRunner;
Expand Up @@ -4,16 +4,16 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import type {EnvironmentClass} from 'types/Environment';
import type {GlobalConfig, Path, ProjectConfig} from 'types/Config';
import type {Resolver} from 'types/Resolve';
import type {TestFramework, TestRunnerContext} from 'types/TestRunner';
import type {TestResult} from 'types/TestResult';
import type RuntimeClass from 'jest-runtime';

import {
Environment,
Config,
TestResult,
Console as ConsoleType,
} from '@jest/types';
// @ts-ignore: not migrated to TS
import RuntimeClass from 'jest-runtime';
import fs from 'graceful-fs';
import {
BufferedConsole,
Expand All @@ -24,22 +24,31 @@ import {
setGlobal,
} from 'jest-util';
import LeakDetector from 'jest-leak-detector';
import Resolver from 'jest-resolve';
// @ts-ignore: not migrated to TS
import {getTestEnvironment} from 'jest-config';
import * as docblock from 'jest-docblock';
import {formatExecError} from 'jest-message-util';
import sourcemapSupport from 'source-map-support';
import sourcemapSupport, {
Options as SourceMapOptions,
} from 'source-map-support';
import chalk from 'chalk';
import {TestFramework, TestRunnerContext} from './types';

type RunTestInternalResult = {
leakDetector: ?LeakDetector,
result: TestResult,
leakDetector: LeakDetector | null;
result: TestResult.TestResult;
};

function freezeConsole(
// @ts-ignore: Correct types when `jest-util` is ESM
testConsole: BufferedConsole | Console | NullConsole,
config: ProjectConfig,
config: Config.ProjectConfig,
) {
testConsole._log = function fakeConsolePush(_type, message) {
testConsole._log = function fakeConsolePush(
_type: ConsoleType.LogType,
message: ConsoleType.LogMessage,
) {
const error = new ErrorWithStack(
`${chalk.red(
`${chalk.bold(
Expand Down Expand Up @@ -73,11 +82,11 @@ function freezeConsole(
// references to verify if there is a leak, which is not maintainable and error
// prone. That's why "runTestInternal" CANNOT be inlined inside "runTest".
async function runTestInternal(
path: Path,
globalConfig: GlobalConfig,
config: ProjectConfig,
path: Config.Path,
globalConfig: Config.GlobalConfig,
config: Config.ProjectConfig,
resolver: Resolver,
context: ?TestRunnerContext,
context?: TestRunnerContext,
): Promise<RunTestInternalResult> {
const testSource = fs.readFileSync(path, 'utf8');
const parsedDocblock = docblock.parse(docblock.extract(testSource));
Expand All @@ -92,21 +101,22 @@ async function runTestInternal(
});
}

/* $FlowFixMe */
const TestEnvironment = (require(testEnvironment): EnvironmentClass);
const testFramework = ((process.env.JEST_CIRCUS === '1'
? require('jest-circus/runner') // eslint-disable-line import/no-extraneous-dependencies
: /* $FlowFixMe */
require(config.testRunner)): TestFramework);
const Runtime = ((config.moduleLoader
? /* $FlowFixMe */
require(config.moduleLoader)
: require('jest-runtime')): Class<RuntimeClass>);
const TestEnvironment: Environment.EnvironmentClass = require(testEnvironment);
const testFramework: TestFramework =
process.env.JEST_CIRCUS === '1'
? require('jest-circus/runner') // eslint-disable-line import/no-extraneous-dependencies
: require(config.testRunner);
const Runtime: RuntimeClass = config.moduleLoader
? require(config.moduleLoader)
: require('jest-runtime');

let runtime = undefined;
let runtime: RuntimeClass = undefined;

const consoleOut = globalConfig.useStderr ? process.stderr : process.stdout;
const consoleFormatter = (type, message) =>
const consoleFormatter = (
type: ConsoleType.LogType,
message: ConsoleType.LogMessage,
) =>
getConsoleOutput(
config.cwd,
!!globalConfig.verbose,
Expand Down Expand Up @@ -150,7 +160,7 @@ async function runTestInternal(

const start = Date.now();

const sourcemapOptions = {
const sourcemapOptions: SourceMapOptions = {
environment: 'node',
handleUncaughtExceptions: false,
retrieveSourceMap: source => {
Expand All @@ -160,7 +170,7 @@ async function runTestInternal(
if (sourceMapSource) {
try {
return {
map: JSON.parse(fs.readFileSync(sourceMapSource)),
map: JSON.parse(fs.readFileSync(sourceMapSource, 'utf8')),
url: source,
};
} catch (e) {}
Expand All @@ -187,7 +197,7 @@ async function runTestInternal(
) {
const realExit = environment.global.process.exit;

environment.global.process.exit = function exit(...args) {
environment.global.process.exit = function exit(...args: Array<any>) {
const error = new ErrorWithStack(
`process.exit called with "${args.join(', ')}"`,
exit,
Expand All @@ -210,7 +220,7 @@ async function runTestInternal(
try {
await environment.setup();

let result: TestResult;
let result: TestResult.TestResult;

try {
result = await testFramework(
Expand Down Expand Up @@ -259,17 +269,18 @@ async function runTestInternal(
} finally {
await environment.teardown();

// @ts-ignore: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/33351
sourcemapSupport.resetRetrieveHandlers();
}
}

export default async function runTest(
path: Path,
globalConfig: GlobalConfig,
config: ProjectConfig,
path: Config.Path,
globalConfig: Config.GlobalConfig,
config: Config.ProjectConfig,
resolver: Resolver,
context: ?TestRunnerContext,
): Promise<TestResult> {
context?: TestRunnerContext,
): Promise<TestResult.TestResult> {
const {leakDetector, result} = await runTestInternal(
path,
globalConfig,
Expand Down

0 comments on commit af669ef

Please sign in to comment.