diff --git a/CHANGELOG.md b/CHANGELOG.md index a19a6ca80c55..c910de37cdc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - `[jest-util]`: Migrate to TypeScript ([#7844](https://github.com/facebook/jest/pull/7844)) - `[jest-watcher]`: Migrate to TypeScript ([#7843](https://github.com/facebook/jest/pull/7843)) - `[jest-mock]`: Migrate to TypeScript ([#7847](https://github.com/facebook/jest/pull/7847), [#7850](https://github.com/facebook/jest/pull/7850)) +- `[jest-worker]`: Migrate to TypeScript ([#7853](https://github.com/facebook/jest/pull/7853)) ### Performance diff --git a/packages/jest-cli/src/reporters/coverage_reporter.js b/packages/jest-cli/src/reporters/coverage_reporter.js index f2fad46f9d27..d8466110f720 100644 --- a/packages/jest-cli/src/reporters/coverage_reporter.js +++ b/packages/jest-cli/src/reporters/coverage_reporter.js @@ -159,7 +159,6 @@ export default class CoverageReporter extends BaseReporter { if (this._globalConfig.maxWorkers <= 1) { worker = require('./coverage_worker'); } else { - // $FlowFixMe: assignment of a worker with custom properties. worker = new Worker(require.resolve('./coverage_worker'), { exposedMethods: ['worker'], maxRetries: 2, diff --git a/packages/jest-haste-map/src/index.js b/packages/jest-haste-map/src/index.js index c7c6a79ac841..7831169d2ff0 100644 --- a/packages/jest-haste-map/src/index.js +++ b/packages/jest-haste-map/src/index.js @@ -670,7 +670,6 @@ class HasteMap extends EventEmitter { if ((options && options.forceInBand) || this._options.maxWorkers <= 1) { this._worker = {getSha1, worker}; } else { - // $FlowFixMe: assignment of a worker with custom properties. this._worker = (new Worker(require.resolve('./worker'), { exposedMethods: ['getSha1', 'worker'], maxRetries: 3, diff --git a/packages/jest-runner/src/index.js b/packages/jest-runner/src/index.js index cd339cd37e5c..538978903fd8 100644 --- a/packages/jest-runner/src/index.js +++ b/packages/jest-runner/src/index.js @@ -98,7 +98,6 @@ class TestRunner { onResult: OnTestSuccess, onFailure: OnTestFailure, ) { - // $FlowFixMe: class object is augmented with worker when instantiating. const worker: WorkerInterface = new Worker(TEST_WORKER_PATH, { exposedMethods: ['worker'], forkOptions: {stdio: 'pipe'}, diff --git a/packages/jest-worker/package.json b/packages/jest-worker/package.json index b993e76c65da..994afd104cfe 100644 --- a/packages/jest-worker/package.json +++ b/packages/jest-worker/package.json @@ -8,7 +8,9 @@ }, "license": "MIT", "main": "build/index.js", + "types": "build/index.d.ts", "dependencies": { + "@types/node": "*", "merge-stream": "^1.0.1", "supports-color": "^6.1.0" }, diff --git a/packages/jest-worker/src/Farm.js b/packages/jest-worker/src/Farm.ts similarity index 80% rename from packages/jest-worker/src/Farm.js rename to packages/jest-worker/src/Farm.ts index a601eebc42ac..34b0155c8850 100644 --- a/packages/jest-worker/src/Farm.js +++ b/packages/jest-worker/src/Farm.ts @@ -3,35 +3,32 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; - -import type { +import { ChildMessage, + FarmOptions, QueueChildMessage, WorkerInterface, OnStart, OnEnd, + CHILD_MESSAGE_CALL, } from './types'; -import {CHILD_MESSAGE_CALL} from './types'; export default class Farm { - _computeWorkerKey: (string, ...Array) => ?string; - _cacheKeys: {[string]: WorkerInterface, __proto__: null}; + _computeWorkerKey: FarmOptions['computeWorkerKey']; + _cacheKeys: {[key: string]: WorkerInterface}; _callback: Function; _last: Array; _locks: Array; _numOfWorkers: number; _offset: number; - _queue: Array; + _queue: Array; constructor( numOfWorkers: number, callback: Function, - computeWorkerKey?: (string, ...Array) => ?string, + computeWorkerKey?: FarmOptions['computeWorkerKey'], ) { this._callback = callback; this._numOfWorkers = numOfWorkers; @@ -45,16 +42,16 @@ export default class Farm { } } - doWork(method: string, ...args: Array): Promise { + doWork(method: string, ...args: Array): Promise { return new Promise((resolve, reject) => { const computeWorkerKey = this._computeWorkerKey; const request: ChildMessage = [CHILD_MESSAGE_CALL, false, method, args]; - let worker: ?WorkerInterface = null; - let hash: ?string = null; + let worker: WorkerInterface | null = null; + let hash: string | null = null; if (computeWorkerKey) { - hash = computeWorkerKey.apply(this, [method].concat(args)); + hash = computeWorkerKey.call(this, method, ...args); worker = hash == null ? null : this._cacheKeys[hash]; } @@ -64,7 +61,7 @@ export default class Farm { } }; - const onEnd: OnEnd = (error: ?Error, result: ?mixed) => { + const onEnd: OnEnd = (error: Error | null, result: unknown) => { if (error) { reject(error); } else { @@ -81,11 +78,11 @@ export default class Farm { }); } - _getNextJob(workerId: number): ?QueueChildMessage { + _getNextJob(workerId: number): QueueChildMessage | null { let queueHead = this._queue[workerId]; while (queueHead && queueHead.request[1]) { - queueHead = queueHead.next; + queueHead = queueHead.next || null; } this._queue[workerId] = queueHead; @@ -104,7 +101,7 @@ export default class Farm { return this; } - const onEnd = (error: ?Error, result: mixed) => { + const onEnd = (error: Error | null, result: unknown) => { job.onEnd(error, result); this.unlock(workerId); this._process(workerId); diff --git a/packages/jest-worker/src/WorkerPool.js b/packages/jest-worker/src/WorkerPool.ts similarity index 96% rename from packages/jest-worker/src/WorkerPool.js rename to packages/jest-worker/src/WorkerPool.ts index 0c6828288653..dd61ce4dfa8e 100644 --- a/packages/jest-worker/src/WorkerPool.js +++ b/packages/jest-worker/src/WorkerPool.ts @@ -3,15 +3,11 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; - import BaseWorkerPool from './base/BaseWorkerPool'; -import type { +import { ChildMessage, WorkerOptions, OnStart, diff --git a/packages/jest-worker/src/base/BaseWorkerPool.js b/packages/jest-worker/src/base/BaseWorkerPool.ts similarity index 85% rename from packages/jest-worker/src/base/BaseWorkerPool.js rename to packages/jest-worker/src/base/BaseWorkerPool.ts index 03a3b878517e..db27a42f5492 100644 --- a/packages/jest-worker/src/base/BaseWorkerPool.js +++ b/packages/jest-worker/src/base/BaseWorkerPool.ts @@ -3,26 +3,24 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; - -import mergeStream from 'merge-stream'; import path from 'path'; +import mergeStream from 'merge-stream'; -import {CHILD_MESSAGE_END} from '../types'; - -import type {Readable} from 'stream'; -import type {WorkerPoolOptions, WorkerOptions, WorkerInterface} from '../types'; +import { + CHILD_MESSAGE_END, + WorkerPoolOptions, + WorkerOptions, + WorkerInterface, +} from '../types'; /* istanbul ignore next */ const emptyMethod = () => {}; export default class BaseWorkerPool { - _stderr: Readable; - _stdout: Readable; + _stderr: NodeJS.ReadableStream; + _stdout: NodeJS.ReadableStream; _options: WorkerPoolOptions; _workers: Array; @@ -67,11 +65,11 @@ export default class BaseWorkerPool { this._stderr = stderr; } - getStderr(): Readable { + getStderr(): NodeJS.ReadableStream { return this._stderr; } - getStdout(): Readable { + getStdout(): NodeJS.ReadableStream { return this._stdout; } @@ -83,7 +81,7 @@ export default class BaseWorkerPool { return this._workers[workerId]; } - createWorker(workerOptions: WorkerOptions): WorkerInterface { + createWorker(_workerOptions: WorkerOptions): WorkerInterface { throw Error('Missing method createWorker in WorkerPool'); } diff --git a/packages/jest-worker/src/index.js b/packages/jest-worker/src/index.ts similarity index 85% rename from packages/jest-worker/src/index.js rename to packages/jest-worker/src/index.ts index dcd2c633164f..ffef6bfebf29 100644 --- a/packages/jest-worker/src/index.js +++ b/packages/jest-worker/src/index.ts @@ -3,39 +3,30 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; - import os from 'os'; import WorkerPool from './WorkerPool'; import Farm from './Farm'; -import type { - WorkerPoolInterface, - WorkerPoolOptions, - FarmOptions, -} from './types'; -import type {Readable} from 'stream'; +import {WorkerPoolInterface, WorkerPoolOptions, FarmOptions} from './types'; function getExposedMethods( workerPath: string, options: FarmOptions, -): $ReadOnlyArray { +): ReadonlyArray { let exposedMethods = options.exposedMethods; // If no methods list is given, try getting it by auto-requiring the module. if (!exposedMethods) { - // $FlowFixMe: This has to be a dynamic require. const module: Function | Object = require(workerPath); exposedMethods = Object.keys(module).filter( + // @ts-ignore: no index name => typeof module[name] === 'function', ); if (typeof module === 'function') { - exposedMethods.push('default'); + exposedMethods = [...exposedMethods, 'default']; } } @@ -75,6 +66,7 @@ export default class JestWorker { constructor(workerPath: string, options?: FarmOptions) { this._options = {...options}; + this._ending = false; const workerPoolOptions: WorkerPoolOptions = { enableWorkerThreads: this._options.enableWorkerThreads || false, @@ -84,9 +76,15 @@ export default class JestWorker { setupArgs: this._options.setupArgs || [], }; - this._workerPool = this._options.WorkerPool - ? new this._options.WorkerPool(workerPath, workerPoolOptions) - : new WorkerPool(workerPath, workerPoolOptions); + if (this._options.WorkerPool) { + // @ts-ignore: constructor target any? + this._workerPool = new this._options.WorkerPool( + workerPath, + workerPoolOptions, + ); + } else { + this._workerPool = new WorkerPool(workerPath, workerPoolOptions); + } this._farm = new Farm( workerPoolOptions.numWorkers, @@ -107,7 +105,7 @@ export default class JestWorker { throw new TypeError('Cannot define a method called ' + name); } - // $FlowFixMe: dynamic extension of the class instance is expected. + // @ts-ignore: dynamic extension of the class instance is expected. this[name] = this._callFunctionWithArgs.bind(this, name); }); } @@ -120,11 +118,11 @@ export default class JestWorker { return this._farm.doWork(method, ...args); } - getStderr(): Readable { + getStderr(): NodeJS.ReadableStream { return this._workerPool.getStderr(); } - getStdout(): Readable { + getStdout(): NodeJS.ReadableStream { return this._workerPool.getStdout(); } diff --git a/packages/jest-worker/src/types.js b/packages/jest-worker/src/types.ts similarity index 50% rename from packages/jest-worker/src/types.js rename to packages/jest-worker/src/types.ts index bb12434eca1a..5c0e7f144cdc 100644 --- a/packages/jest-worker/src/types.js +++ b/packages/jest-worker/src/types.ts @@ -3,15 +3,11 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; - // Because of the dynamic nature of a worker communication process, all messages // coming from any of the other processes cannot be typed. Thus, many types -// include "any" as a flow type, which is (unfortunately) correct here. +// include "unknown" as a TS type, which is (unfortunately) correct here. export const CHILD_MESSAGE_INITIALIZE: 0 = 0; export const CHILD_MESSAGE_CALL: 1 = 1; @@ -27,98 +23,105 @@ export type PARENT_MESSAGE_ERROR = // Option objects. -import type {Readable} from 'stream'; const EventEmitter = require('events'); export type ForkOptions = { - cwd?: string, - env?: Object, - execPath?: string, - execArgv?: Array, - silent?: boolean, - stdio?: Array, - uid?: number, - gid?: number, + cwd?: string; + env?: NodeJS.ProcessEnv; + execPath?: string; + execArgv?: Array; + silent?: boolean; + stdio?: Array; + uid?: number; + gid?: number; }; export interface WorkerPoolInterface { - getStderr(): Readable; - getStdout(): Readable; + getStderr(): NodeJS.ReadableStream; + getStdout(): NodeJS.ReadableStream; getWorkers(): Array; - createWorker(WorkerOptions): WorkerInterface; - send(number, ChildMessage, Function, Function): void; + createWorker(options: WorkerOptions): WorkerInterface; + send( + workerId: number, + request: ChildMessage, + onStart: OnStart, + onEnd: OnEnd, + ): void; end(): void; } export interface WorkerInterface { - send(ChildMessage, Function, Function): void; + send( + request: ChildMessage, + onProcessStart: OnStart, + onProcessEnd: OnEnd, + ): void; getWorkerId(): number; - getStderr(): Readable; - getStdout(): Readable; - onExit(number): void; - onMessage(any): void; + getStderr(): NodeJS.ReadableStream; + getStdout(): NodeJS.ReadableStream; + onExit(exitCode: number): void; + onMessage(message: ParentMessage): void; } export type FarmOptions = { - computeWorkerKey?: (string, ...Array) => ?string, - exposedMethods?: $ReadOnlyArray, - forkOptions?: ForkOptions, - setupArgs?: Array, - maxRetries?: number, - numWorkers?: number, + computeWorkerKey?: (method: string, ...args: Array) => string | null; + exposedMethods?: ReadonlyArray; + forkOptions?: ForkOptions; + setupArgs?: Array; + maxRetries?: number; + numWorkers?: number; WorkerPool?: ( workerPath: string, options?: WorkerPoolOptions, - ) => WorkerPoolInterface, - enableWorkerThreads?: boolean, + ) => WorkerPoolInterface; + enableWorkerThreads?: boolean; }; -export type WorkerPoolOptions = {| - setupArgs: Array, - forkOptions: ForkOptions, - maxRetries: number, - numWorkers: number, - enableWorkerThreads: boolean, -|}; - -export type WorkerOptions = {| - forkOptions: ForkOptions, - setupArgs: Array, - maxRetries: number, - workerId: number, - workerPath: string, -|}; +export type WorkerPoolOptions = { + setupArgs: Array; + forkOptions: ForkOptions; + maxRetries: number; + numWorkers: number; + enableWorkerThreads: boolean; +}; + +export type WorkerOptions = { + forkOptions: ForkOptions; + setupArgs: Array; + maxRetries: number; + workerId: number; + workerPath: string; +}; // Messages passed from the parent to the children. -export type MessagePort = { - ...typeof EventEmitter, - postMessage(any): void, +export type MessagePort = typeof EventEmitter & { + postMessage(message: unknown): void; }; export type MessageChannel = { - port1: MessagePort, - port2: MessagePort, + port1: MessagePort; + port2: MessagePort; }; export type ChildMessageInitialize = [ typeof CHILD_MESSAGE_INITIALIZE, // type boolean, // processed string, // file - ?Array, // setupArgs - ?MessagePort, // MessagePort + Array | undefined, // setupArgs + MessagePort | undefined // MessagePort ]; export type ChildMessageCall = [ typeof CHILD_MESSAGE_CALL, // type boolean, // processed string, // method - $ReadOnlyArray, // args + Array // args ]; export type ChildMessageEnd = [ typeof CHILD_MESSAGE_END, // type - boolean, // processed + boolean // processed ]; export type ChildMessage = @@ -130,7 +133,7 @@ export type ChildMessage = export type ParentMessageOk = [ typeof PARENT_MESSAGE_OK, // type - any, // result + unknown // result ]; export type ParentMessageError = [ @@ -138,18 +141,18 @@ export type ParentMessageError = [ string, // constructor string, // message string, // stack - any, // extra + unknown // extra ]; export type ParentMessage = ParentMessageOk | ParentMessageError; // Queue types. -export type OnStart = WorkerInterface => void; -export type OnEnd = (?Error, ?any) => void; - -export type QueueChildMessage = {| - request: ChildMessage, - onStart: OnStart, - onEnd: OnEnd, - next?: QueueChildMessage, -|}; +export type OnStart = (worker: WorkerInterface) => void; +export type OnEnd = (err: Error | null, result: unknown) => void; + +export type QueueChildMessage = { + request: ChildMessage; + onStart: OnStart; + onEnd: OnEnd; + next?: QueueChildMessage; +}; diff --git a/packages/jest-worker/src/workers/ChildProcessWorker.js b/packages/jest-worker/src/workers/ChildProcessWorker.ts similarity index 85% rename from packages/jest-worker/src/workers/ChildProcessWorker.js rename to packages/jest-worker/src/workers/ChildProcessWorker.ts index 2ad70be2cd07..ae3945ff0be0 100644 --- a/packages/jest-worker/src/workers/ChildProcessWorker.js +++ b/packages/jest-worker/src/workers/ChildProcessWorker.ts @@ -3,13 +3,10 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; - -import childProcess from 'child_process'; +import childProcess, {ChildProcess} from 'child_process'; +import supportsColor from 'supports-color'; import { CHILD_MESSAGE_INITIALIZE, @@ -17,15 +14,13 @@ import { PARENT_MESSAGE_SETUP_ERROR, PARENT_MESSAGE_OK, WorkerInterface, + ChildMessage, + OnEnd, + OnStart, + WorkerOptions, + ParentMessage, } from '../types'; -import type {ChildProcess} from 'child_process'; -import type {Readable} from 'stream'; - -import type {ChildMessage, OnEnd, OnStart, WorkerOptions} from '../types'; - -import supportsColor from 'supports-color'; - /** * This class wraps the child process and provides a nice interface to * communicate with. It takes care of: @@ -45,10 +40,10 @@ import supportsColor from 'supports-color'; * same call skip it. */ export default class ChildProcessWorker implements WorkerInterface { - _child: ChildProcess; + _child!: ChildProcess; _options: WorkerOptions; - _onProcessEnd: OnEnd; - _retries: number; + _onProcessEnd!: OnEnd; + _retries!: number; constructor(options: WorkerOptions) { this._options = options; @@ -57,13 +52,13 @@ export default class ChildProcessWorker implements WorkerInterface { initialize() { const forceColor = supportsColor.stdout ? {FORCE_COLOR: '1'} : {}; - const child = childProcess.fork(require.resolve('./processChild'), { + const child = childProcess.fork(require.resolve('./processChild'), [], { cwd: process.cwd(), env: { ...process.env, - JEST_WORKER_ID: this._options.workerId, + JEST_WORKER_ID: String(this._options.workerId), ...forceColor, - }, + } as NodeJS.ProcessEnv, // Suppress --debug / --inspect flags while preserving others (like --harmony). execArgv: process.execArgv.filter(v => !/^--(debug|inspect)/.test(v)), silent: true, @@ -93,13 +88,13 @@ export default class ChildProcessWorker implements WorkerInterface { PARENT_MESSAGE_CLIENT_ERROR, error.name, error.message, - error.stack, + error.stack!, {type: 'WorkerError'}, ]); } } - onMessage(response: any /* Should be ParentMessage */) { + onMessage(response: ParentMessage) { let error; switch (response[0]) { @@ -112,16 +107,16 @@ export default class ChildProcessWorker implements WorkerInterface { if (error != null && typeof error === 'object') { const extra = error; + // @ts-ignore: no index const NativeCtor = global[response[1]]; const Ctor = typeof NativeCtor === 'function' ? NativeCtor : Error; error = new Ctor(response[2]); - // $FlowFixMe: adding custom properties to errors. error.type = response[1]; error.stack = response[3]; for (const key in extra) { - // $FlowFixMe: adding custom properties to errors. + // @ts-ignore: adding custom properties to errors. error[key] = extra[key]; } } @@ -132,7 +127,7 @@ export default class ChildProcessWorker implements WorkerInterface { case PARENT_MESSAGE_SETUP_ERROR: error = new Error('Error when calling setup: ' + response[2]); - // $FlowFixMe: adding custom properties to errors. + // @ts-ignore: adding custom properties to errors. error.type = response[1]; error.stack = response[3]; @@ -162,11 +157,11 @@ export default class ChildProcessWorker implements WorkerInterface { return this._options.workerId; } - getStdout(): Readable { + getStdout(): NodeJS.ReadableStream { return this._child.stdout; } - getStderr(): Readable { + getStderr(): NodeJS.ReadableStream { return this._child.stderr; } } diff --git a/packages/jest-worker/src/workers/NodeThreadsWorker.js b/packages/jest-worker/src/workers/NodeThreadsWorker.ts similarity index 83% rename from packages/jest-worker/src/workers/NodeThreadsWorker.js rename to packages/jest-worker/src/workers/NodeThreadsWorker.ts index 3b93ab822b7d..48118eac1c28 100644 --- a/packages/jest-worker/src/workers/NodeThreadsWorker.js +++ b/packages/jest-worker/src/workers/NodeThreadsWorker.ts @@ -3,38 +3,31 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; +import path from 'path'; +// ESLint doesn't know about this experimental module +// eslint-disable-next-line import/no-unresolved +import {Worker} from 'worker_threads'; import { CHILD_MESSAGE_INITIALIZE, PARENT_MESSAGE_OK, PARENT_MESSAGE_CLIENT_ERROR, PARENT_MESSAGE_SETUP_ERROR, -} from '../types'; - -import path from 'path'; - -import type {Readable} from 'stream'; -import type { ChildMessage, OnEnd, OnStart, WorkerOptions, WorkerInterface, + ParentMessage, } from '../types'; -// $FlowFixMe: Flow doesn't know about experimental features of Node -const {Worker} = require('worker_threads'); - export default class ExperimentalWorker implements WorkerInterface { - _worker: Worker; + _worker!: Worker; _options: WorkerOptions; - _onProcessEnd: OnEnd; - _retries: number; + _onProcessEnd!: OnEnd; + _retries!: number; constructor(options: WorkerOptions) { this._options = options; @@ -48,7 +41,10 @@ export default class ExperimentalWorker implements WorkerInterface { stdout: true, workerData: { cwd: process.cwd(), - env: {...process.env, JEST_WORKER_ID: this._options.workerId}, + env: { + ...process.env, + JEST_WORKER_ID: String(this._options.workerId), + } as NodeJS.ProcessEnv, // Suppress --debug / --inspect flags while preserving others (like --harmony). execArgv: process.execArgv.filter(v => !/^--(debug|inspect)/.test(v)), silent: true, @@ -78,13 +74,13 @@ export default class ExperimentalWorker implements WorkerInterface { PARENT_MESSAGE_CLIENT_ERROR, error.name, error.message, - error.stack, + error.stack!, {type: 'WorkerError'}, ]); } } - onMessage(response: any /* Should be ParentMessage */) { + onMessage(response: ParentMessage) { let error; switch (response[0]) { @@ -97,16 +93,16 @@ export default class ExperimentalWorker implements WorkerInterface { if (error != null && typeof error === 'object') { const extra = error; + // @ts-ignore: no index const NativeCtor = global[response[1]]; const Ctor = typeof NativeCtor === 'function' ? NativeCtor : Error; error = new Ctor(response[2]); - // $FlowFixMe: adding custom properties to errors. error.type = response[1]; error.stack = response[3]; for (const key in extra) { - // $FlowFixMe: adding custom properties to errors. + // @ts-ignore: no index error[key] = extra[key]; } } @@ -116,7 +112,7 @@ export default class ExperimentalWorker implements WorkerInterface { case PARENT_MESSAGE_SETUP_ERROR: error = new Error('Error when calling setup: ' + response[2]); - // $FlowFixMe: adding custom properties to errors. + // @ts-ignore: adding custom properties to errors. error.type = response[1]; error.stack = response[3]; @@ -146,11 +142,11 @@ export default class ExperimentalWorker implements WorkerInterface { return this._options.workerId; } - getStdout(): Readable { + getStdout(): NodeJS.ReadableStream { return this._worker.stdout; } - getStderr(): Readable { + getStderr(): NodeJS.ReadableStream { return this._worker.stderr; } } diff --git a/packages/jest-worker/src/workers/__tests__/ChildProcessWorker.test.js b/packages/jest-worker/src/workers/__tests__/ChildProcessWorker.test.js index d6c5fc8790b7..79944efadb65 100644 --- a/packages/jest-worker/src/workers/__tests__/ChildProcessWorker.test.js +++ b/packages/jest-worker/src/workers/__tests__/ChildProcessWorker.test.js @@ -5,8 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -'use strict'; - /* eslint-disable no-new */ import EventEmitter from 'events'; @@ -63,7 +61,7 @@ it('passes fork options down to child_process.fork, adding the defaults', () => }); expect(childProcess.fork.mock.calls[0][0]).toBe(child); - expect(childProcess.fork.mock.calls[0][1]).toEqual({ + expect(childProcess.fork.mock.calls[0][2]).toEqual({ cwd: '/tmp', // Overridden default option. env: {...process.env, FORCE_COLOR: supportsColor.stdout ? '1' : undefined}, // Default option. execArgv: ['-p'], // Filtered option. @@ -80,7 +78,7 @@ it('passes workerId to the child process and assign it to env.JEST_WORKER_ID', ( workerPath: '/tmp/foo', }); - expect(childProcess.fork.mock.calls[0][1].env.JEST_WORKER_ID).toEqual(2); + expect(childProcess.fork.mock.calls[0][2].env.JEST_WORKER_ID).toEqual('2'); }); it('initializes the child process with the given workerPath', () => { diff --git a/packages/jest-worker/src/workers/__tests__/NodeThreadsWorker.test.js b/packages/jest-worker/src/workers/__tests__/NodeThreadsWorker.test.js index 4406e3795c71..747ba0531c88 100644 --- a/packages/jest-worker/src/workers/__tests__/NodeThreadsWorker.test.js +++ b/packages/jest-worker/src/workers/__tests__/NodeThreadsWorker.test.js @@ -63,7 +63,7 @@ it('passes fork options down to child_process.fork, adding the defaults', () => workerPath: '/tmp/foo/bar/baz.js', }); - expect(childProcess.mock.calls[0][0]).toBe(child); + expect(childProcess.mock.calls[0][0]).toBe(child.replace(/\.ts$/, '.js')); expect(childProcess.mock.calls[0][1]).toEqual({ eval: false, stderr: true, @@ -87,7 +87,7 @@ it('passes workerId to the child process and assign it to env.JEST_WORKER_ID', ( }); expect(childProcess.mock.calls[0][1].workerData.env.JEST_WORKER_ID).toEqual( - 2, + '2', ); }); diff --git a/packages/jest-worker/src/workers/processChild.js b/packages/jest-worker/src/workers/processChild.ts similarity index 87% rename from packages/jest-worker/src/workers/processChild.js rename to packages/jest-worker/src/workers/processChild.ts index 9becbba0fb49..beb395af1a22 100644 --- a/packages/jest-worker/src/workers/processChild.js +++ b/packages/jest-worker/src/workers/processChild.ts @@ -3,29 +3,22 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; - import { CHILD_MESSAGE_CALL, CHILD_MESSAGE_END, CHILD_MESSAGE_INITIALIZE, PARENT_MESSAGE_CLIENT_ERROR, + PARENT_MESSAGE_ERROR, PARENT_MESSAGE_SETUP_ERROR, PARENT_MESSAGE_OK, -} from '../types'; - -import type { ChildMessageInitialize, ChildMessageCall, - PARENT_MESSAGE_ERROR, } from '../types'; -let file = null; -let setupArgs: Array = []; +let file: string | null = null; +let setupArgs: Array = []; let initialized = false; /** @@ -101,8 +94,7 @@ function reportError(error: Error, type: PARENT_MESSAGE_ERROR) { } function end(): void { - // $FlowFixMe: This has to be a dynamic require. - const main = require(file); + const main = require(file!); if (!main.teardown) { exitProcess(); @@ -117,11 +109,10 @@ function exitProcess(): void { process.exit(0); } -function execMethod(method: string, args: $ReadOnlyArray): void { - // $FlowFixMe: This has to be a dynamic require. - const main = require(file); +function execMethod(method: string, args: Array): void { + const main = require(file!); - let fn; + let fn: (...args: Array) => unknown; if (method === 'default') { fn = main.__esModule ? main['default'] : main; @@ -145,10 +136,10 @@ function execMethod(method: string, args: $ReadOnlyArray): void { } function execFunction( - fn: (...args: $ReadOnlyArray) => mixed, - ctx: mixed, - args: $ReadOnlyArray, - onResult: (result: mixed) => void, + fn: (...args: Array) => any | Promise, + ctx: unknown, + args: Array, + onResult: (result: unknown) => void, onError: (error: Error) => void, ): void { let result; diff --git a/packages/jest-worker/src/workers/threadChild.js b/packages/jest-worker/src/workers/threadChild.ts similarity index 79% rename from packages/jest-worker/src/workers/threadChild.js rename to packages/jest-worker/src/workers/threadChild.ts index e35e4610acc5..4d8272cef8c0 100644 --- a/packages/jest-worker/src/workers/threadChild.js +++ b/packages/jest-worker/src/workers/threadChild.ts @@ -3,36 +3,28 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - * - * @flow */ -'use strict'; +// ESLint doesn't know about this experimental module +// eslint-disable-next-line import/no-unresolved +import {parentPort, isMainThread} from 'worker_threads'; import { + ChildMessageInitialize, + ChildMessageCall, CHILD_MESSAGE_CALL, CHILD_MESSAGE_END, CHILD_MESSAGE_INITIALIZE, PARENT_MESSAGE_CLIENT_ERROR, + PARENT_MESSAGE_ERROR, PARENT_MESSAGE_SETUP_ERROR, PARENT_MESSAGE_OK, } from '../types'; -import type { - ChildMessageInitialize, - ChildMessageCall, - PARENT_MESSAGE_ERROR, -} from '../types'; - -let file = null; -let setupArgs: Array = []; +let file: string | null = null; +let setupArgs: Array = []; let initialized = false; -/* eslint-disable import/no-unresolved */ -// $FlowFixMe: Flow doesn't support experimental node modules -import {parentPort, isMainThread} from 'worker_threads'; -/* eslint-enable import/no-unresolved */ - /** * This file is a small bootstrapper for workers. It sets up the communication * between the worker and the parent process, interpreting parent messages and @@ -46,7 +38,7 @@ import {parentPort, isMainThread} from 'worker_threads'; * If an invalid message is detected, the child will exit (by throwing) with a * non-zero exit code. */ -parentPort.on('message', (request: any) => { +parentPort!.on('message', (request: any) => { switch (request[0]) { case CHILD_MESSAGE_INITIALIZE: const init: ChildMessageInitialize = request; @@ -75,7 +67,7 @@ function reportSuccess(result: any) { throw new Error('Child can only be used on a forked process'); } - parentPort.postMessage([PARENT_MESSAGE_OK, result]); + parentPort!.postMessage([PARENT_MESSAGE_OK, result]); } function reportClientError(error: Error) { @@ -95,19 +87,17 @@ function reportError(error: Error, type: PARENT_MESSAGE_ERROR) { error = new Error('"null" or "undefined" thrown'); } - parentPort.postMessage([ + parentPort!.postMessage([ type, error.constructor && error.constructor.name, error.message, error.stack, - // $FlowFixMe: this is safe to just inherit from Object. typeof error === 'object' ? {...error} : error, ]); } function end(): void { - // $FlowFixMe: This has to be a dynamic require. - const main = require(file); + const main = require(file!); if (!main.teardown) { exitProcess(); @@ -122,11 +112,10 @@ function exitProcess(): void { process.exit(0); } -function execMethod(method: string, args: $ReadOnlyArray): void { - // $FlowFixMe: This has to be a dynamic require. - const main = require(file); +function execMethod(method: string, args: Array): void { + const main = require(file!); - let fn; + let fn: (...args: Array) => unknown; if (method === 'default') { fn = main.__esModule ? main['default'] : main; @@ -150,10 +139,10 @@ function execMethod(method: string, args: $ReadOnlyArray): void { } function execFunction( - fn: (...args: $ReadOnlyArray) => mixed, - ctx: mixed, - args: $ReadOnlyArray, - onResult: (result: mixed) => void, + fn: (...args: Array) => any, + ctx: unknown, + args: Array, + onResult: (result: unknown) => void, onError: (error: Error) => void, ): void { let result; diff --git a/packages/jest-worker/tsconfig.json b/packages/jest-worker/tsconfig.json new file mode 100644 index 000000000000..7bb06bce6d20 --- /dev/null +++ b/packages/jest-worker/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + } +}