From 71da2fc3d5eda42d2bd99e65ab302c91888fb8f3 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Fri, 27 Sep 2019 21:22:20 -0700 Subject: [PATCH 01/43] Add custom message support to jest-worker --- packages/jest-runner/src/index.ts | 9 +- packages/jest-worker/src/Farm.ts | 86 +++++++++++++------ packages/jest-worker/src/WorkerPool.ts | 4 +- .../src/__performance_tests__/workers/pi.js | 4 + .../jest-worker/src/__tests__/Farm.test.js | 15 ++++ .../src/__tests__/WorkerPool.test.js | 3 + packages/jest-worker/src/hello.js | 14 +++ packages/jest-worker/src/index.ts | 3 + packages/jest-worker/src/types.ts | 19 +++- .../src/workers/ChildProcessWorker.ts | 21 ++++- .../src/workers/NodeThreadsWorker.ts | 22 ++++- .../src/workers/sendCustomMessageToParent.ts | 25 ++++++ 12 files changed, 191 insertions(+), 34 deletions(-) create mode 100644 packages/jest-worker/src/hello.js create mode 100644 packages/jest-worker/src/workers/sendCustomMessageToParent.ts diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index e838e63e06b6..38ac5df2e309 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -150,7 +150,7 @@ class TestRunner { await onStart(test); - return worker.worker({ + const promise = worker.worker({ config: test.context.config, context: { ...this._context, @@ -161,6 +161,13 @@ class TestRunner { globalConfig: this._globalConfig, path: test.path, }); + + + promise.onCustomMessage = () => { + console.log('Custom message') + } + + return promise; }); const onError = async (err: SerializableError, test: JestTest) => { diff --git a/packages/jest-worker/src/Farm.ts b/packages/jest-worker/src/Farm.ts index 3e9196b1339d..f78da49c8d5f 100644 --- a/packages/jest-worker/src/Farm.ts +++ b/packages/jest-worker/src/Farm.ts @@ -14,6 +14,8 @@ import { QueueChildMessage, QueueItem, WorkerInterface, + PromiseWithCustomMessage, + OnCustomMessage, } from './types'; export default class Farm { @@ -44,41 +46,65 @@ export default class Farm { } } - doWork(method: string, ...args: Array): Promise { - return new Promise((resolve, reject) => { - const computeWorkerKey = this._computeWorkerKey; - const request: ChildMessage = [CHILD_MESSAGE_CALL, false, method, args]; + doWork( + method: string, + ...args: Array + ): PromiseWithCustomMessage { + let customMessageListeners: OnCustomMessage[] = []; + + const addCustomMessageListener = (listener: OnCustomMessage) => { + customMessageListeners.push(listener); + return () => { + customMessageListeners = customMessageListeners.filter( + l => l !== listener, + ); + }; + }; - let worker: WorkerInterface | null = null; - let hash: string | null = null; + const onCustomMessage: OnCustomMessage = (message: any) => { + customMessageListeners.forEach(listener => listener(message)); + }; - if (computeWorkerKey) { - hash = computeWorkerKey.call(this, method, ...args); - worker = hash == null ? null : this._cacheKeys[hash]; - } + const promise: PromiseWithCustomMessage = new Promise( + (resolve, reject) => { + const computeWorkerKey = this._computeWorkerKey; + const request: ChildMessage = [CHILD_MESSAGE_CALL, false, method, args]; - const onStart: OnStart = (worker: WorkerInterface) => { - if (hash != null) { - this._cacheKeys[hash] = worker; + let worker: WorkerInterface | null = null; + let hash: string | null = null; + + if (computeWorkerKey) { + hash = computeWorkerKey.call(this, method, ...args); + worker = hash == null ? null : this._cacheKeys[hash]; } - }; - const onEnd: OnEnd = (error: Error | null, result: unknown) => { - if (error) { - reject(error); + const onStart: OnStart = (worker: WorkerInterface) => { + if (hash != null) { + this._cacheKeys[hash] = worker; + } + }; + + const onEnd: OnEnd = (error: Error | null, result: unknown) => { + if (error) { + reject(error); + } else { + resolve(result); + } + }; + + const task = {onEnd, onStart, request, onCustomMessage}; + + if (worker) { + this._enqueue(task, worker.getWorkerId()); } else { - resolve(result); + this._push(task); } - }; + }, + ); - const task = {onEnd, onStart, request}; + promise.onCustomMessage = addCustomMessageListener; - if (worker) { - this._enqueue(task, worker.getWorkerId()); - } else { - this._push(task); - } - }); + return promise; } private _getNextTask(workerId: number): QueueChildMessage | null { @@ -114,7 +140,13 @@ export default class Farm { task.request[1] = true; this._lock(workerId); - this._callback(workerId, task.request, task.onStart, onEnd); + this._callback( + workerId, + task.request, + task.onStart, + onEnd, + task.onCustomMessage, + ); return this; } diff --git a/packages/jest-worker/src/WorkerPool.ts b/packages/jest-worker/src/WorkerPool.ts index 941312facaa9..b904df4698c4 100644 --- a/packages/jest-worker/src/WorkerPool.ts +++ b/packages/jest-worker/src/WorkerPool.ts @@ -14,6 +14,7 @@ import { WorkerInterface, WorkerOptions, WorkerPoolInterface, + OnCustomMessage, } from './types'; const canUseWorkerThreads = () => { @@ -31,8 +32,9 @@ class WorkerPool extends BaseWorkerPool implements WorkerPoolInterface { request: ChildMessage, onStart: OnStart, onEnd: OnEnd, + onCustomMessage: OnCustomMessage, ): void { - this.getWorkerById(workerId).send(request, onStart, onEnd); + this.getWorkerById(workerId).send(request, onStart, onEnd, onCustomMessage); } createWorker(workerOptions: WorkerOptions): WorkerInterface { diff --git a/packages/jest-worker/src/__performance_tests__/workers/pi.js b/packages/jest-worker/src/__performance_tests__/workers/pi.js index bf2c043f45ec..2e2a9f58d288 100644 --- a/packages/jest-worker/src/__performance_tests__/workers/pi.js +++ b/packages/jest-worker/src/__performance_tests__/workers/pi.js @@ -7,12 +7,16 @@ 'use strict'; +const { messageParent } = require('jest-worker'); + module.exports = function() { const points = 10000; let inside = 0; + messageParent({ r: 'Lucas' }) for (let i = 0; i < points; i++) { if (Math.pow(Math.random(), 2) + Math.pow(Math.random(), 2) <= 1) { + messageParent({ i }) inside++; } } diff --git a/packages/jest-worker/src/__tests__/Farm.test.js b/packages/jest-worker/src/__tests__/Farm.test.js index e502b1a987ca..230e4015bf5f 100644 --- a/packages/jest-worker/src/__tests__/Farm.test.js +++ b/packages/jest-worker/src/__tests__/Farm.test.js @@ -49,6 +49,7 @@ describe('Farm', () => { [1, true, 'foo', [42]], expect.any(Function), expect.any(Function), + expect.any(Function), ); }); @@ -67,6 +68,7 @@ describe('Farm', () => { [1, true, 'foo', [42]], expect.any(Function), expect.any(Function), + expect.any(Function), ); expect(callback).toHaveBeenNthCalledWith( 2, @@ -74,6 +76,8 @@ describe('Farm', () => { [1, true, 'foo1', [43]], expect.any(Function), expect.any(Function), + + expect.any(Function), ); expect(callback).toHaveBeenNthCalledWith( 3, @@ -81,6 +85,7 @@ describe('Farm', () => { [1, true, 'foo2', [44]], expect.any(Function), expect.any(Function), + expect.any(Function), ); expect(callback).toHaveBeenNthCalledWith( 4, @@ -88,10 +93,12 @@ describe('Farm', () => { [1, true, 'foo3', [45]], expect.any(Function), expect.any(Function), + expect.any(Function), ); }); it('handles null computeWorkerKey, sending to first worker', async () => { + process.send([-1, 'ROGELIo']) const computeWorkerKey = jest.fn(() => null); const farm = new Farm(4, callback, computeWorkerKey); @@ -110,6 +117,7 @@ describe('Farm', () => { [1, true, 'foo', [42]], expect.any(Function), expect.any(Function), + expect.any(Function), ); }); @@ -146,6 +154,7 @@ describe('Farm', () => { [1, true, 'foo', [42]], expect.any(Function), expect.any(Function), + expect.any(Function), ); expect(callback).toHaveBeenNthCalledWith( 2, @@ -153,6 +162,7 @@ describe('Farm', () => { [1, true, 'foo1', [43]], expect.any(Function), expect.any(Function), + expect.any(Function), ); expect(callback).toHaveBeenNthCalledWith( 3, @@ -160,6 +170,7 @@ describe('Farm', () => { [1, true, 'foo2', [44]], expect.any(Function), expect.any(Function), + expect.any(Function), ); }); @@ -220,6 +231,7 @@ describe('Farm', () => { [1, true, 'car', ['plane']], expect.any(Function), expect.any(Function), + expect.any(Function), ); expect(callback).toHaveBeenNthCalledWith( 2, @@ -227,6 +239,7 @@ describe('Farm', () => { [1, true, 'foo', ['bar']], expect.any(Function), expect.any(Function), + expect.any(Function), ); }); @@ -261,6 +274,7 @@ describe('Farm', () => { [1, true, 'car', ['plane']], expect.any(Function), expect.any(Function), + expect.any(Function), ); expect(callback).toHaveBeenNthCalledWith( 2, @@ -268,6 +282,7 @@ describe('Farm', () => { [1, true, 'foo', ['bar']], expect.any(Function), expect.any(Function), + expect.any(Function), ); }); diff --git a/packages/jest-worker/src/__tests__/WorkerPool.test.js b/packages/jest-worker/src/__tests__/WorkerPool.test.js index a5bafa91f0f0..7c2cbcedbfa1 100644 --- a/packages/jest-worker/src/__tests__/WorkerPool.test.js +++ b/packages/jest-worker/src/__tests__/WorkerPool.test.js @@ -71,6 +71,7 @@ describe('WorkerPool', () => { {foo: 'bar'}, onStart, onEnd, + undefined, ); }); @@ -100,6 +101,7 @@ describe('WorkerPool', () => { {foo: 'bar'}, onStart, onEnd, + undefined, ); }); @@ -128,6 +130,7 @@ describe('WorkerPool', () => { {foo: 'bar'}, onStart, onEnd, + undefined, ); }); }); diff --git a/packages/jest-worker/src/hello.js b/packages/jest-worker/src/hello.js new file mode 100644 index 000000000000..6f10cce04ede --- /dev/null +++ b/packages/jest-worker/src/hello.js @@ -0,0 +1,14 @@ +const { default: Worker } = require('jest-worker'); + + +const myWorker = new Worker(require.resolve('./__performance_tests__/workers/pi.js'), { + numWorkers: 4, + enableWorkerThreads: true + }); + +const promise = myWorker.default(); + +promise.onCustomMessage((message) => { + console.log(message) +}) +promise.then(console.log).then(() => process.exit()) \ No newline at end of file diff --git a/packages/jest-worker/src/index.ts b/packages/jest-worker/src/index.ts index a253e0b489c6..284852a4bc3f 100644 --- a/packages/jest-worker/src/index.ts +++ b/packages/jest-worker/src/index.ts @@ -14,6 +14,9 @@ import { WorkerPoolInterface, WorkerPoolOptions, } from './types'; +import sendCustomMessageToParent from './workers/sendCustomMessageToParent'; + +export const messageParent = sendCustomMessageToParent; function getExposedMethods( workerPath: string, diff --git a/packages/jest-worker/src/types.ts b/packages/jest-worker/src/types.ts index c61b6303247b..1d00ed15bcf7 100644 --- a/packages/jest-worker/src/types.ts +++ b/packages/jest-worker/src/types.ts @@ -19,6 +19,7 @@ export const CHILD_MESSAGE_END: 2 = 2; export const PARENT_MESSAGE_OK: 0 = 0; export const PARENT_MESSAGE_CLIENT_ERROR: 1 = 1; export const PARENT_MESSAGE_SETUP_ERROR: 2 = 2; +export const PARENT_MESSAGE_CUSTOM: -1 = -1; export type PARENT_MESSAGE_ERROR = | typeof PARENT_MESSAGE_CLIENT_ERROR @@ -34,6 +35,7 @@ export interface WorkerPoolInterface { request: ChildMessage, onStart: OnStart, onEnd: OnEnd, + onCustomMessage: OnCustomMessage, ): void; end(): Promise; } @@ -43,6 +45,7 @@ export interface WorkerInterface { request: ChildMessage, onProcessStart: OnStart, onProcessEnd: OnEnd, + onCustomMessage: OnCustomMessage, ): void; waitForExit(): Promise; forceExit(): void; @@ -56,6 +59,10 @@ export type PoolExitResult = { forceExited: boolean; }; +export interface PromiseWithCustomMessage extends Promise { + onCustomMessage?: (listener: OnCustomMessage) => () => void; +} + // Option objects. export {ForkOptions}; @@ -128,6 +135,11 @@ export type ChildMessage = // Messages passed from the children to the parent. +export type ParentMessageCustom = [ + typeof PARENT_MESSAGE_CUSTOM, // type + unknown, // result +]; + export type ParentMessageOk = [ typeof PARENT_MESSAGE_OK, // type unknown, // result @@ -141,17 +153,22 @@ export type ParentMessageError = [ unknown, // extra ]; -export type ParentMessage = ParentMessageOk | ParentMessageError; +export type ParentMessage = + | ParentMessageOk + | ParentMessageError + | ParentMessageCustom; // Queue types. export type OnStart = (worker: WorkerInterface) => void; export type OnEnd = (err: Error | null, result: unknown) => void; +export type OnCustomMessage = (message: unknown) => void; export type QueueChildMessage = { request: ChildMessage; onStart: OnStart; onEnd: OnEnd; + onCustomMessage: OnCustomMessage; }; export type QueueItem = { diff --git a/packages/jest-worker/src/workers/ChildProcessWorker.ts b/packages/jest-worker/src/workers/ChildProcessWorker.ts index a6b3e3ac02f2..aa051d6887f4 100644 --- a/packages/jest-worker/src/workers/ChildProcessWorker.ts +++ b/packages/jest-worker/src/workers/ChildProcessWorker.ts @@ -18,9 +18,11 @@ import { PARENT_MESSAGE_CLIENT_ERROR, PARENT_MESSAGE_OK, PARENT_MESSAGE_SETUP_ERROR, + PARENT_MESSAGE_CUSTOM, ParentMessage, WorkerInterface, WorkerOptions, + OnCustomMessage, } from '../types'; const SIGNAL_BASE_EXIT_CODE = 128; @@ -55,6 +57,7 @@ export default class ChildProcessWorker implements WorkerInterface { private _request: ChildMessage | null; private _retries!: number; private _onProcessEnd!: OnEnd; + private _onCustomMessage!: OnCustomMessage; private _fakeStream: PassThrough | null; private _stdout: ReturnType | null; @@ -156,7 +159,6 @@ export default class ChildProcessWorker implements WorkerInterface { private _onMessage(response: ParentMessage) { let error; - switch (response[0]) { case PARENT_MESSAGE_OK: this._onProcessEnd(null, response[1]); @@ -193,7 +195,9 @@ export default class ChildProcessWorker implements WorkerInterface { this._onProcessEnd(error, null); break; - + case PARENT_MESSAGE_CUSTOM: + this._onCustomMessage(response[1]); + break; default: throw new TypeError('Unexpected response from worker: ' + response[0]); } @@ -215,7 +219,12 @@ export default class ChildProcessWorker implements WorkerInterface { } } - send(request: ChildMessage, onProcessStart: OnStart, onProcessEnd: OnEnd) { + send( + request: ChildMessage, + onProcessStart: OnStart, + onProcessEnd: OnEnd, + onCustomMessage: OnCustomMessage, + ) { onProcessStart(this); this._onProcessEnd = (...args) => { // Clean the request to avoid sending past requests to workers that fail @@ -224,6 +233,12 @@ export default class ChildProcessWorker implements WorkerInterface { return onProcessEnd(...args); }; + this._onCustomMessage = (...arg) => { + if (onCustomMessage) { + return onCustomMessage(...arg); + } + }; + this._request = request; this._retries = 0; this._child.send(request); diff --git a/packages/jest-worker/src/workers/NodeThreadsWorker.ts b/packages/jest-worker/src/workers/NodeThreadsWorker.ts index f33181f9f874..b0f543be5841 100644 --- a/packages/jest-worker/src/workers/NodeThreadsWorker.ts +++ b/packages/jest-worker/src/workers/NodeThreadsWorker.ts @@ -23,6 +23,8 @@ import { ParentMessage, WorkerInterface, WorkerOptions, + OnCustomMessage, + PARENT_MESSAGE_CUSTOM, } from '../types'; export default class ExperimentalWorker implements WorkerInterface { @@ -32,6 +34,7 @@ export default class ExperimentalWorker implements WorkerInterface { private _request: ChildMessage | null; private _retries!: number; private _onProcessEnd!: OnEnd; + private _onCustomMessage!: OnCustomMessage; private _fakeStream: PassThrough | null; private _stdout: ReturnType | null; @@ -172,6 +175,12 @@ export default class ExperimentalWorker implements WorkerInterface { this._onProcessEnd(error, null); break; + case PARENT_MESSAGE_OK: + this._onCustomMessage(response[1]); + break; + case PARENT_MESSAGE_CUSTOM: + this._onCustomMessage(response[1]); + break; default: throw new TypeError('Unexpected response from worker: ' + response[0]); } @@ -198,7 +207,12 @@ export default class ExperimentalWorker implements WorkerInterface { this._worker.terminate(); } - send(request: ChildMessage, onProcessStart: OnStart, onProcessEnd: OnEnd) { + send( + request: ChildMessage, + onProcessStart: OnStart, + onProcessEnd: OnEnd, + onCustomMessage: OnCustomMessage, + ) { onProcessStart(this); this._onProcessEnd = (...args) => { // Clean the request to avoid sending past requests to workers that fail @@ -207,6 +221,12 @@ export default class ExperimentalWorker implements WorkerInterface { return onProcessEnd(...args); }; + this._onCustomMessage = (...arg) => { + if (onCustomMessage) { + return onCustomMessage(...arg); + } + }; + this._request = request; this._retries = 0; diff --git a/packages/jest-worker/src/workers/sendCustomMessageToParent.ts b/packages/jest-worker/src/workers/sendCustomMessageToParent.ts new file mode 100644 index 000000000000..5b71011ba5d7 --- /dev/null +++ b/packages/jest-worker/src/workers/sendCustomMessageToParent.ts @@ -0,0 +1,25 @@ +import {PARENT_MESSAGE_CUSTOM} from '../types'; + +const isWorkerThread = () => { + try { + const {isMainThread, parentPort} = require('worker_threads'); + return !isMainThread && parentPort; + } catch (_) { + return false; + } +}; + +const sendCustomMessageToParent = (message: any) => { + if (isWorkerThread()) { + const {parentPort} = require('worker_threads'); + parentPort.postMessage([PARENT_MESSAGE_CUSTOM, message]); + } else if (typeof process.send === 'function') { + process.send([PARENT_MESSAGE_CUSTOM, message]); + } else { + throw new Error( + 'sendCustomMessageToParent can only be used inside a worker', + ); + } +}; + +export default sendCustomMessageToParent; From 4283f012cec5473e51a738ee06537cc60c07d23a Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Sat, 28 Sep 2019 20:45:10 -0700 Subject: [PATCH 02/43] WIP --- packages/jest-runner/src/index.ts | 11 ++++------- packages/jest-worker/src/Farm.ts | 1 + packages/jest-worker/src/base/BaseWorkerPool.ts | 2 +- packages/jest-worker/src/index.ts | 6 ++++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 38ac5df2e309..28a0a5c22ddb 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -6,11 +6,11 @@ */ import {Config} from '@jest/types'; -import {SerializableError} from '@jest/test-result'; +import {SerializableError, TestResult} from '@jest/test-result'; import exit = require('exit'); import chalk from 'chalk'; import throat from 'throat'; -import Worker from 'jest-worker'; +import Worker, { PromiseWithCustomMessage } from 'jest-worker'; import runTest from './runTest'; import {SerializableResolver, worker} from './testWorker'; import { @@ -160,12 +160,9 @@ class TestRunner { }, globalConfig: this._globalConfig, path: test.path, - }); - + }) as PromiseWithCustomMessage; - promise.onCustomMessage = () => { - console.log('Custom message') - } + promise.onCustomMessage((message: any) => {}) return promise; }); diff --git a/packages/jest-worker/src/Farm.ts b/packages/jest-worker/src/Farm.ts index f78da49c8d5f..aa0be3e6d64c 100644 --- a/packages/jest-worker/src/Farm.ts +++ b/packages/jest-worker/src/Farm.ts @@ -85,6 +85,7 @@ export default class Farm { }; const onEnd: OnEnd = (error: Error | null, result: unknown) => { + customMessageListeners = [] if (error) { reject(error); } else { diff --git a/packages/jest-worker/src/base/BaseWorkerPool.ts b/packages/jest-worker/src/base/BaseWorkerPool.ts index 5eec43c0214c..d367c0652044 100644 --- a/packages/jest-worker/src/base/BaseWorkerPool.ts +++ b/packages/jest-worker/src/base/BaseWorkerPool.ts @@ -94,7 +94,7 @@ export default class BaseWorkerPool { // We do not cache the request object here. If so, it would only be only // processed by one of the workers, and we want them all to close. const workerExitPromises = this._workers.map(async worker => { - worker.send([CHILD_MESSAGE_END, false], emptyMethod, emptyMethod); + worker.send([CHILD_MESSAGE_END, false], emptyMethod, emptyMethod, emptyMethod); // Schedule a force exit in case worker fails to exit gracefully so // await worker.waitForExit() never takes longer than FORCE_EXIT_DELAY diff --git a/packages/jest-worker/src/index.ts b/packages/jest-worker/src/index.ts index 284852a4bc3f..a12cce8b8538 100644 --- a/packages/jest-worker/src/index.ts +++ b/packages/jest-worker/src/index.ts @@ -13,11 +13,10 @@ import { PoolExitResult, WorkerPoolInterface, WorkerPoolOptions, + PromiseWithCustomMessage } from './types'; import sendCustomMessageToParent from './workers/sendCustomMessageToParent'; -export const messageParent = sendCustomMessageToParent; - function getExposedMethods( workerPath: string, options: FarmOptions, @@ -149,3 +148,6 @@ export default class JestWorker { return this._workerPool.end(); } } + +export { PromiseWithCustomMessage } +export const messageParent = sendCustomMessageToParent; \ No newline at end of file From f34cfc76047d9687f0cf9aec0989c3c79e99e943 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Sun, 29 Sep 2019 12:57:45 -0700 Subject: [PATCH 03/43] Add @SimenB's code --- packages/jest-core/src/ReporterDispatcher.ts | 17 +- packages/jest-core/src/TestScheduler.ts | 55 ++++- packages/jest-diff/src/cleanupSemantic.ts | 224 +++++++++++------- packages/jest-reporters/src/types.ts | 20 +- packages/jest-runner/package.json | 1 + packages/jest-runner/src/index.ts | 44 ++-- packages/jest-test-result/src/index.ts | 1 + packages/jest-test-result/src/types.ts | 7 + packages/jest-worker/src/Farm.ts | 2 +- .../jest-worker/src/base/BaseWorkerPool.ts | 7 +- packages/jest-worker/src/index.ts | 6 +- yarn.lock | 5 + 12 files changed, 247 insertions(+), 142 deletions(-) diff --git a/packages/jest-core/src/ReporterDispatcher.ts b/packages/jest-core/src/ReporterDispatcher.ts index e76caf596919..eba3a4097570 100644 --- a/packages/jest-core/src/ReporterDispatcher.ts +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -27,14 +27,17 @@ export default class ReporterDispatcher { ); } - async onTestResult( + async onTestFileResult( test: Test, testResult: TestResult, results: AggregatedResult, ) { for (const reporter of this._reporters) { - reporter.onTestResult && - (await reporter.onTestResult(test, testResult, results)); + if (reporter.onTestFileResult) { + await reporter.onTestFileResult(test, testResult, results); + } else if (reporter.onTestResult) { + await reporter.onTestResult(test, testResult, results); + } } // Release memory if unused later. @@ -43,9 +46,13 @@ export default class ReporterDispatcher { testResult.console = undefined; } - async onTestStart(test: Test) { + async onTestFileStart(test: Test) { for (const reporter of this._reporters) { - reporter.onTestStart && (await reporter.onTestStart(test)); + if (reporter.onTestFileStart) { + await reporter.onTestFileStart(test); + } else if (reporter.onTestStart) { + await reporter.onTestStart(test); + } } } diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index a4d237cd939a..8cc6dffe73a3 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -71,7 +71,9 @@ export default class TestScheduler { } async scheduleTests(tests: Array, watcher: TestWatcher) { - const onStart = this._dispatcher.onTestStart.bind(this._dispatcher); + const onTestFileStart = this._dispatcher.onTestFileStart.bind( + this._dispatcher, + ); const timings: Array = []; const contexts = new Set(); tests.forEach(test => { @@ -120,7 +122,11 @@ export default class TestScheduler { } addResult(aggregatedResults, testResult); - await this._dispatcher.onTestResult(test, testResult, aggregatedResults); + await this._dispatcher.onTestFileResult( + test, + testResult, + aggregatedResults, + ); return this._bailIfNeeded(contexts, aggregatedResults, watcher); }; @@ -139,7 +145,11 @@ export default class TestScheduler { test.path, ); addResult(aggregatedResults, testResult); - await this._dispatcher.onTestResult(test, testResult, aggregatedResults); + await this._dispatcher.onTestFileResult( + test, + testResult, + aggregatedResults, + ); }; const updateSnapshotState = () => { @@ -186,16 +196,35 @@ export default class TestScheduler { if (testsByRunner) { try { for (const runner of Object.keys(testRunners)) { - await testRunners[runner].runTests( - testsByRunner[runner], - watcher, - onStart, - onResult, - onFailure, - { - serial: runInBand || Boolean(testRunners[runner].isSerial), - }, - ); + const testRunner = testRunners[runner]; + const tests = testsByRunner[runner]; + const testRunnerOptions = { + serial: runInBand || Boolean(testRunner.isSerial), + }; + + const unsubscribes = [ + testRunner.eventEmitter.on( + 'test-file-start', + ([test]: [TestRunner.Test]) => onTestFileStart(test), + ), + testRunner.eventEmitter.on( + 'test-file-success', + ([test, testResult]: [TestRunner.Test, TestResult]) => + onResult(test, testResult), + ), + testRunner.eventEmitter.on( + 'test-file-failure', + ([test, error]: [TestRunner.Test, SerializableError]) => + onFailure(test, error), + ), + testRunner.eventEmitter.on('test-file-result', () => { + // TODO + }), + ]; + + await testRunner.runTests(tests, watcher, testRunnerOptions); + + unsubscribes.forEach(sub => sub()); } } catch (error) { if (!watcher.isInterrupted()) { diff --git a/packages/jest-diff/src/cleanupSemantic.ts b/packages/jest-diff/src/cleanupSemantic.ts index 0df74e0bc895..13b5f7dff325 100644 --- a/packages/jest-diff/src/cleanupSemantic.ts +++ b/packages/jest-diff/src/cleanupSemantic.ts @@ -58,7 +58,6 @@ class Diff { } } - /** * Determine the common prefix of two strings. * @param {string} text1 First string. @@ -78,8 +77,10 @@ var diff_commonPrefix = function(text1: string, text2: string): number { var pointermid = pointermax; var pointerstart = 0; while (pointermin < pointermid) { - if (text1.substring(pointerstart, pointermid) == - text2.substring(pointerstart, pointermid)) { + if ( + text1.substring(pointerstart, pointermid) == + text2.substring(pointerstart, pointermid) + ) { pointermin = pointermid; pointerstart = pointermin; } else { @@ -90,7 +91,6 @@ var diff_commonPrefix = function(text1: string, text2: string): number { return pointermid; }; - /** * Determine the common suffix of two strings. * @param {string} text1 First string. @@ -99,8 +99,11 @@ var diff_commonPrefix = function(text1: string, text2: string): number { */ var diff_commonSuffix = function(text1: string, text2: string): number { // Quick check for common null cases. - if (!text1 || !text2 || - text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) { + if ( + !text1 || + !text2 || + text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1) + ) { return 0; } // Binary search. @@ -110,8 +113,10 @@ var diff_commonSuffix = function(text1: string, text2: string): number { var pointermid = pointermax; var pointerend = 0; while (pointermin < pointermid) { - if (text1.substring(text1.length - pointermid, text1.length - pointerend) == - text2.substring(text2.length - pointermid, text2.length - pointerend)) { + if ( + text1.substring(text1.length - pointermid, text1.length - pointerend) == + text2.substring(text2.length - pointermid, text2.length - pointerend) + ) { pointermin = pointermid; pointerend = pointermin; } else { @@ -122,7 +127,6 @@ var diff_commonSuffix = function(text1: string, text2: string): number { return pointermid; }; - /** * Determine if the suffix of one string is the prefix of another. * @param {string} text1 First string. @@ -163,27 +167,28 @@ var diff_commonOverlap_ = function(text1: string, text2: string): number { return best; } length += found; - if (found == 0 || text1.substring(text_length - length) == - text2.substring(0, length)) { + if ( + found == 0 || + text1.substring(text_length - length) == text2.substring(0, length) + ) { best = length; length++; } } }; - /** * Reduce the number of edits by eliminating semantically trivial equalities. * @param {!Array.} diffs Array of diff tuples. */ - var diff_cleanupSemantic = function(diffs: Array) { +var diff_cleanupSemantic = function(diffs: Array) { var changes = false; - var equalities = []; // Stack of indices where equalities are found. - var equalitiesLength = 0; // Keeping our own length var is faster in JS. + var equalities = []; // Stack of indices where equalities are found. + var equalitiesLength = 0; // Keeping our own length var is faster in JS. /** @type {?string} */ var lastEquality = null; // Always equal to diffs[equalities[equalitiesLength - 1]][1] - var pointer = 0; // Index of current position. + var pointer = 0; // Index of current position. // Number of characters that changed prior to the equality. var length_insertions1 = 0; var length_deletions1 = 0; @@ -191,14 +196,16 @@ var diff_commonOverlap_ = function(text1: string, text2: string): number { var length_insertions2 = 0; var length_deletions2 = 0; while (pointer < diffs.length) { - if (diffs[pointer][0] == DIFF_EQUAL) { // Equality found. + if (diffs[pointer][0] == DIFF_EQUAL) { + // Equality found. equalities[equalitiesLength++] = pointer; length_insertions1 = length_insertions2; length_deletions1 = length_deletions2; length_insertions2 = 0; length_deletions2 = 0; lastEquality = diffs[pointer][1]; - } else { // An insertion or deletion. + } else { + // An insertion or deletion. if (diffs[pointer][0] == DIFF_INSERT) { length_insertions2 += diffs[pointer][1].length; } else { @@ -206,13 +213,18 @@ var diff_commonOverlap_ = function(text1: string, text2: string): number { } // Eliminate an equality that is smaller or equal to the edits on both // sides of it. - if (lastEquality && (lastEquality.length <= - Math.max(length_insertions1, length_deletions1)) && - (lastEquality.length <= Math.max(length_insertions2, - length_deletions2))) { + if ( + lastEquality && + lastEquality.length <= + Math.max(length_insertions1, length_deletions1) && + lastEquality.length <= Math.max(length_insertions2, length_deletions2) + ) { // Duplicate record. - diffs.splice(equalities[equalitiesLength - 1], 0, - new Diff(DIFF_DELETE, lastEquality)); + diffs.splice( + equalities[equalitiesLength - 1], + 0, + new Diff(DIFF_DELETE, lastEquality), + ); // Change second copy to insert. diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT; // Throw away the equality we just deleted. @@ -220,7 +232,7 @@ var diff_commonOverlap_ = function(text1: string, text2: string): number { // Throw away the previous equality (it needs to be reevaluated). equalitiesLength--; pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1; - length_insertions1 = 0; // Reset the counters. + length_insertions1 = 0; // Reset the counters. length_deletions1 = 0; length_insertions2 = 0; length_deletions2 = 0; @@ -245,36 +257,51 @@ var diff_commonOverlap_ = function(text1: string, text2: string): number { // Only extract an overlap if it is as big as the edit ahead or behind it. pointer = 1; while (pointer < diffs.length) { - if (diffs[pointer - 1][0] == DIFF_DELETE && - diffs[pointer][0] == DIFF_INSERT) { + if ( + diffs[pointer - 1][0] == DIFF_DELETE && + diffs[pointer][0] == DIFF_INSERT + ) { var deletion = diffs[pointer - 1][1]; var insertion = diffs[pointer][1]; var overlap_length1 = diff_commonOverlap_(deletion, insertion); var overlap_length2 = diff_commonOverlap_(insertion, deletion); if (overlap_length1 >= overlap_length2) { - if (overlap_length1 >= deletion.length / 2 || - overlap_length1 >= insertion.length / 2) { + if ( + overlap_length1 >= deletion.length / 2 || + overlap_length1 >= insertion.length / 2 + ) { // Overlap found. Insert an equality and trim the surrounding edits. - diffs.splice(pointer, 0, new Diff(DIFF_EQUAL, - insertion.substring(0, overlap_length1))); - diffs[pointer - 1][1] = - deletion.substring(0, deletion.length - overlap_length1); + diffs.splice( + pointer, + 0, + new Diff(DIFF_EQUAL, insertion.substring(0, overlap_length1)), + ); + diffs[pointer - 1][1] = deletion.substring( + 0, + deletion.length - overlap_length1, + ); diffs[pointer + 1][1] = insertion.substring(overlap_length1); pointer++; } } else { - if (overlap_length2 >= deletion.length / 2 || - overlap_length2 >= insertion.length / 2) { + if ( + overlap_length2 >= deletion.length / 2 || + overlap_length2 >= insertion.length / 2 + ) { // Reverse overlap found. // Insert an equality and swap and trim the surrounding edits. - diffs.splice(pointer, 0, new Diff(DIFF_EQUAL, - deletion.substring(0, overlap_length2))); + diffs.splice( + pointer, + 0, + new Diff(DIFF_EQUAL, deletion.substring(0, overlap_length2)), + ); diffs[pointer - 1][0] = DIFF_INSERT; - diffs[pointer - 1][1] = - insertion.substring(0, insertion.length - overlap_length2); + diffs[pointer - 1][1] = insertion.substring( + 0, + insertion.length - overlap_length2, + ); diffs[pointer + 1][0] = DIFF_DELETE; - diffs[pointer + 1][1] = - deletion.substring(overlap_length2); + diffs[pointer + 1][1] = deletion.substring(overlap_length2); pointer++; } } @@ -284,7 +311,6 @@ var diff_commonOverlap_ = function(text1: string, text2: string): number { } }; - /** * Look for single edits surrounded on both sides by equalities * which can be shifted sideways to align the edit to a word boundary. @@ -317,18 +343,12 @@ var diff_cleanupSemanticLossless = function(diffs: Array) { var char2 = two.charAt(0); var nonAlphaNumeric1 = char1.match(nonAlphaNumericRegex_); var nonAlphaNumeric2 = char2.match(nonAlphaNumericRegex_); - var whitespace1 = nonAlphaNumeric1 && - char1.match(whitespaceRegex_); - var whitespace2 = nonAlphaNumeric2 && - char2.match(whitespaceRegex_); - var lineBreak1 = whitespace1 && - char1.match(linebreakRegex_); - var lineBreak2 = whitespace2 && - char2.match(linebreakRegex_); - var blankLine1 = lineBreak1 && - one.match(blanklineEndRegex_); - var blankLine2 = lineBreak2 && - two.match(blanklineStartRegex_); + var whitespace1 = nonAlphaNumeric1 && char1.match(whitespaceRegex_); + var whitespace2 = nonAlphaNumeric2 && char2.match(whitespaceRegex_); + var lineBreak1 = whitespace1 && char1.match(linebreakRegex_); + var lineBreak2 = whitespace2 && char2.match(linebreakRegex_); + var blankLine1 = lineBreak1 && one.match(blanklineEndRegex_); + var blankLine2 = lineBreak2 && two.match(blanklineStartRegex_); if (blankLine1 || blankLine2) { // Five points for blank lines. @@ -352,8 +372,10 @@ var diff_cleanupSemanticLossless = function(diffs: Array) { var pointer = 1; // Intentionally ignore the first and last element (don't need checking). while (pointer < diffs.length - 1) { - if (diffs[pointer - 1][0] == DIFF_EQUAL && - diffs[pointer + 1][0] == DIFF_EQUAL) { + if ( + diffs[pointer - 1][0] == DIFF_EQUAL && + diffs[pointer + 1][0] == DIFF_EQUAL + ) { // This is a single edit surrounded by equalities. var equality1 = diffs[pointer - 1][1]; var edit = diffs[pointer][1]; @@ -372,14 +394,16 @@ var diff_cleanupSemanticLossless = function(diffs: Array) { var bestEquality1 = equality1; var bestEdit = edit; var bestEquality2 = equality2; - var bestScore = diff_cleanupSemanticScore_(equality1, edit) + - diff_cleanupSemanticScore_(edit, equality2); + var bestScore = + diff_cleanupSemanticScore_(equality1, edit) + + diff_cleanupSemanticScore_(edit, equality2); while (edit.charAt(0) === equality2.charAt(0)) { equality1 += edit.charAt(0); edit = edit.substring(1) + equality2.charAt(0); equality2 = equality2.substring(1); - var score = diff_cleanupSemanticScore_(equality1, edit) + - diff_cleanupSemanticScore_(edit, equality2); + var score = + diff_cleanupSemanticScore_(equality1, edit) + + diff_cleanupSemanticScore_(edit, equality2); // The >= encourages trailing rather than leading whitespace on edits. if (score >= bestScore) { bestScore = score; @@ -410,7 +434,6 @@ var diff_cleanupSemanticLossless = function(diffs: Array) { } }; - // Define some regex patterns for matching boundaries. var nonAlphaNumericRegex_ = /[^a-zA-Z0-9]/; var whitespaceRegex_ = /\s/; @@ -418,7 +441,6 @@ var linebreakRegex_ = /[\r\n]/; var blanklineEndRegex_ = /\n\r?\n$/; var blanklineStartRegex_ = /^\r?\n\r?\n/; - /** * Reorder and merge like edit sections. Merge equalities. * Any edit section can move as long as it doesn't cross an equality. @@ -452,14 +474,20 @@ var diff_cleanupMerge = function(diffs: Array) { // Factor out any common prefixies. commonlength = diff_commonPrefix(text_insert, text_delete); if (commonlength !== 0) { - if ((pointer - count_delete - count_insert) > 0 && - diffs[pointer - count_delete - count_insert - 1][0] == - DIFF_EQUAL) { - diffs[pointer - count_delete - count_insert - 1][1] += - text_insert.substring(0, commonlength); + if ( + pointer - count_delete - count_insert > 0 && + diffs[pointer - count_delete - count_insert - 1][0] == + DIFF_EQUAL + ) { + diffs[ + pointer - count_delete - count_insert - 1 + ][1] += text_insert.substring(0, commonlength); } else { - diffs.splice(0, 0, new Diff(DIFF_EQUAL, - text_insert.substring(0, commonlength))); + diffs.splice( + 0, + 0, + new Diff(DIFF_EQUAL, text_insert.substring(0, commonlength)), + ); pointer++; } text_insert = text_insert.substring(commonlength); @@ -468,25 +496,28 @@ var diff_cleanupMerge = function(diffs: Array) { // Factor out any common suffixies. commonlength = diff_commonSuffix(text_insert, text_delete); if (commonlength !== 0) { - diffs[pointer][1] = text_insert.substring(text_insert.length - - commonlength) + diffs[pointer][1]; - text_insert = text_insert.substring(0, text_insert.length - - commonlength); - text_delete = text_delete.substring(0, text_delete.length - - commonlength); + diffs[pointer][1] = + text_insert.substring(text_insert.length - commonlength) + + diffs[pointer][1]; + text_insert = text_insert.substring( + 0, + text_insert.length - commonlength, + ); + text_delete = text_delete.substring( + 0, + text_delete.length - commonlength, + ); } } // Delete the offending records and add the merged ones. pointer -= count_delete + count_insert; diffs.splice(pointer, count_delete + count_insert); if (text_delete.length) { - diffs.splice(pointer, 0, - new Diff(DIFF_DELETE, text_delete)); + diffs.splice(pointer, 0, new Diff(DIFF_DELETE, text_delete)); pointer++; } if (text_insert.length) { - diffs.splice(pointer, 0, - new Diff(DIFF_INSERT, text_insert)); + diffs.splice(pointer, 0, new Diff(DIFF_INSERT, text_insert)); pointer++; } pointer++; @@ -505,7 +536,7 @@ var diff_cleanupMerge = function(diffs: Array) { } } if (diffs[diffs.length - 1][1] === '') { - diffs.pop(); // Remove the dummy entry at the end. + diffs.pop(); // Remove the dummy entry at the end. } // Second pass: look for single edits surrounded on both sides by equalities @@ -515,25 +546,35 @@ var diff_cleanupMerge = function(diffs: Array) { pointer = 1; // Intentionally ignore the first and last element (don't need checking). while (pointer < diffs.length - 1) { - if (diffs[pointer - 1][0] == DIFF_EQUAL && - diffs[pointer + 1][0] == DIFF_EQUAL) { + if ( + diffs[pointer - 1][0] == DIFF_EQUAL && + diffs[pointer + 1][0] == DIFF_EQUAL + ) { // This is a single edit surrounded by equalities. - if (diffs[pointer][1].substring(diffs[pointer][1].length - - diffs[pointer - 1][1].length) == diffs[pointer - 1][1]) { + if ( + diffs[pointer][1].substring( + diffs[pointer][1].length - diffs[pointer - 1][1].length, + ) == diffs[pointer - 1][1] + ) { // Shift the edit over the previous equality. - diffs[pointer][1] = diffs[pointer - 1][1] + - diffs[pointer][1].substring(0, diffs[pointer][1].length - - diffs[pointer - 1][1].length); + diffs[pointer][1] = + diffs[pointer - 1][1] + + diffs[pointer][1].substring( + 0, + diffs[pointer][1].length - diffs[pointer - 1][1].length, + ); diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1]; diffs.splice(pointer - 1, 1); changes = true; - } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) == - diffs[pointer + 1][1]) { + } else if ( + diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) == + diffs[pointer + 1][1] + ) { // Shift the edit over the next equality. diffs[pointer - 1][1] += diffs[pointer + 1][1]; diffs[pointer][1] = - diffs[pointer][1].substring(diffs[pointer + 1][1].length) + - diffs[pointer + 1][1]; + diffs[pointer][1].substring(diffs[pointer + 1][1].length) + + diffs[pointer + 1][1]; diffs.splice(pointer + 1, 1); changes = true; } @@ -546,7 +587,6 @@ var diff_cleanupMerge = function(diffs: Array) { } }; - export { Diff, DIFF_EQUAL, diff --git a/packages/jest-reporters/src/types.ts b/packages/jest-reporters/src/types.ts index 83b15c6aef4e..fe1a552aa28b 100644 --- a/packages/jest-reporters/src/types.ts +++ b/packages/jest-reporters/src/types.ts @@ -10,6 +10,8 @@ import { AggregatedResult, SerializableError, TestResult, + AssertionResult, + TestCase, } from '@jest/test-result'; import {JestEnvironment as Environment} from '@jest/environment'; import {FS as HasteFS, ModuleMap} from 'jest-haste-map'; @@ -53,16 +55,30 @@ export type OnTestFailure = ( export type OnTestSuccess = (test: Test, result: TestResult) => Promise; export interface Reporter { - readonly onTestResult: ( + readonly onTestResult?: ( test: Test, testResult: TestResult, aggregatedResult: AggregatedResult, ) => Promise | void; + readonly onTestFileResult?: ( + test: Test, + testResult: TestResult, + aggregatedResult: AggregatedResult, + ) => Promise | void; + readonly onTestCaseResult?: ( + test: Test, + testCase: TestCase, + testCaseResult: AssertionResult, + ) => Promise | void; readonly onRunStart: ( results: AggregatedResult, options: ReporterOnStartOptions, ) => Promise | void; - readonly onTestStart: (test: Test) => Promise | void; + readonly onTestStart?: (test: Test) => Promise | void; + readonly onTestCaseStart?: ( + test: Test, + testCase: TestCase, + ) => Promise | void; readonly onRunComplete: ( contexts: Set, results: AggregatedResult, diff --git a/packages/jest-runner/package.json b/packages/jest-runner/package.json index 3aefedd43667..08d4f24dd02e 100644 --- a/packages/jest-runner/package.json +++ b/packages/jest-runner/package.json @@ -10,6 +10,7 @@ "main": "build/index.js", "types": "build/index.d.ts", "dependencies": { + "emittery": "^0.5.1", "@jest/console": "^24.7.1", "@jest/environment": "^24.9.0", "@jest/test-result": "^24.9.0", diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 28a0a5c22ddb..863e10b8b128 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -10,7 +10,7 @@ import {SerializableError, TestResult} from '@jest/test-result'; import exit = require('exit'); import chalk from 'chalk'; import throat from 'throat'; -import Worker, { PromiseWithCustomMessage } from 'jest-worker'; +import Worker, {PromiseWithCustomMessage} from 'jest-worker'; import runTest from './runTest'; import {SerializableResolver, worker} from './testWorker'; import { @@ -23,6 +23,7 @@ import { TestWatcher as JestTestWatcher, WatcherState, } from './types'; +import Emittery = require('emittery'); const TEST_WORKER_PATH = require.resolve('./testWorker'); @@ -44,6 +45,7 @@ namespace TestRunner { class TestRunner { private _globalConfig: Config.GlobalConfig; private _context: JestTestRunnerContext; + public eventEmitter: Emittery; constructor( globalConfig: Config.GlobalConfig, @@ -51,33 +53,22 @@ class TestRunner { ) { this._globalConfig = globalConfig; this._context = context || {}; + this.eventEmitter = new Emittery(); } async runTests( tests: Array, watcher: JestTestWatcher, - onStart: JestOnTestStart, - onResult: JestOnTestSuccess, - onFailure: JestOnTestFailure, options: JestTestRunnerOptions, ): Promise { return await (options.serial - ? this._createInBandTestRun(tests, watcher, onStart, onResult, onFailure) - : this._createParallelTestRun( - tests, - watcher, - onStart, - onResult, - onFailure, - )); + ? this._createInBandTestRun(tests, watcher) + : this._createParallelTestRun(tests, watcher)); } private async _createInBandTestRun( tests: Array, watcher: JestTestWatcher, - onStart: JestOnTestStart, - onResult: JestOnTestSuccess, - onFailure: JestOnTestFailure, ) { process.env.JEST_WORKER_ID = '1'; const mutex = throat(1); @@ -90,7 +81,7 @@ class TestRunner { throw new CancelRun(); } - await onStart(test); + await this.eventEmitter.emit('test-file-start', [test]); return runTest( test.path, this._globalConfig, @@ -99,8 +90,12 @@ class TestRunner { this._context, ); }) - .then(result => onResult(test, result)) - .catch(err => onFailure(test, err)), + .then(result => + this.eventEmitter.emit('test-file-success', [test, result]), + ) + .catch(err => + this.eventEmitter.emit('test-file-failure', [test, err]), + ), ), Promise.resolve(), ); @@ -109,9 +104,6 @@ class TestRunner { private async _createParallelTestRun( tests: Array, watcher: JestTestWatcher, - onStart: JestOnTestStart, - onResult: JestOnTestSuccess, - onFailure: JestOnTestFailure, ) { const resolvers: Map = new Map(); for (const test of tests) { @@ -148,7 +140,7 @@ class TestRunner { return Promise.reject(); } - await onStart(test); + await this.eventEmitter.emit('test-file-start', [test]); const promise = worker.worker({ config: test.context.config, @@ -162,13 +154,13 @@ class TestRunner { path: test.path, }) as PromiseWithCustomMessage; - promise.onCustomMessage((message: any) => {}) + // promise.onCustomMessage((message: any) => {}) return promise; }); const onError = async (err: SerializableError, test: JestTest) => { - await onFailure(test, err); + await this.eventEmitter.emit('test-file-failure', [test, err]); if (err.type === 'ProcessTerminatedError') { console.error( 'A worker process has quit unexpectedly! ' + @@ -189,7 +181,9 @@ class TestRunner { const runAllTests = Promise.all( tests.map(test => runTestInWorker(test) - .then(testResult => onResult(test, testResult)) + .then(result => + this.eventEmitter.emit('test-file-success', [test, result]), + ) .catch(error => onError(error, test)), ), ); diff --git a/packages/jest-test-result/src/index.ts b/packages/jest-test-result/src/index.ts index b5feb16ae93e..2a08706efcec 100644 --- a/packages/jest-test-result/src/index.ts +++ b/packages/jest-test-result/src/index.ts @@ -24,4 +24,5 @@ export { Status, Suite, TestResult, + TestCase, } from './types'; diff --git a/packages/jest-test-result/src/types.ts b/packages/jest-test-result/src/types.ts index a9427cd7abb2..afc97fca4f02 100644 --- a/packages/jest-test-result/src/types.ts +++ b/packages/jest-test-result/src/types.ts @@ -100,6 +100,13 @@ export type Suite = { tests: Array; }; +export type TestCase = { + ancestorTitles: Array; + fullName: string; + location: Callsite | null | undefined; + title: string; +}; + export type TestResult = { console?: ConsoleBuffer; coverage?: CoverageMapData; diff --git a/packages/jest-worker/src/Farm.ts b/packages/jest-worker/src/Farm.ts index aa0be3e6d64c..ce310af22a02 100644 --- a/packages/jest-worker/src/Farm.ts +++ b/packages/jest-worker/src/Farm.ts @@ -85,7 +85,7 @@ export default class Farm { }; const onEnd: OnEnd = (error: Error | null, result: unknown) => { - customMessageListeners = [] + customMessageListeners = []; if (error) { reject(error); } else { diff --git a/packages/jest-worker/src/base/BaseWorkerPool.ts b/packages/jest-worker/src/base/BaseWorkerPool.ts index d367c0652044..9538a603cf8b 100644 --- a/packages/jest-worker/src/base/BaseWorkerPool.ts +++ b/packages/jest-worker/src/base/BaseWorkerPool.ts @@ -94,7 +94,12 @@ export default class BaseWorkerPool { // We do not cache the request object here. If so, it would only be only // processed by one of the workers, and we want them all to close. const workerExitPromises = this._workers.map(async worker => { - worker.send([CHILD_MESSAGE_END, false], emptyMethod, emptyMethod, emptyMethod); + worker.send( + [CHILD_MESSAGE_END, false], + emptyMethod, + emptyMethod, + emptyMethod, + ); // Schedule a force exit in case worker fails to exit gracefully so // await worker.waitForExit() never takes longer than FORCE_EXIT_DELAY diff --git a/packages/jest-worker/src/index.ts b/packages/jest-worker/src/index.ts index a12cce8b8538..8755d2628186 100644 --- a/packages/jest-worker/src/index.ts +++ b/packages/jest-worker/src/index.ts @@ -13,7 +13,7 @@ import { PoolExitResult, WorkerPoolInterface, WorkerPoolOptions, - PromiseWithCustomMessage + PromiseWithCustomMessage, } from './types'; import sendCustomMessageToParent from './workers/sendCustomMessageToParent'; @@ -149,5 +149,5 @@ export default class JestWorker { } } -export { PromiseWithCustomMessage } -export const messageParent = sendCustomMessageToParent; \ No newline at end of file +export {PromiseWithCustomMessage}; +export const messageParent = sendCustomMessageToParent; diff --git a/yarn.lock b/yarn.lock index efb2690bd15d..da0d05af5a4c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5246,6 +5246,11 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +emittery@^0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.5.1.tgz#9fbbf57e9aecc258d727d78858a598eb05ea5c96" + integrity sha512-sYZXNHH9PhTfs98ROEFVC3bLiR8KSqXQsEHIwZ9J6H0RaQObC3JYq4G8IvDd0b45/LxfGKYBpmaUN4LiKytaNw== + emoji-regex@^7.0.1, emoji-regex@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" From 667025243554b8c238e51b21db68c0b07536becd Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Mon, 30 Sep 2019 10:29:50 -0700 Subject: [PATCH 04/43] It kind of works --- .vscode/settings.json | 2 +- packages/jest-circus/package.json | 1 + .../jestAdapterInit.ts | 158 +++++++++++++----- packages/jest-core/src/ReporterDispatcher.ts | 9 +- packages/jest-core/src/TestScheduler.ts | 9 +- packages/jest-reporters/src/Status.ts | 15 ++ .../jest-reporters/src/default_reporter.ts | 6 + packages/jest-reporters/src/types.ts | 1 + packages/jest-reporters/src/utils.ts | 54 +++++- packages/jest-runner/src/index.ts | 8 +- .../jest-worker/src/workers/processChild.ts | 1 - .../src/workers/sendCustomMessageToParent.ts | 6 +- 12 files changed, 211 insertions(+), 59 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c4951686b125..07d18558adbe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,5 @@ "flow.useNPMPackagedFlow": true, "javascript.validate.enable": false, "jest.pathToJest": "yarn jest --", - "prettier.eslintIntegration": true + "prettier.eslintIntegration": false } diff --git a/packages/jest-circus/package.json b/packages/jest-circus/package.json index d8484864aff8..56e723b04489 100644 --- a/packages/jest-circus/package.json +++ b/packages/jest-circus/package.json @@ -18,6 +18,7 @@ "co": "^4.6.0", "expect": "^24.9.0", "is-generator-fn": "^2.0.0", + "jest-worker": "^24.9.0", "jest-each": "^24.9.0", "jest-matcher-utils": "^24.9.0", "jest-message-util": "^24.9.0", diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 0b0f92095ba3..f83316bbedf5 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -12,6 +12,8 @@ import { Status, TestResult, createEmptyTestResult, + TestCase, + Test, } from '@jest/test-result'; import {extractExpectedAssertionsErrors, getState, setState} from 'expect'; import {formatExecError, formatResultsErrors} from 'jest-message-util'; @@ -28,12 +30,67 @@ import { dispatch, getState as getRunnerState, } from '../state'; -import {getTestID} from '../utils'; +import {getTestID, makeRunResult} from '../utils'; import run from '../run'; +import {messageParent} from 'jest-worker'; import globals from '..'; +import {TestEntry, DescribeBlock} from '@jest/types/build/Circus'; type Process = NodeJS.Process; +const parseTestResults = (testResults: Circus.TestResult[]) => { + let numFailingTests = 0; + let numPassingTests = 0; + let numPendingTests = 0; + let numTodoTests = 0; + + const assertionResults: Array = testResults.map( + testResult => { + let status: Status; + if (testResult.status === 'skip') { + status = 'pending'; + numPendingTests += 1; + } else if (testResult.status === 'todo') { + status = 'todo'; + numTodoTests += 1; + } else if (testResult.errors.length) { + status = 'failed'; + numFailingTests += 1; + } else { + status = 'passed'; + numPassingTests += 1; + } + + const ancestorTitles = testResult.testPath.filter( + name => name !== ROOT_DESCRIBE_BLOCK_NAME, + ); + const title = ancestorTitles.pop(); + + return { + ancestorTitles, + duration: testResult.duration, + failureMessages: testResult.errors, + fullName: title + ? ancestorTitles.concat(title).join(' ') + : ancestorTitles.join(' '), + invocations: testResult.invocations, + location: testResult.location, + numPassingAsserts: 0, + status, + title: testResult.testPath[testResult.testPath.length - 1], + }; + }, + ); + + return { + numFailingTests, + numPassingTests, + numPendingTests, + numTodoTests, + assertionResults, + }; +}; + export const initialize = ({ config, environment, @@ -138,6 +195,7 @@ export const initialize = ({ setState({snapshotState, testPath}); addEventHandler(handleSnapshotStateAfterRetry(snapshotState)); + addEventHandler(reportTestEvents(testPath, parentProcess)); // Return it back to the outer scope (test runner outside the VM). return {globals, snapshotState}; @@ -154,48 +212,13 @@ export const runAndTransformResultsToJestFormat = async ({ }): Promise => { const runResult: Circus.RunResult = await run(); - let numFailingTests = 0; - let numPassingTests = 0; - let numPendingTests = 0; - let numTodoTests = 0; - - const assertionResults: Array = runResult.testResults.map( - testResult => { - let status: Status; - if (testResult.status === 'skip') { - status = 'pending'; - numPendingTests += 1; - } else if (testResult.status === 'todo') { - status = 'todo'; - numTodoTests += 1; - } else if (testResult.errors.length) { - status = 'failed'; - numFailingTests += 1; - } else { - status = 'passed'; - numPassingTests += 1; - } - - const ancestorTitles = testResult.testPath.filter( - name => name !== ROOT_DESCRIBE_BLOCK_NAME, - ); - const title = ancestorTitles.pop(); - - return { - ancestorTitles, - duration: testResult.duration, - failureMessages: testResult.errors, - fullName: title - ? ancestorTitles.concat(title).join(' ') - : ancestorTitles.join(' '), - invocations: testResult.invocations, - location: testResult.location, - numPassingAsserts: 0, - status, - title: testResult.testPath[testResult.testPath.length - 1], - }; - }, - ); + const { + numFailingTests, + numPassingTests, + numPendingTests, + numTodoTests, + assertionResults, + } = parseTestResults(runResult.testResults); let failureMessage = formatResultsErrors( assertionResults, @@ -235,6 +258,55 @@ export const runAndTransformResultsToJestFormat = async ({ }; }; +const getAncestorTitles = (testEntry: TestEntry) => { + let current: TestEntry | DescribeBlock | undefined = testEntry; + const titles = []; + while (current && current.name !== ROOT_DESCRIBE_BLOCK_NAME) { + titles.push(current.name); + current = current.parent; + } + + return titles.reverse(); +}; + +const reportTestEvents = (testPath: string, parentProcess: NodeJS.Process) => ( + event: Circus.Event, +) => { + // const toTestCase = (test: TestEntry) => { + // const ancestorTitles = getAncestorTitles(test); + // const title = ancestorTitles.pop() as string; + // const testCase: TestCase = { + // ancestorTitles, + // title, + // location: null, + // fullName: title + // ? ancestorTitles.concat(title).join(' ') + // : ancestorTitles.join(' '), + // }; + // return testCase; + // }; + switch (event.name) { + case 'test_done': { + const quickStats = + event.test.errors.length === 0 + ? { + testPath, + numFailingTests: 0, + numPassingTests: 1, + numPendingTests: 0, + } + : { + testPath, + numFailingTests: 1, + numPassingTests: 0, + numPendingTests: 0, + }; + messageParent(['test-case-result', [quickStats]], parentProcess); + break; + } + } +}; + const handleSnapshotStateAfterRetry = (snapshotState: SnapshotStateType) => ( event: Circus.Event, ) => { diff --git a/packages/jest-core/src/ReporterDispatcher.ts b/packages/jest-core/src/ReporterDispatcher.ts index eba3a4097570..99ac10f26c9a 100644 --- a/packages/jest-core/src/ReporterDispatcher.ts +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {AggregatedResult, TestResult} from '@jest/test-result'; +import {AggregatedResult, TestResult, TestCase} from '@jest/test-result'; import {Test} from 'jest-runner'; import {Context} from 'jest-runtime'; import {Reporter, ReporterOnStartOptions} from '@jest/reporters'; @@ -62,6 +62,13 @@ export default class ReporterDispatcher { } } + async onTestCaseResult(quickStats) { + for (const reporter of this._reporters) { + reporter.onTestCaseResult && + (await reporter.onTestCaseResult(quickStats)); + } + } + async onRunComplete(contexts: Set, results: AggregatedResult) { for (const reporter of this._reporters) { reporter.onRunComplete && diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 8cc6dffe73a3..d5cd02e91337 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -217,9 +217,12 @@ export default class TestScheduler { ([test, error]: [TestRunner.Test, SerializableError]) => onFailure(test, error), ), - testRunner.eventEmitter.on('test-file-result', () => { - // TODO - }), + testRunner.eventEmitter.on( + 'test-case-result', + ([quickStats]: any) => { + this._dispatcher.onTestCaseResult(quickStats); + }, + ), ]; await testRunner.runTests(tests, watcher, testRunnerOptions); diff --git a/packages/jest-reporters/src/Status.ts b/packages/jest-reporters/src/Status.ts index b486b7a3ae2c..4535fb9f2f77 100644 --- a/packages/jest-reporters/src/Status.ts +++ b/packages/jest-reporters/src/Status.ts @@ -66,6 +66,7 @@ export default class Status { private _cache: {content: string; clear: string} | null; private _callback?: () => void; private _currentTests: CurrentTestList; + private _currentQuickStats: any[]; private _done: boolean; private _emitScheduled: boolean; private _estimatedTime: number; @@ -76,6 +77,7 @@ export default class Status { constructor() { this._cache = null; this._currentTests = new CurrentTestList(); + this._currentQuickStats = []; this._done = false; this._emitScheduled = false; this._estimatedTime = 0; @@ -103,6 +105,15 @@ export default class Status { this._emit(); } + addQuickStats(quickStats) { + this._currentQuickStats.push(quickStats); + if (!this._showStatus) { + this._emit(); + } else { + this._debouncedEmit(); + } + } + testStarted(testPath: Config.Path, config: Config.ProjectConfig) { this._currentTests.add(testPath, config); if (!this._showStatus) { @@ -119,6 +130,9 @@ export default class Status { ) { const {testFilePath} = testResult; this._aggregatedResults = aggregatedResults; + this._currentQuickStats = this._currentQuickStats.filter( + quickStats => quickStats.testPath !== testFilePath, + ); this._currentTests.delete(testFilePath); this._debouncedEmit(); } @@ -156,6 +170,7 @@ export default class Status { content += '\n' + getSummary(this._aggregatedResults, { + currentQuickStats: this._currentQuickStats, estimatedTime: this._estimatedTime, roundTime: true, width, diff --git a/packages/jest-reporters/src/default_reporter.ts b/packages/jest-reporters/src/default_reporter.ts index 9f9f613ac001..f085a3fa7383 100644 --- a/packages/jest-reporters/src/default_reporter.ts +++ b/packages/jest-reporters/src/default_reporter.ts @@ -130,6 +130,12 @@ export default class DefaultReporter extends BaseReporter { this._status.testStarted(test.path, test.context.config); } + onTestCaseResult(quickStats) { + // console.log({quickStats}); + this._status.addQuickStats(quickStats); + // console.log('Test case result from reporter'); + } + onRunComplete() { this.forceFlushBufferedOutput(); this._status.runFinished(); diff --git a/packages/jest-reporters/src/types.ts b/packages/jest-reporters/src/types.ts index fe1a552aa28b..0a22b8e02413 100644 --- a/packages/jest-reporters/src/types.ts +++ b/packages/jest-reporters/src/types.ts @@ -75,6 +75,7 @@ export interface Reporter { options: ReporterOnStartOptions, ) => Promise | void; readonly onTestStart?: (test: Test) => Promise | void; + readonly onTestFileStart?: (test: Test) => Promise | void; readonly onTestCaseStart?: ( test: Test, testCase: TestCase, diff --git a/packages/jest-reporters/src/utils.ts b/packages/jest-reporters/src/utils.ts index 3d730e59404b..62c824b427ba 100644 --- a/packages/jest-reporters/src/utils.ts +++ b/packages/jest-reporters/src/utils.ts @@ -94,6 +94,29 @@ export const relativePath = ( return {basename, dirname}; }; +const getCurrentQuickStatsValues = (currentQuickStats = []) => { + let numFailingTests = 0; + let numPassingTests = 0; + let numPendingTests = 0; + let numTodoTests = 0; + + currentQuickStats.forEach(quickStat => { + numFailingTests += quickStat.numFailingTests || 0; + numPassingTests += quickStat.numPassingTests || 0; + numPendingTests += quickStat.numPendingTests || 0; + numTodoTests += quickStat.numTodoTests || 0; + }); + + return { + numFailingTests, + numPassingTests, + numPendingTests, + numTodoTests, + numTotalTests: + numFailingTests + numPassingTests + numPendingTests + numTodoTests, + }; +}; + export const getSummary = ( aggregatedResults: AggregatedResult, options?: SummaryOptions, @@ -103,6 +126,11 @@ export const getSummary = ( runTime = Math.floor(runTime); } + const aggregatedQuickStats = getCurrentQuickStatsValues( + options.currentQuickStats, + ); + // console.log(aggregatedQuickStats.numPassingTests); + const estimatedTime = (options && options.estimatedTime) || 0; const snapshotResults = aggregatedResults.snapshot; const snapshotsAdded = snapshotResults.added; @@ -139,11 +167,27 @@ export const getSummary = ( const tests = chalk.bold('Tests: ') + - (testsFailed ? chalk.bold.red(`${testsFailed} failed`) + ', ' : '') + - (testsPending ? chalk.bold.yellow(`${testsPending} skipped`) + ', ' : '') + - (testsTodo ? chalk.bold.magenta(`${testsTodo} todo`) + ', ' : '') + - (testsPassed ? chalk.bold.green(`${testsPassed} passed`) + ', ' : '') + - `${testsTotal} total`; + (testsFailed + ? chalk.bold.red( + `${testsFailed + aggregatedQuickStats.numFailingTests} failed`, + ) + ', ' + : '') + + (testsPending + ? chalk.bold.yellow( + `${testsPending + aggregatedQuickStats.numPendingTests} skipped`, + ) + ', ' + : '') + + (testsTodo + ? chalk.bold.magenta( + `${testsTodo + aggregatedQuickStats.numTodoTests} todo`, + ) + ', ' + : '') + + (testsPassed + ? chalk.bold.green( + `${testsPassed + aggregatedQuickStats.numPassingTests} passed`, + ) + ', ' + : '') + + `${testsTotal + aggregatedQuickStats.numTotalTests} total`; const snapshots = chalk.bold('Snapshots: ') + diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 863e10b8b128..7a827a40d10a 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -61,7 +61,7 @@ class TestRunner { watcher: JestTestWatcher, options: JestTestRunnerOptions, ): Promise { - return await (options.serial + return await (false ? this._createInBandTestRun(tests, watcher) : this._createParallelTestRun(tests, watcher)); } @@ -154,7 +154,11 @@ class TestRunner { path: test.path, }) as PromiseWithCustomMessage; - // promise.onCustomMessage((message: any) => {}) + if (promise.onCustomMessage) { + promise.onCustomMessage(([event, payload]: any) => { + this.eventEmitter.emit(event, payload); + }); + } return promise; }); diff --git a/packages/jest-worker/src/workers/processChild.ts b/packages/jest-worker/src/workers/processChild.ts index 96a298cf33e9..e166f19e1ed4 100644 --- a/packages/jest-worker/src/workers/processChild.ts +++ b/packages/jest-worker/src/workers/processChild.ts @@ -63,7 +63,6 @@ function reportSuccess(result: any) { if (!process || !process.send) { throw new Error('Child can only be used on a forked process'); } - process.send([PARENT_MESSAGE_OK, result]); } diff --git a/packages/jest-worker/src/workers/sendCustomMessageToParent.ts b/packages/jest-worker/src/workers/sendCustomMessageToParent.ts index 5b71011ba5d7..2334e08379e4 100644 --- a/packages/jest-worker/src/workers/sendCustomMessageToParent.ts +++ b/packages/jest-worker/src/workers/sendCustomMessageToParent.ts @@ -9,12 +9,12 @@ const isWorkerThread = () => { } }; -const sendCustomMessageToParent = (message: any) => { +const sendCustomMessageToParent = (message: any, parentProcess: NodeJS.Process = process) => { if (isWorkerThread()) { const {parentPort} = require('worker_threads'); parentPort.postMessage([PARENT_MESSAGE_CUSTOM, message]); - } else if (typeof process.send === 'function') { - process.send([PARENT_MESSAGE_CUSTOM, message]); + } else if (typeof parentProcess.send === 'function') { + parentProcess.send([PARENT_MESSAGE_CUSTOM, message]); } else { throw new Error( 'sendCustomMessageToParent can only be used inside a worker', From d13455f9bf66ecb96931b7a269e0a8d5c476d21a Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Mon, 30 Sep 2019 10:38:10 -0700 Subject: [PATCH 05/43] WIP --- .../jestAdapterInit.ts | 160 +++++------------- .../jest-circus/src/testCaseReportHandler.ts | 30 ++++ packages/jest-circus/src/utils.ts | 56 +++++- packages/jest-worker/src/hello.js | 14 -- packages/jest-worker/src/index.ts | 4 +- ...tomMessageToParent.ts => messageParent.ts} | 11 +- 6 files changed, 138 insertions(+), 137 deletions(-) create mode 100644 packages/jest-circus/src/testCaseReportHandler.ts delete mode 100644 packages/jest-worker/src/hello.js rename packages/jest-worker/src/workers/{sendCustomMessageToParent.ts => messageParent.ts} (68%) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index f83316bbedf5..0cd57f313db5 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -12,8 +12,6 @@ import { Status, TestResult, createEmptyTestResult, - TestCase, - Test, } from '@jest/test-result'; import {extractExpectedAssertionsErrors, getState, setState} from 'expect'; import {formatExecError, formatResultsErrors} from 'jest-message-util'; @@ -30,67 +28,13 @@ import { dispatch, getState as getRunnerState, } from '../state'; -import {getTestID, makeRunResult} from '../utils'; +import {getTestID} from '../utils'; import run from '../run'; -import {messageParent} from 'jest-worker'; import globals from '..'; -import {TestEntry, DescribeBlock} from '@jest/types/build/Circus'; +import testCaseReportHandler from '../testCaseReportHandler'; type Process = NodeJS.Process; -const parseTestResults = (testResults: Circus.TestResult[]) => { - let numFailingTests = 0; - let numPassingTests = 0; - let numPendingTests = 0; - let numTodoTests = 0; - - const assertionResults: Array = testResults.map( - testResult => { - let status: Status; - if (testResult.status === 'skip') { - status = 'pending'; - numPendingTests += 1; - } else if (testResult.status === 'todo') { - status = 'todo'; - numTodoTests += 1; - } else if (testResult.errors.length) { - status = 'failed'; - numFailingTests += 1; - } else { - status = 'passed'; - numPassingTests += 1; - } - - const ancestorTitles = testResult.testPath.filter( - name => name !== ROOT_DESCRIBE_BLOCK_NAME, - ); - const title = ancestorTitles.pop(); - - return { - ancestorTitles, - duration: testResult.duration, - failureMessages: testResult.errors, - fullName: title - ? ancestorTitles.concat(title).join(' ') - : ancestorTitles.join(' '), - invocations: testResult.invocations, - location: testResult.location, - numPassingAsserts: 0, - status, - title: testResult.testPath[testResult.testPath.length - 1], - }; - }, - ); - - return { - numFailingTests, - numPassingTests, - numPendingTests, - numTodoTests, - assertionResults, - }; -}; - export const initialize = ({ config, environment, @@ -195,7 +139,7 @@ export const initialize = ({ setState({snapshotState, testPath}); addEventHandler(handleSnapshotStateAfterRetry(snapshotState)); - addEventHandler(reportTestEvents(testPath, parentProcess)); + addEventHandler(testCaseReportHandler(testPath, parentProcess)); // Return it back to the outer scope (test runner outside the VM). return {globals, snapshotState}; @@ -212,13 +156,48 @@ export const runAndTransformResultsToJestFormat = async ({ }): Promise => { const runResult: Circus.RunResult = await run(); - const { - numFailingTests, - numPassingTests, - numPendingTests, - numTodoTests, - assertionResults, - } = parseTestResults(runResult.testResults); + let numFailingTests = 0; + let numPassingTests = 0; + let numPendingTests = 0; + let numTodoTests = 0; + + const assertionResults: Array = runResult.testResults.map( + testResult => { + let status: Status; + if (testResult.status === 'skip') { + status = 'pending'; + numPendingTests += 1; + } else if (testResult.status === 'todo') { + status = 'todo'; + numTodoTests += 1; + } else if (testResult.errors.length) { + status = 'failed'; + numFailingTests += 1; + } else { + status = 'passed'; + numPassingTests += 1; + } + + const ancestorTitles = testResult.testPath.filter( + name => name !== ROOT_DESCRIBE_BLOCK_NAME, + ); + const title = ancestorTitles.pop(); + + return { + ancestorTitles, + duration: testResult.duration, + failureMessages: testResult.errors, + fullName: title + ? ancestorTitles.concat(title).join(' ') + : ancestorTitles.join(' '), + invocations: testResult.invocations, + location: testResult.location, + numPassingAsserts: 0, + status, + title: testResult.testPath[testResult.testPath.length - 1], + }; + }, + ); let failureMessage = formatResultsErrors( assertionResults, @@ -258,55 +237,6 @@ export const runAndTransformResultsToJestFormat = async ({ }; }; -const getAncestorTitles = (testEntry: TestEntry) => { - let current: TestEntry | DescribeBlock | undefined = testEntry; - const titles = []; - while (current && current.name !== ROOT_DESCRIBE_BLOCK_NAME) { - titles.push(current.name); - current = current.parent; - } - - return titles.reverse(); -}; - -const reportTestEvents = (testPath: string, parentProcess: NodeJS.Process) => ( - event: Circus.Event, -) => { - // const toTestCase = (test: TestEntry) => { - // const ancestorTitles = getAncestorTitles(test); - // const title = ancestorTitles.pop() as string; - // const testCase: TestCase = { - // ancestorTitles, - // title, - // location: null, - // fullName: title - // ? ancestorTitles.concat(title).join(' ') - // : ancestorTitles.join(' '), - // }; - // return testCase; - // }; - switch (event.name) { - case 'test_done': { - const quickStats = - event.test.errors.length === 0 - ? { - testPath, - numFailingTests: 0, - numPassingTests: 1, - numPendingTests: 0, - } - : { - testPath, - numFailingTests: 1, - numPassingTests: 0, - numPendingTests: 0, - }; - messageParent(['test-case-result', [quickStats]], parentProcess); - break; - } - } -}; - const handleSnapshotStateAfterRetry = (snapshotState: SnapshotStateType) => ( event: Circus.Event, ) => { diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts new file mode 100644 index 000000000000..632c12bc652a --- /dev/null +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -0,0 +1,30 @@ +import {Circus} from '@jest/types'; +import {messageParent} from 'jest-worker'; + +const testCaseReportHandler = ( + testPath: string, + parentProcess: NodeJS.Process, +) => (event: Circus.Event) => { + switch (event.name) { + case 'test_done': { + const quickStats = + event.test.errors.length === 0 + ? { + testPath, + numFailingTests: 0, + numPassingTests: 1, + numPendingTests: 0, + } + : { + testPath, + numFailingTests: 1, + numPassingTests: 0, + numPendingTests: 0, + }; + messageParent(['test-case-result', [quickStats]], parentProcess); + break; + } + } +}; + +export default testCaseReportHandler; diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index 284239484594..e4a117f1d87d 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -11,7 +11,8 @@ import isGeneratorFn from 'is-generator-fn'; import co from 'co'; import StackUtils = require('stack-utils'); import prettyFormat = require('pretty-format'); -import {getState} from './state'; +import {getState, ROOT_DESCRIBE_BLOCK_NAME} from './state'; +import {AssertionResult, Status} from '@jest/test-result'; const stackUtils = new StackUtils({cwd: 'A path that does not exist'}); @@ -354,3 +355,56 @@ export const invariant = (condition: unknown, message?: string) => { throw new Error(message); } }; + +export const parseTestResults = (testResults: Circus.TestResult[]) => { + let numFailingTests = 0; + let numPassingTests = 0; + let numPendingTests = 0; + let numTodoTests = 0; + + const assertionResults: Array = testResults.map( + testResult => { + let status: Status; + if (testResult.status === 'skip') { + status = 'pending'; + numPendingTests += 1; + } else if (testResult.status === 'todo') { + status = 'todo'; + numTodoTests += 1; + } else if (testResult.errors.length) { + status = 'failed'; + numFailingTests += 1; + } else { + status = 'passed'; + numPassingTests += 1; + } + + const ancestorTitles = testResult.testPath.filter( + name => name !== ROOT_DESCRIBE_BLOCK_NAME, + ); + const title = ancestorTitles.pop(); + + return { + ancestorTitles, + duration: testResult.duration, + failureMessages: testResult.errors, + fullName: title + ? ancestorTitles.concat(title).join(' ') + : ancestorTitles.join(' '), + invocations: testResult.invocations, + location: testResult.location, + numPassingAsserts: 0, + status, + title: testResult.testPath[testResult.testPath.length - 1], + }; + }, + ); + + return { + numFailingTests, + numPassingTests, + numPendingTests, + numTodoTests, + assertionResults, + }; +}; diff --git a/packages/jest-worker/src/hello.js b/packages/jest-worker/src/hello.js deleted file mode 100644 index 6f10cce04ede..000000000000 --- a/packages/jest-worker/src/hello.js +++ /dev/null @@ -1,14 +0,0 @@ -const { default: Worker } = require('jest-worker'); - - -const myWorker = new Worker(require.resolve('./__performance_tests__/workers/pi.js'), { - numWorkers: 4, - enableWorkerThreads: true - }); - -const promise = myWorker.default(); - -promise.onCustomMessage((message) => { - console.log(message) -}) -promise.then(console.log).then(() => process.exit()) \ No newline at end of file diff --git a/packages/jest-worker/src/index.ts b/packages/jest-worker/src/index.ts index 8755d2628186..a56a9ff270b2 100644 --- a/packages/jest-worker/src/index.ts +++ b/packages/jest-worker/src/index.ts @@ -15,7 +15,7 @@ import { WorkerPoolOptions, PromiseWithCustomMessage, } from './types'; -import sendCustomMessageToParent from './workers/sendCustomMessageToParent'; +import _messageParent from './workers/messageParent'; function getExposedMethods( workerPath: string, @@ -150,4 +150,4 @@ export default class JestWorker { } export {PromiseWithCustomMessage}; -export const messageParent = sendCustomMessageToParent; +export const messageParent = _messageParent; diff --git a/packages/jest-worker/src/workers/sendCustomMessageToParent.ts b/packages/jest-worker/src/workers/messageParent.ts similarity index 68% rename from packages/jest-worker/src/workers/sendCustomMessageToParent.ts rename to packages/jest-worker/src/workers/messageParent.ts index 2334e08379e4..7ec34b3e492b 100644 --- a/packages/jest-worker/src/workers/sendCustomMessageToParent.ts +++ b/packages/jest-worker/src/workers/messageParent.ts @@ -9,17 +9,18 @@ const isWorkerThread = () => { } }; -const sendCustomMessageToParent = (message: any, parentProcess: NodeJS.Process = process) => { +const messageParent = ( + message: any, + parentProcess: NodeJS.Process = process, +) => { if (isWorkerThread()) { const {parentPort} = require('worker_threads'); parentPort.postMessage([PARENT_MESSAGE_CUSTOM, message]); } else if (typeof parentProcess.send === 'function') { parentProcess.send([PARENT_MESSAGE_CUSTOM, message]); } else { - throw new Error( - 'sendCustomMessageToParent can only be used inside a worker', - ); + throw new Error('"messageParent" can only be used inside a worker'); } }; -export default sendCustomMessageToParent; +export default messageParent; From 4bb9b1f4d10f0e76951009befba65d4496367a63 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Mon, 30 Sep 2019 11:36:29 -0700 Subject: [PATCH 06/43] Better types --- .../jest-circus/src/testCaseReportHandler.ts | 29 ++- packages/jest-circus/src/utils.ts | 138 ++++++----- packages/jest-core/src/ReporterDispatcher.ts | 15 +- packages/jest-core/src/TestScheduler.ts | 29 ++- packages/jest-diff/src/cleanupSemantic.ts | 224 +++++++----------- packages/jest-reporters/src/Status.ts | 24 +- .../jest-reporters/src/default_reporter.ts | 17 +- packages/jest-reporters/src/types.ts | 1 + packages/jest-reporters/src/utils.ts | 38 +-- .../src/workers/NodeThreadsWorker.ts | 5 +- .../jest-worker/src/workers/processChild.ts | 1 + 11 files changed, 268 insertions(+), 253 deletions(-) diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index 632c12bc652a..d9f7819d545c 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -1,5 +1,7 @@ import {Circus} from '@jest/types'; import {messageParent} from 'jest-worker'; +import {TestCase} from '@jest/test-result'; +import {makeSingleTestResult, parseSingleTestResult} from './utils'; const testCaseReportHandler = ( testPath: string, @@ -7,21 +9,18 @@ const testCaseReportHandler = ( ) => (event: Circus.Event) => { switch (event.name) { case 'test_done': { - const quickStats = - event.test.errors.length === 0 - ? { - testPath, - numFailingTests: 0, - numPassingTests: 1, - numPendingTests: 0, - } - : { - testPath, - numFailingTests: 1, - numPassingTests: 0, - numPendingTests: 0, - }; - messageParent(['test-case-result', [quickStats]], parentProcess); + const testResult = makeSingleTestResult(event.test); + const testCaseResult = parseSingleTestResult(testResult); + const testCase: TestCase = { + fullName: testCaseResult.fullName, + location: testCaseResult.location, + title: testCaseResult.title, + ancestorTitles: testCaseResult.ancestorTitles, + }; + messageParent( + ['test-case-result', [testPath, testCase, testCaseResult]], + parentProcess, + ); break; } } diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index e4a117f1d87d..4c5df9f34f6a 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -244,50 +244,56 @@ export const makeRunResult = ( unhandledErrors: unhandledErrors.map(_formatError), }); -const makeTestResults = ( - describeBlock: Circus.DescribeBlock, -): Circus.TestResults => { +export const makeSingleTestResult = ( + test: Circus.TestEntry, +): Circus.TestResult => { const {includeTestLocationInResult} = getState(); - let testResults: Circus.TestResults = []; - for (const test of describeBlock.tests) { - const testPath = []; - let parent: Circus.TestEntry | Circus.DescribeBlock | undefined = test; - do { - testPath.unshift(parent.name); - } while ((parent = parent.parent)); - const {status} = test; + const testPath = []; + let parent: Circus.TestEntry | Circus.DescribeBlock | undefined = test; + do { + testPath.unshift(parent.name); + } while ((parent = parent.parent)); - if (!status) { - throw new Error('Status should be present after tests are run.'); - } + const {status} = test; - let location = null; - if (includeTestLocationInResult) { - const stackLine = test.asyncError.stack.split('\n')[1]; - const parsedLine = stackUtils.parseLine(stackLine); - if ( - parsedLine && - typeof parsedLine.column === 'number' && - typeof parsedLine.line === 'number' - ) { - location = { - column: parsedLine.column, - line: parsedLine.line, - }; - } - } + if (!status) { + throw new Error('Status should be present after tests are run.'); + } - testResults.push({ - duration: test.duration, - errors: test.errors.map(_formatError), - invocations: test.invocations, - location, - status, - testPath, - }); + let location = null; + if (includeTestLocationInResult) { + const stackLine = test.asyncError.stack.split('\n')[1]; + const parsedLine = stackUtils.parseLine(stackLine); + if ( + parsedLine && + typeof parsedLine.column === 'number' && + typeof parsedLine.line === 'number' + ) { + location = { + column: parsedLine.column, + line: parsedLine.line, + }; + } } + return { + duration: test.duration, + errors: test.errors.map(_formatError), + invocations: test.invocations, + location, + status, + testPath, + }; +}; + +const makeTestResults = ( + describeBlock: Circus.DescribeBlock, +): Circus.TestResults => { + let testResults: Circus.TestResults = describeBlock.tests.map( + makeSingleTestResult, + ); + for (const child of describeBlock.children) { testResults = testResults.concat(makeTestResults(child)); } @@ -356,6 +362,40 @@ export const invariant = (condition: unknown, message?: string) => { } }; +export const parseSingleTestResult = ( + testResult: Circus.TestResult, +): AssertionResult => { + let status: Status; + if (testResult.status === 'skip') { + status = 'pending'; + } else if (testResult.status === 'todo') { + status = 'todo'; + } else if (testResult.errors.length) { + status = 'failed'; + } else { + status = 'passed'; + } + + const ancestorTitles = testResult.testPath.filter( + name => name !== ROOT_DESCRIBE_BLOCK_NAME, + ); + const title = ancestorTitles.pop(); + + return { + ancestorTitles, + duration: testResult.duration, + failureMessages: testResult.errors, + fullName: title + ? ancestorTitles.concat(title).join(' ') + : ancestorTitles.join(' '), + invocations: testResult.invocations, + location: testResult.location, + numPassingAsserts: 0, + status, + title: testResult.testPath[testResult.testPath.length - 1], + }; +}; + export const parseTestResults = (testResults: Circus.TestResult[]) => { let numFailingTests = 0; let numPassingTests = 0; @@ -364,39 +404,17 @@ export const parseTestResults = (testResults: Circus.TestResult[]) => { const assertionResults: Array = testResults.map( testResult => { - let status: Status; if (testResult.status === 'skip') { - status = 'pending'; numPendingTests += 1; } else if (testResult.status === 'todo') { - status = 'todo'; numTodoTests += 1; } else if (testResult.errors.length) { - status = 'failed'; numFailingTests += 1; } else { - status = 'passed'; numPassingTests += 1; } - const ancestorTitles = testResult.testPath.filter( - name => name !== ROOT_DESCRIBE_BLOCK_NAME, - ); - const title = ancestorTitles.pop(); - - return { - ancestorTitles, - duration: testResult.duration, - failureMessages: testResult.errors, - fullName: title - ? ancestorTitles.concat(title).join(' ') - : ancestorTitles.join(' '), - invocations: testResult.invocations, - location: testResult.location, - numPassingAsserts: 0, - status, - title: testResult.testPath[testResult.testPath.length - 1], - }; + return parseSingleTestResult(testResult); }, ); diff --git a/packages/jest-core/src/ReporterDispatcher.ts b/packages/jest-core/src/ReporterDispatcher.ts index 99ac10f26c9a..f83f6a9c9171 100644 --- a/packages/jest-core/src/ReporterDispatcher.ts +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -5,7 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import {AggregatedResult, TestResult, TestCase} from '@jest/test-result'; +import { + AggregatedResult, + TestResult, + TestCase, + AssertionResult, +} from '@jest/test-result'; import {Test} from 'jest-runner'; import {Context} from 'jest-runtime'; import {Reporter, ReporterOnStartOptions} from '@jest/reporters'; @@ -62,10 +67,14 @@ export default class ReporterDispatcher { } } - async onTestCaseResult(quickStats) { + async onTestCaseResult( + test: Test, + testCase: TestCase, + testCaseResult: AssertionResult, + ) { for (const reporter of this._reporters) { reporter.onTestCaseResult && - (await reporter.onTestCaseResult(quickStats)); + (await reporter.onTestCaseResult(test, testCase, testCaseResult)); } } diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index d5cd02e91337..37b4ea05d7b9 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -27,6 +27,8 @@ import { addResult, buildFailureTestResult, makeEmptyAggregatedTestResult, + TestCase, + AssertionResult, } from '@jest/test-result'; import ReporterDispatcher from './ReporterDispatcher'; import TestWatcher from './TestWatcher'; @@ -182,12 +184,16 @@ export default class TestScheduler { }); const testRunners = Object.create(null); - contexts.forEach(({config}) => { + const contextsByTestRunner = new WeakMap(); + contexts.forEach(context => { + const {config} = context; if (!testRunners[config.runner]) { const Runner: typeof TestRunner = require(config.runner); - testRunners[config.runner] = new Runner(this._globalConfig, { + const runner = new Runner(this._globalConfig, { changedFiles: this._context && this._context.changedFiles, }); + testRunners[config.runner] = runner; + contextsByTestRunner.set(runner, context); } }); @@ -197,7 +203,9 @@ export default class TestScheduler { try { for (const runner of Object.keys(testRunners)) { const testRunner = testRunners[runner]; + const context = contextsByTestRunner.get(testRunner); const tests = testsByRunner[runner]; + const testRunnerOptions = { serial: runInBand || Boolean(testRunner.isSerial), }; @@ -219,8 +227,19 @@ export default class TestScheduler { ), testRunner.eventEmitter.on( 'test-case-result', - ([quickStats]: any) => { - this._dispatcher.onTestCaseResult(quickStats); + ([testPath, testCase, testCaseResult]: [ + Config.Path, + TestCase, + AssertionResult, + ]) => { + if (context) { + const test: TestRunner.Test = {context, path: testPath}; + this._dispatcher.onTestCaseResult( + test, + testCase, + testCaseResult, + ); + } }, ), ]; @@ -258,7 +277,7 @@ export default class TestScheduler { private _partitionTests( testRunners: Record, tests: Array, - ) { + ): Record> | null { if (Object.keys(testRunners).length > 1) { return tests.reduce((testRuns, test) => { const runner = test.context.config.runner; diff --git a/packages/jest-diff/src/cleanupSemantic.ts b/packages/jest-diff/src/cleanupSemantic.ts index 13b5f7dff325..0df74e0bc895 100644 --- a/packages/jest-diff/src/cleanupSemantic.ts +++ b/packages/jest-diff/src/cleanupSemantic.ts @@ -58,6 +58,7 @@ class Diff { } } + /** * Determine the common prefix of two strings. * @param {string} text1 First string. @@ -77,10 +78,8 @@ var diff_commonPrefix = function(text1: string, text2: string): number { var pointermid = pointermax; var pointerstart = 0; while (pointermin < pointermid) { - if ( - text1.substring(pointerstart, pointermid) == - text2.substring(pointerstart, pointermid) - ) { + if (text1.substring(pointerstart, pointermid) == + text2.substring(pointerstart, pointermid)) { pointermin = pointermid; pointerstart = pointermin; } else { @@ -91,6 +90,7 @@ var diff_commonPrefix = function(text1: string, text2: string): number { return pointermid; }; + /** * Determine the common suffix of two strings. * @param {string} text1 First string. @@ -99,11 +99,8 @@ var diff_commonPrefix = function(text1: string, text2: string): number { */ var diff_commonSuffix = function(text1: string, text2: string): number { // Quick check for common null cases. - if ( - !text1 || - !text2 || - text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1) - ) { + if (!text1 || !text2 || + text1.charAt(text1.length - 1) != text2.charAt(text2.length - 1)) { return 0; } // Binary search. @@ -113,10 +110,8 @@ var diff_commonSuffix = function(text1: string, text2: string): number { var pointermid = pointermax; var pointerend = 0; while (pointermin < pointermid) { - if ( - text1.substring(text1.length - pointermid, text1.length - pointerend) == - text2.substring(text2.length - pointermid, text2.length - pointerend) - ) { + if (text1.substring(text1.length - pointermid, text1.length - pointerend) == + text2.substring(text2.length - pointermid, text2.length - pointerend)) { pointermin = pointermid; pointerend = pointermin; } else { @@ -127,6 +122,7 @@ var diff_commonSuffix = function(text1: string, text2: string): number { return pointermid; }; + /** * Determine if the suffix of one string is the prefix of another. * @param {string} text1 First string. @@ -167,28 +163,27 @@ var diff_commonOverlap_ = function(text1: string, text2: string): number { return best; } length += found; - if ( - found == 0 || - text1.substring(text_length - length) == text2.substring(0, length) - ) { + if (found == 0 || text1.substring(text_length - length) == + text2.substring(0, length)) { best = length; length++; } } }; + /** * Reduce the number of edits by eliminating semantically trivial equalities. * @param {!Array.} diffs Array of diff tuples. */ -var diff_cleanupSemantic = function(diffs: Array) { + var diff_cleanupSemantic = function(diffs: Array) { var changes = false; - var equalities = []; // Stack of indices where equalities are found. - var equalitiesLength = 0; // Keeping our own length var is faster in JS. + var equalities = []; // Stack of indices where equalities are found. + var equalitiesLength = 0; // Keeping our own length var is faster in JS. /** @type {?string} */ var lastEquality = null; // Always equal to diffs[equalities[equalitiesLength - 1]][1] - var pointer = 0; // Index of current position. + var pointer = 0; // Index of current position. // Number of characters that changed prior to the equality. var length_insertions1 = 0; var length_deletions1 = 0; @@ -196,16 +191,14 @@ var diff_cleanupSemantic = function(diffs: Array) { var length_insertions2 = 0; var length_deletions2 = 0; while (pointer < diffs.length) { - if (diffs[pointer][0] == DIFF_EQUAL) { - // Equality found. + if (diffs[pointer][0] == DIFF_EQUAL) { // Equality found. equalities[equalitiesLength++] = pointer; length_insertions1 = length_insertions2; length_deletions1 = length_deletions2; length_insertions2 = 0; length_deletions2 = 0; lastEquality = diffs[pointer][1]; - } else { - // An insertion or deletion. + } else { // An insertion or deletion. if (diffs[pointer][0] == DIFF_INSERT) { length_insertions2 += diffs[pointer][1].length; } else { @@ -213,18 +206,13 @@ var diff_cleanupSemantic = function(diffs: Array) { } // Eliminate an equality that is smaller or equal to the edits on both // sides of it. - if ( - lastEquality && - lastEquality.length <= - Math.max(length_insertions1, length_deletions1) && - lastEquality.length <= Math.max(length_insertions2, length_deletions2) - ) { + if (lastEquality && (lastEquality.length <= + Math.max(length_insertions1, length_deletions1)) && + (lastEquality.length <= Math.max(length_insertions2, + length_deletions2))) { // Duplicate record. - diffs.splice( - equalities[equalitiesLength - 1], - 0, - new Diff(DIFF_DELETE, lastEquality), - ); + diffs.splice(equalities[equalitiesLength - 1], 0, + new Diff(DIFF_DELETE, lastEquality)); // Change second copy to insert. diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT; // Throw away the equality we just deleted. @@ -232,7 +220,7 @@ var diff_cleanupSemantic = function(diffs: Array) { // Throw away the previous equality (it needs to be reevaluated). equalitiesLength--; pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1; - length_insertions1 = 0; // Reset the counters. + length_insertions1 = 0; // Reset the counters. length_deletions1 = 0; length_insertions2 = 0; length_deletions2 = 0; @@ -257,51 +245,36 @@ var diff_cleanupSemantic = function(diffs: Array) { // Only extract an overlap if it is as big as the edit ahead or behind it. pointer = 1; while (pointer < diffs.length) { - if ( - diffs[pointer - 1][0] == DIFF_DELETE && - diffs[pointer][0] == DIFF_INSERT - ) { + if (diffs[pointer - 1][0] == DIFF_DELETE && + diffs[pointer][0] == DIFF_INSERT) { var deletion = diffs[pointer - 1][1]; var insertion = diffs[pointer][1]; var overlap_length1 = diff_commonOverlap_(deletion, insertion); var overlap_length2 = diff_commonOverlap_(insertion, deletion); if (overlap_length1 >= overlap_length2) { - if ( - overlap_length1 >= deletion.length / 2 || - overlap_length1 >= insertion.length / 2 - ) { + if (overlap_length1 >= deletion.length / 2 || + overlap_length1 >= insertion.length / 2) { // Overlap found. Insert an equality and trim the surrounding edits. - diffs.splice( - pointer, - 0, - new Diff(DIFF_EQUAL, insertion.substring(0, overlap_length1)), - ); - diffs[pointer - 1][1] = deletion.substring( - 0, - deletion.length - overlap_length1, - ); + diffs.splice(pointer, 0, new Diff(DIFF_EQUAL, + insertion.substring(0, overlap_length1))); + diffs[pointer - 1][1] = + deletion.substring(0, deletion.length - overlap_length1); diffs[pointer + 1][1] = insertion.substring(overlap_length1); pointer++; } } else { - if ( - overlap_length2 >= deletion.length / 2 || - overlap_length2 >= insertion.length / 2 - ) { + if (overlap_length2 >= deletion.length / 2 || + overlap_length2 >= insertion.length / 2) { // Reverse overlap found. // Insert an equality and swap and trim the surrounding edits. - diffs.splice( - pointer, - 0, - new Diff(DIFF_EQUAL, deletion.substring(0, overlap_length2)), - ); + diffs.splice(pointer, 0, new Diff(DIFF_EQUAL, + deletion.substring(0, overlap_length2))); diffs[pointer - 1][0] = DIFF_INSERT; - diffs[pointer - 1][1] = insertion.substring( - 0, - insertion.length - overlap_length2, - ); + diffs[pointer - 1][1] = + insertion.substring(0, insertion.length - overlap_length2); diffs[pointer + 1][0] = DIFF_DELETE; - diffs[pointer + 1][1] = deletion.substring(overlap_length2); + diffs[pointer + 1][1] = + deletion.substring(overlap_length2); pointer++; } } @@ -311,6 +284,7 @@ var diff_cleanupSemantic = function(diffs: Array) { } }; + /** * Look for single edits surrounded on both sides by equalities * which can be shifted sideways to align the edit to a word boundary. @@ -343,12 +317,18 @@ var diff_cleanupSemanticLossless = function(diffs: Array) { var char2 = two.charAt(0); var nonAlphaNumeric1 = char1.match(nonAlphaNumericRegex_); var nonAlphaNumeric2 = char2.match(nonAlphaNumericRegex_); - var whitespace1 = nonAlphaNumeric1 && char1.match(whitespaceRegex_); - var whitespace2 = nonAlphaNumeric2 && char2.match(whitespaceRegex_); - var lineBreak1 = whitespace1 && char1.match(linebreakRegex_); - var lineBreak2 = whitespace2 && char2.match(linebreakRegex_); - var blankLine1 = lineBreak1 && one.match(blanklineEndRegex_); - var blankLine2 = lineBreak2 && two.match(blanklineStartRegex_); + var whitespace1 = nonAlphaNumeric1 && + char1.match(whitespaceRegex_); + var whitespace2 = nonAlphaNumeric2 && + char2.match(whitespaceRegex_); + var lineBreak1 = whitespace1 && + char1.match(linebreakRegex_); + var lineBreak2 = whitespace2 && + char2.match(linebreakRegex_); + var blankLine1 = lineBreak1 && + one.match(blanklineEndRegex_); + var blankLine2 = lineBreak2 && + two.match(blanklineStartRegex_); if (blankLine1 || blankLine2) { // Five points for blank lines. @@ -372,10 +352,8 @@ var diff_cleanupSemanticLossless = function(diffs: Array) { var pointer = 1; // Intentionally ignore the first and last element (don't need checking). while (pointer < diffs.length - 1) { - if ( - diffs[pointer - 1][0] == DIFF_EQUAL && - diffs[pointer + 1][0] == DIFF_EQUAL - ) { + if (diffs[pointer - 1][0] == DIFF_EQUAL && + diffs[pointer + 1][0] == DIFF_EQUAL) { // This is a single edit surrounded by equalities. var equality1 = diffs[pointer - 1][1]; var edit = diffs[pointer][1]; @@ -394,16 +372,14 @@ var diff_cleanupSemanticLossless = function(diffs: Array) { var bestEquality1 = equality1; var bestEdit = edit; var bestEquality2 = equality2; - var bestScore = - diff_cleanupSemanticScore_(equality1, edit) + - diff_cleanupSemanticScore_(edit, equality2); + var bestScore = diff_cleanupSemanticScore_(equality1, edit) + + diff_cleanupSemanticScore_(edit, equality2); while (edit.charAt(0) === equality2.charAt(0)) { equality1 += edit.charAt(0); edit = edit.substring(1) + equality2.charAt(0); equality2 = equality2.substring(1); - var score = - diff_cleanupSemanticScore_(equality1, edit) + - diff_cleanupSemanticScore_(edit, equality2); + var score = diff_cleanupSemanticScore_(equality1, edit) + + diff_cleanupSemanticScore_(edit, equality2); // The >= encourages trailing rather than leading whitespace on edits. if (score >= bestScore) { bestScore = score; @@ -434,6 +410,7 @@ var diff_cleanupSemanticLossless = function(diffs: Array) { } }; + // Define some regex patterns for matching boundaries. var nonAlphaNumericRegex_ = /[^a-zA-Z0-9]/; var whitespaceRegex_ = /\s/; @@ -441,6 +418,7 @@ var linebreakRegex_ = /[\r\n]/; var blanklineEndRegex_ = /\n\r?\n$/; var blanklineStartRegex_ = /^\r?\n\r?\n/; + /** * Reorder and merge like edit sections. Merge equalities. * Any edit section can move as long as it doesn't cross an equality. @@ -474,20 +452,14 @@ var diff_cleanupMerge = function(diffs: Array) { // Factor out any common prefixies. commonlength = diff_commonPrefix(text_insert, text_delete); if (commonlength !== 0) { - if ( - pointer - count_delete - count_insert > 0 && - diffs[pointer - count_delete - count_insert - 1][0] == - DIFF_EQUAL - ) { - diffs[ - pointer - count_delete - count_insert - 1 - ][1] += text_insert.substring(0, commonlength); + if ((pointer - count_delete - count_insert) > 0 && + diffs[pointer - count_delete - count_insert - 1][0] == + DIFF_EQUAL) { + diffs[pointer - count_delete - count_insert - 1][1] += + text_insert.substring(0, commonlength); } else { - diffs.splice( - 0, - 0, - new Diff(DIFF_EQUAL, text_insert.substring(0, commonlength)), - ); + diffs.splice(0, 0, new Diff(DIFF_EQUAL, + text_insert.substring(0, commonlength))); pointer++; } text_insert = text_insert.substring(commonlength); @@ -496,28 +468,25 @@ var diff_cleanupMerge = function(diffs: Array) { // Factor out any common suffixies. commonlength = diff_commonSuffix(text_insert, text_delete); if (commonlength !== 0) { - diffs[pointer][1] = - text_insert.substring(text_insert.length - commonlength) + - diffs[pointer][1]; - text_insert = text_insert.substring( - 0, - text_insert.length - commonlength, - ); - text_delete = text_delete.substring( - 0, - text_delete.length - commonlength, - ); + diffs[pointer][1] = text_insert.substring(text_insert.length - + commonlength) + diffs[pointer][1]; + text_insert = text_insert.substring(0, text_insert.length - + commonlength); + text_delete = text_delete.substring(0, text_delete.length - + commonlength); } } // Delete the offending records and add the merged ones. pointer -= count_delete + count_insert; diffs.splice(pointer, count_delete + count_insert); if (text_delete.length) { - diffs.splice(pointer, 0, new Diff(DIFF_DELETE, text_delete)); + diffs.splice(pointer, 0, + new Diff(DIFF_DELETE, text_delete)); pointer++; } if (text_insert.length) { - diffs.splice(pointer, 0, new Diff(DIFF_INSERT, text_insert)); + diffs.splice(pointer, 0, + new Diff(DIFF_INSERT, text_insert)); pointer++; } pointer++; @@ -536,7 +505,7 @@ var diff_cleanupMerge = function(diffs: Array) { } } if (diffs[diffs.length - 1][1] === '') { - diffs.pop(); // Remove the dummy entry at the end. + diffs.pop(); // Remove the dummy entry at the end. } // Second pass: look for single edits surrounded on both sides by equalities @@ -546,35 +515,25 @@ var diff_cleanupMerge = function(diffs: Array) { pointer = 1; // Intentionally ignore the first and last element (don't need checking). while (pointer < diffs.length - 1) { - if ( - diffs[pointer - 1][0] == DIFF_EQUAL && - diffs[pointer + 1][0] == DIFF_EQUAL - ) { + if (diffs[pointer - 1][0] == DIFF_EQUAL && + diffs[pointer + 1][0] == DIFF_EQUAL) { // This is a single edit surrounded by equalities. - if ( - diffs[pointer][1].substring( - diffs[pointer][1].length - diffs[pointer - 1][1].length, - ) == diffs[pointer - 1][1] - ) { + if (diffs[pointer][1].substring(diffs[pointer][1].length - + diffs[pointer - 1][1].length) == diffs[pointer - 1][1]) { // Shift the edit over the previous equality. - diffs[pointer][1] = - diffs[pointer - 1][1] + - diffs[pointer][1].substring( - 0, - diffs[pointer][1].length - diffs[pointer - 1][1].length, - ); + diffs[pointer][1] = diffs[pointer - 1][1] + + diffs[pointer][1].substring(0, diffs[pointer][1].length - + diffs[pointer - 1][1].length); diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1]; diffs.splice(pointer - 1, 1); changes = true; - } else if ( - diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) == - diffs[pointer + 1][1] - ) { + } else if (diffs[pointer][1].substring(0, diffs[pointer + 1][1].length) == + diffs[pointer + 1][1]) { // Shift the edit over the next equality. diffs[pointer - 1][1] += diffs[pointer + 1][1]; diffs[pointer][1] = - diffs[pointer][1].substring(diffs[pointer + 1][1].length) + - diffs[pointer + 1][1]; + diffs[pointer][1].substring(diffs[pointer + 1][1].length) + + diffs[pointer + 1][1]; diffs.splice(pointer + 1, 1); changes = true; } @@ -587,6 +546,7 @@ var diff_cleanupMerge = function(diffs: Array) { } }; + export { Diff, DIFF_EQUAL, diff --git a/packages/jest-reporters/src/Status.ts b/packages/jest-reporters/src/Status.ts index 4535fb9f2f77..e93e75c0d887 100644 --- a/packages/jest-reporters/src/Status.ts +++ b/packages/jest-reporters/src/Status.ts @@ -6,10 +6,10 @@ */ import {Config} from '@jest/types'; -import {AggregatedResult, TestResult} from '@jest/test-result'; +import {AggregatedResult, TestResult, AssertionResult} from '@jest/test-result'; import chalk from 'chalk'; import stringLength = require('string-length'); -import {ReporterOnStartOptions} from './types'; +import {ReporterOnStartOptions, Test} from './types'; import { getSummary, printDisplayName, @@ -56,7 +56,6 @@ class CurrentTestList { return this._array; } } - /** * A class that generates the CLI status of currently running tests * and also provides an ANSI escape sequence to remove status lines @@ -66,7 +65,10 @@ export default class Status { private _cache: {content: string; clear: string} | null; private _callback?: () => void; private _currentTests: CurrentTestList; - private _currentQuickStats: any[]; + private _currentTestCases: Array<{ + test: Test; + testCaseResult: AssertionResult; + }>; private _done: boolean; private _emitScheduled: boolean; private _estimatedTime: number; @@ -77,7 +79,7 @@ export default class Status { constructor() { this._cache = null; this._currentTests = new CurrentTestList(); - this._currentQuickStats = []; + this._currentTestCases = []; this._done = false; this._emitScheduled = false; this._estimatedTime = 0; @@ -105,8 +107,8 @@ export default class Status { this._emit(); } - addQuickStats(quickStats) { - this._currentQuickStats.push(quickStats); + addTestCaseResult(test: Test, testCaseResult: AssertionResult) { + this._currentTestCases.push({test, testCaseResult}); if (!this._showStatus) { this._emit(); } else { @@ -130,10 +132,10 @@ export default class Status { ) { const {testFilePath} = testResult; this._aggregatedResults = aggregatedResults; - this._currentQuickStats = this._currentQuickStats.filter( - quickStats => quickStats.testPath !== testFilePath, - ); this._currentTests.delete(testFilePath); + this._currentTestCases = this._currentTestCases.filter(({test}) => + _config === test.context.config ? test.path !== testFilePath : true, + ); this._debouncedEmit(); } @@ -170,7 +172,7 @@ export default class Status { content += '\n' + getSummary(this._aggregatedResults, { - currentQuickStats: this._currentQuickStats, + currentTestCases: this._currentTestCases, estimatedTime: this._estimatedTime, roundTime: true, width, diff --git a/packages/jest-reporters/src/default_reporter.ts b/packages/jest-reporters/src/default_reporter.ts index f085a3fa7383..414f775442b7 100644 --- a/packages/jest-reporters/src/default_reporter.ts +++ b/packages/jest-reporters/src/default_reporter.ts @@ -6,7 +6,12 @@ */ import {Config} from '@jest/types'; -import {AggregatedResult, TestResult} from '@jest/test-result'; +import { + AggregatedResult, + TestResult, + TestCase, + AssertionResult, +} from '@jest/test-result'; import {clearLine, isInteractive} from 'jest-util'; import {getConsoleOutput} from '@jest/console'; import chalk from 'chalk'; @@ -130,10 +135,12 @@ export default class DefaultReporter extends BaseReporter { this._status.testStarted(test.path, test.context.config); } - onTestCaseResult(quickStats) { - // console.log({quickStats}); - this._status.addQuickStats(quickStats); - // console.log('Test case result from reporter'); + onTestCaseResult( + test: Test, + testCase: TestCase, + testCaseResult: AssertionResult, + ) { + this._status.addTestCaseResult(test, testCaseResult); } onRunComplete() { diff --git a/packages/jest-reporters/src/types.ts b/packages/jest-reporters/src/types.ts index 0a22b8e02413..a3492bbc63c3 100644 --- a/packages/jest-reporters/src/types.ts +++ b/packages/jest-reporters/src/types.ts @@ -88,6 +88,7 @@ export interface Reporter { } export type SummaryOptions = { + currentTestCases?: Array<{test: Test; testCaseResult: AssertionResult}>; estimatedTime?: number; roundTime?: boolean; width?: number; diff --git a/packages/jest-reporters/src/utils.ts b/packages/jest-reporters/src/utils.ts index 62c824b427ba..aeba8ec6c89a 100644 --- a/packages/jest-reporters/src/utils.ts +++ b/packages/jest-reporters/src/utils.ts @@ -7,11 +7,11 @@ import * as path from 'path'; import {Config} from '@jest/types'; -import {AggregatedResult} from '@jest/test-result'; +import {AggregatedResult, AssertionResult} from '@jest/test-result'; import chalk from 'chalk'; import slash = require('slash'); import {pluralize} from 'jest-util'; -import {SummaryOptions} from './types'; +import {SummaryOptions, Test} from './types'; const PROGRESS_BAR_WIDTH = 40; @@ -94,17 +94,20 @@ export const relativePath = ( return {basename, dirname}; }; -const getCurrentQuickStatsValues = (currentQuickStats = []) => { +const getValuesCurrentTestCases = ( + currentTestCases: Array<{test: Test; testCaseResult: AssertionResult}> = [], +) => { let numFailingTests = 0; let numPassingTests = 0; let numPendingTests = 0; let numTodoTests = 0; - - currentQuickStats.forEach(quickStat => { - numFailingTests += quickStat.numFailingTests || 0; - numPassingTests += quickStat.numPassingTests || 0; - numPendingTests += quickStat.numPendingTests || 0; - numTodoTests += quickStat.numTodoTests || 0; + let numTotalTests = 0; + currentTestCases.forEach(({testCaseResult: {status}}) => { + numFailingTests += status === 'failed' ? 1 : 0; + numPassingTests += status === 'passed' ? 1 : 0; + numPendingTests += status === 'skipped' ? 1 : 0; + numTodoTests += status === 'todo' ? 1 : 0; + numTotalTests += 1; }); return { @@ -112,8 +115,7 @@ const getCurrentQuickStatsValues = (currentQuickStats = []) => { numPassingTests, numPendingTests, numTodoTests, - numTotalTests: - numFailingTests + numPassingTests + numPendingTests + numTodoTests, + numTotalTests, }; }; @@ -126,8 +128,8 @@ export const getSummary = ( runTime = Math.floor(runTime); } - const aggregatedQuickStats = getCurrentQuickStatsValues( - options.currentQuickStats, + const valuesForCurrentTestCases = getValuesCurrentTestCases( + options ? options.currentTestCases : [], ); // console.log(aggregatedQuickStats.numPassingTests); @@ -169,25 +171,25 @@ export const getSummary = ( chalk.bold('Tests: ') + (testsFailed ? chalk.bold.red( - `${testsFailed + aggregatedQuickStats.numFailingTests} failed`, + `${testsFailed + valuesForCurrentTestCases.numFailingTests} failed`, ) + ', ' : '') + (testsPending ? chalk.bold.yellow( - `${testsPending + aggregatedQuickStats.numPendingTests} skipped`, + `${testsPending + valuesForCurrentTestCases.numPendingTests} skipped`, ) + ', ' : '') + (testsTodo ? chalk.bold.magenta( - `${testsTodo + aggregatedQuickStats.numTodoTests} todo`, + `${testsTodo + valuesForCurrentTestCases.numTodoTests} todo`, ) + ', ' : '') + (testsPassed ? chalk.bold.green( - `${testsPassed + aggregatedQuickStats.numPassingTests} passed`, + `${testsPassed + valuesForCurrentTestCases.numPassingTests} passed`, ) + ', ' : '') + - `${testsTotal + aggregatedQuickStats.numTotalTests} total`; + `${testsTotal + valuesForCurrentTestCases.numTotalTests} total`; const snapshots = chalk.bold('Snapshots: ') + diff --git a/packages/jest-worker/src/workers/NodeThreadsWorker.ts b/packages/jest-worker/src/workers/NodeThreadsWorker.ts index b0f543be5841..a39cc6e94520 100644 --- a/packages/jest-worker/src/workers/NodeThreadsWorker.ts +++ b/packages/jest-worker/src/workers/NodeThreadsWorker.ts @@ -20,11 +20,11 @@ import { PARENT_MESSAGE_CLIENT_ERROR, PARENT_MESSAGE_OK, PARENT_MESSAGE_SETUP_ERROR, + PARENT_MESSAGE_CUSTOM, ParentMessage, WorkerInterface, WorkerOptions, OnCustomMessage, - PARENT_MESSAGE_CUSTOM, } from '../types'; export default class ExperimentalWorker implements WorkerInterface { @@ -175,9 +175,6 @@ export default class ExperimentalWorker implements WorkerInterface { this._onProcessEnd(error, null); break; - case PARENT_MESSAGE_OK: - this._onCustomMessage(response[1]); - break; case PARENT_MESSAGE_CUSTOM: this._onCustomMessage(response[1]); break; diff --git a/packages/jest-worker/src/workers/processChild.ts b/packages/jest-worker/src/workers/processChild.ts index e166f19e1ed4..96a298cf33e9 100644 --- a/packages/jest-worker/src/workers/processChild.ts +++ b/packages/jest-worker/src/workers/processChild.ts @@ -63,6 +63,7 @@ function reportSuccess(result: any) { if (!process || !process.send) { throw new Error('Child can only be used on a forked process'); } + process.send([PARENT_MESSAGE_OK, result]); } From 4d475c1dfc7936af918fa1358bb57f78bb8bdef2 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Mon, 30 Sep 2019 11:56:25 -0700 Subject: [PATCH 07/43] Update types --- packages/jest-circus/src/testCaseReportHandler.ts | 4 ++-- packages/jest-core/src/ReporterDispatcher.ts | 4 ++-- packages/jest-reporters/src/Status.ts | 6 +++--- packages/jest-reporters/src/default_reporter.ts | 6 +++--- packages/jest-reporters/src/types.ts | 6 +++--- packages/jest-reporters/src/utils.ts | 4 ++-- packages/jest-runner/src/index.ts | 2 +- packages/jest-test-result/src/index.ts | 1 + packages/jest-test-result/src/types.ts | 2 ++ 9 files changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index d9f7819d545c..ac233be0fa4b 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -1,6 +1,6 @@ import {Circus} from '@jest/types'; import {messageParent} from 'jest-worker'; -import {TestCase} from '@jest/test-result'; +import {TestCase, TestCaseResult} from '@jest/test-result'; import {makeSingleTestResult, parseSingleTestResult} from './utils'; const testCaseReportHandler = ( @@ -10,7 +10,7 @@ const testCaseReportHandler = ( switch (event.name) { case 'test_done': { const testResult = makeSingleTestResult(event.test); - const testCaseResult = parseSingleTestResult(testResult); + const testCaseResult: TestCaseResult = parseSingleTestResult(testResult); const testCase: TestCase = { fullName: testCaseResult.fullName, location: testCaseResult.location, diff --git a/packages/jest-core/src/ReporterDispatcher.ts b/packages/jest-core/src/ReporterDispatcher.ts index f83f6a9c9171..65dac81e8dc7 100644 --- a/packages/jest-core/src/ReporterDispatcher.ts +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -9,7 +9,7 @@ import { AggregatedResult, TestResult, TestCase, - AssertionResult, + TestCaseResult, } from '@jest/test-result'; import {Test} from 'jest-runner'; import {Context} from 'jest-runtime'; @@ -70,7 +70,7 @@ export default class ReporterDispatcher { async onTestCaseResult( test: Test, testCase: TestCase, - testCaseResult: AssertionResult, + testCaseResult: TestCaseResult, ) { for (const reporter of this._reporters) { reporter.onTestCaseResult && diff --git a/packages/jest-reporters/src/Status.ts b/packages/jest-reporters/src/Status.ts index e93e75c0d887..5f3d2acfd062 100644 --- a/packages/jest-reporters/src/Status.ts +++ b/packages/jest-reporters/src/Status.ts @@ -6,7 +6,7 @@ */ import {Config} from '@jest/types'; -import {AggregatedResult, TestResult, AssertionResult} from '@jest/test-result'; +import {AggregatedResult, TestResult, TestCaseResult} from '@jest/test-result'; import chalk from 'chalk'; import stringLength = require('string-length'); import {ReporterOnStartOptions, Test} from './types'; @@ -67,7 +67,7 @@ export default class Status { private _currentTests: CurrentTestList; private _currentTestCases: Array<{ test: Test; - testCaseResult: AssertionResult; + testCaseResult: TestCaseResult; }>; private _done: boolean; private _emitScheduled: boolean; @@ -107,7 +107,7 @@ export default class Status { this._emit(); } - addTestCaseResult(test: Test, testCaseResult: AssertionResult) { + addTestCaseResult(test: Test, testCaseResult: TestCaseResult) { this._currentTestCases.push({test, testCaseResult}); if (!this._showStatus) { this._emit(); diff --git a/packages/jest-reporters/src/default_reporter.ts b/packages/jest-reporters/src/default_reporter.ts index 414f775442b7..961263610ddc 100644 --- a/packages/jest-reporters/src/default_reporter.ts +++ b/packages/jest-reporters/src/default_reporter.ts @@ -10,7 +10,7 @@ import { AggregatedResult, TestResult, TestCase, - AssertionResult, + TestCaseResult, } from '@jest/test-result'; import {clearLine, isInteractive} from 'jest-util'; import {getConsoleOutput} from '@jest/console'; @@ -137,8 +137,8 @@ export default class DefaultReporter extends BaseReporter { onTestCaseResult( test: Test, - testCase: TestCase, - testCaseResult: AssertionResult, + _testCase: TestCase, + testCaseResult: TestCaseResult, ) { this._status.addTestCaseResult(test, testCaseResult); } diff --git a/packages/jest-reporters/src/types.ts b/packages/jest-reporters/src/types.ts index a3492bbc63c3..f80a592243d2 100644 --- a/packages/jest-reporters/src/types.ts +++ b/packages/jest-reporters/src/types.ts @@ -10,8 +10,8 @@ import { AggregatedResult, SerializableError, TestResult, - AssertionResult, TestCase, + TestCaseResult, } from '@jest/test-result'; import {JestEnvironment as Environment} from '@jest/environment'; import {FS as HasteFS, ModuleMap} from 'jest-haste-map'; @@ -68,7 +68,7 @@ export interface Reporter { readonly onTestCaseResult?: ( test: Test, testCase: TestCase, - testCaseResult: AssertionResult, + testCaseResult: TestCaseResult, ) => Promise | void; readonly onRunStart: ( results: AggregatedResult, @@ -88,7 +88,7 @@ export interface Reporter { } export type SummaryOptions = { - currentTestCases?: Array<{test: Test; testCaseResult: AssertionResult}>; + currentTestCases?: Array<{test: Test; testCaseResult: TestCaseResult}>; estimatedTime?: number; roundTime?: boolean; width?: number; diff --git a/packages/jest-reporters/src/utils.ts b/packages/jest-reporters/src/utils.ts index aeba8ec6c89a..b5e4cf9fd0f0 100644 --- a/packages/jest-reporters/src/utils.ts +++ b/packages/jest-reporters/src/utils.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import {Config} from '@jest/types'; -import {AggregatedResult, AssertionResult} from '@jest/test-result'; +import {AggregatedResult, TestCaseResult} from '@jest/test-result'; import chalk from 'chalk'; import slash = require('slash'); import {pluralize} from 'jest-util'; @@ -95,7 +95,7 @@ export const relativePath = ( }; const getValuesCurrentTestCases = ( - currentTestCases: Array<{test: Test; testCaseResult: AssertionResult}> = [], + currentTestCases: Array<{test: Test; testCaseResult: TestCaseResult}> = [], ) => { let numFailingTests = 0; let numPassingTests = 0; diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 7a827a40d10a..faf80f48fbcd 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -61,7 +61,7 @@ class TestRunner { watcher: JestTestWatcher, options: JestTestRunnerOptions, ): Promise { - return await (false + return await (options.serial ? this._createInBandTestRun(tests, watcher) : this._createParallelTestRun(tests, watcher)); } diff --git a/packages/jest-test-result/src/index.ts b/packages/jest-test-result/src/index.ts index 2a08706efcec..acd9c982b8f7 100644 --- a/packages/jest-test-result/src/index.ts +++ b/packages/jest-test-result/src/index.ts @@ -25,4 +25,5 @@ export { Suite, TestResult, TestCase, + TestCaseResult, } from './types'; diff --git a/packages/jest-test-result/src/types.ts b/packages/jest-test-result/src/types.ts index afc97fca4f02..5b6a9a3095e0 100644 --- a/packages/jest-test-result/src/types.ts +++ b/packages/jest-test-result/src/types.ts @@ -100,6 +100,8 @@ export type Suite = { tests: Array; }; +export type TestCaseResult = AssertionResult; + export type TestCase = { ancestorTitles: Array; fullName: string; From c0cd04f594f3c1daf36a21fef4d1c1a656a64d7f Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Mon, 30 Sep 2019 13:09:46 -0700 Subject: [PATCH 08/43] Add support for runInBand --- .../src/legacy-code-todo-rewrite/jestAdapter.ts | 2 ++ .../src/legacy-code-todo-rewrite/jestAdapterInit.ts | 6 +++++- packages/jest-circus/src/testCaseReportHandler.ts | 12 ++++++------ packages/jest-runner/src/index.ts | 8 ++++++++ packages/jest-runner/src/runTest.ts | 9 +++++++++ packages/jest-runner/src/testWorker.ts | 6 ++++++ 6 files changed, 36 insertions(+), 7 deletions(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index 202744c87b54..debdc139ba94 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -20,6 +20,7 @@ const jestAdapter = async ( environment: JestEnvironment, runtime: Runtime, testPath: string, + sendMessageToJest?: Function, ): Promise => { const { initialize, @@ -45,6 +46,7 @@ const jestAdapter = async ( localRequire: runtime.requireModule.bind(runtime), parentProcess: process, testPath, + sendMessageToJest, }); if (config.timers === 'fake') { diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 0cd57f313db5..4aaea52c1445 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -44,6 +44,7 @@ export const initialize = ({ localRequire, parentProcess, testPath, + sendMessageToJest, }: { config: Config.ProjectConfig; environment: JestEnvironment; @@ -53,6 +54,7 @@ export const initialize = ({ localRequire: (path: Config.Path) => any; testPath: Config.Path; parentProcess: Process; + sendMessageToJest?: Function; }) => { if (globalConfig.testTimeout) { getRunnerState().testTimeout = globalConfig.testTimeout; @@ -139,7 +141,9 @@ export const initialize = ({ setState({snapshotState, testPath}); addEventHandler(handleSnapshotStateAfterRetry(snapshotState)); - addEventHandler(testCaseReportHandler(testPath, parentProcess)); + if (sendMessageToJest) { + addEventHandler(testCaseReportHandler(testPath, sendMessageToJest)); + } // Return it back to the outer scope (test runner outside the VM). return {globals, snapshotState}; diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index ac233be0fa4b..d3f9db4d4e5a 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -1,11 +1,10 @@ import {Circus} from '@jest/types'; -import {messageParent} from 'jest-worker'; import {TestCase, TestCaseResult} from '@jest/test-result'; import {makeSingleTestResult, parseSingleTestResult} from './utils'; const testCaseReportHandler = ( testPath: string, - parentProcess: NodeJS.Process, + sendMessageToJest: Function, ) => (event: Circus.Event) => { switch (event.name) { case 'test_done': { @@ -17,10 +16,11 @@ const testCaseReportHandler = ( title: testCaseResult.title, ancestorTitles: testCaseResult.ancestorTitles, }; - messageParent( - ['test-case-result', [testPath, testCase, testCaseResult]], - parentProcess, - ); + sendMessageToJest('test-case-result', [ + testPath, + testCase, + testCaseResult, + ]); break; } } diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index faf80f48fbcd..2c368e7a78b8 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -81,6 +81,13 @@ class TestRunner { throw new CancelRun(); } + const sendMessageToJest = ( + eventName: string, + arg: Array, + ) => { + this.eventEmitter.emit(eventName, arg); + }; + await this.eventEmitter.emit('test-file-start', [test]); return runTest( test.path, @@ -88,6 +95,7 @@ class TestRunner { test.context.config, test.context.resolver, this._context, + sendMessageToJest, ); }) .then(result => diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index b0892c948168..fe0e66b44558 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -28,6 +28,7 @@ import {formatExecError} from 'jest-message-util'; import sourcemapSupport = require('source-map-support'); import chalk from 'chalk'; import {TestFramework, TestRunnerContext} from './types'; +import {messageParent} from 'jest-worker'; type RunTestInternalResult = { leakDetector: LeakDetector | null; @@ -81,6 +82,7 @@ async function runTestInternal( config: Config.ProjectConfig, resolver: Resolver, context?: TestRunnerContext, + sendMessageToJest: Function, ): Promise { const testSource = fs.readFileSync(path, 'utf8'); const docblockPragmas = docblock.parse(docblock.extract(testSource)); @@ -230,6 +232,7 @@ async function runTestInternal( environment, runtime, path, + sendMessageToJest, ); } catch (err) { // Access stack before uninstalling sourcemaps @@ -279,12 +282,17 @@ async function runTestInternal( } } +const sendMessageToJest = (eventName, args) => { + messageParent(eventName, args); +}; + export default async function runTest( path: Config.Path, globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, resolver: Resolver, context?: TestRunnerContext, + sendMessageToJest?: Function = sendMessageToJest, ): Promise { const {leakDetector, result} = await runTestInternal( path, @@ -292,6 +300,7 @@ export default async function runTest( config, resolver, context, + sendMessageToJest, ); if (leakDetector) { diff --git a/packages/jest-runner/src/testWorker.ts b/packages/jest-runner/src/testWorker.ts index 9987c7ee3f30..73f7346a4bf3 100644 --- a/packages/jest-runner/src/testWorker.ts +++ b/packages/jest-runner/src/testWorker.ts @@ -15,6 +15,7 @@ import Runtime = require('jest-runtime'); import Resolver = require('jest-resolve'); import {ErrorWithCode, TestRunnerSerializedContext} from './types'; import runTest from './runTest'; +import {messageParent} from 'jest-worker'; export type SerializableResolver = { config: Config.ProjectConfig; @@ -74,6 +75,10 @@ export function setup(setupData: { } } +const sendMessageToJest = (eventName: string, args: Array) => { + messageParent([eventName, args]); +}; + export async function worker({ config, globalConfig, @@ -90,6 +95,7 @@ export async function worker({ ...context, changedFiles: context.changedFiles && new Set(context.changedFiles), }, + sendMessageToJest, ); } catch (error) { throw formatError(error); From a6bb2ec72547bbab6932874c551414efa974986f Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Tue, 1 Oct 2019 10:52:12 -0700 Subject: [PATCH 09/43] Remove jest-worker dependency from jest-circus --- packages/jest-circus/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/jest-circus/package.json b/packages/jest-circus/package.json index 56e723b04489..d8484864aff8 100644 --- a/packages/jest-circus/package.json +++ b/packages/jest-circus/package.json @@ -18,7 +18,6 @@ "co": "^4.6.0", "expect": "^24.9.0", "is-generator-fn": "^2.0.0", - "jest-worker": "^24.9.0", "jest-each": "^24.9.0", "jest-matcher-utils": "^24.9.0", "jest-message-util": "^24.9.0", From 6331ae20b663b9309f048cecf0b811ddaf861b67 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Tue, 1 Oct 2019 12:26:24 -0700 Subject: [PATCH 10/43] WIP --- packages/jest-core/src/TestScheduler.ts | 70 +++++++++++++------------ packages/jest-runner/src/index.ts | 2 +- packages/jest-runner/src/runTest.ts | 11 ++-- packages/jest-runner/src/testWorker.ts | 2 +- packages/jest-runner/src/types.ts | 1 + 5 files changed, 43 insertions(+), 43 deletions(-) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 37b4ea05d7b9..453c445c7fe6 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -210,39 +210,43 @@ export default class TestScheduler { serial: runInBand || Boolean(testRunner.isSerial), }; - const unsubscribes = [ - testRunner.eventEmitter.on( - 'test-file-start', - ([test]: [TestRunner.Test]) => onTestFileStart(test), - ), - testRunner.eventEmitter.on( - 'test-file-success', - ([test, testResult]: [TestRunner.Test, TestResult]) => - onResult(test, testResult), - ), - testRunner.eventEmitter.on( - 'test-file-failure', - ([test, error]: [TestRunner.Test, SerializableError]) => - onFailure(test, error), - ), - testRunner.eventEmitter.on( - 'test-case-result', - ([testPath, testCase, testCaseResult]: [ - Config.Path, - TestCase, - AssertionResult, - ]) => { - if (context) { - const test: TestRunner.Test = {context, path: testPath}; - this._dispatcher.onTestCaseResult( - test, - testCase, - testCaseResult, - ); - } - }, - ), - ]; + const unsubscribes: Array<() => void> = []; + + if (typeof testRunner.eventEmitter !== 'undefined') { + unsubscribes.concat([ + testRunner.eventEmitter.on( + 'test-file-start', + ([test]: [TestRunner.Test]) => onTestFileStart(test), + ), + testRunner.eventEmitter.on( + 'test-file-success', + ([test, testResult]: [TestRunner.Test, TestResult]) => + onResult(test, testResult), + ), + testRunner.eventEmitter.on( + 'test-file-failure', + ([test, error]: [TestRunner.Test, SerializableError]) => + onFailure(test, error), + ), + testRunner.eventEmitter.on( + 'test-case-result', + ([testPath, testCase, testCaseResult]: [ + Config.Path, + TestCase, + AssertionResult, + ]) => { + if (context) { + const test: TestRunner.Test = {context, path: testPath}; + this._dispatcher.onTestCaseResult( + test, + testCase, + testCaseResult, + ); + } + }, + ), + ]); + } await testRunner.runTests(tests, watcher, testRunnerOptions); diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 2c368e7a78b8..c92f3c2b8986 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -94,8 +94,8 @@ class TestRunner { this._globalConfig, test.context.config, test.context.resolver, - this._context, sendMessageToJest, + this._context, ); }) .then(result => diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index fe0e66b44558..b2eae86a546a 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -28,7 +28,6 @@ import {formatExecError} from 'jest-message-util'; import sourcemapSupport = require('source-map-support'); import chalk from 'chalk'; import {TestFramework, TestRunnerContext} from './types'; -import {messageParent} from 'jest-worker'; type RunTestInternalResult = { leakDetector: LeakDetector | null; @@ -81,8 +80,8 @@ async function runTestInternal( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, resolver: Resolver, - context?: TestRunnerContext, sendMessageToJest: Function, + context?: TestRunnerContext, ): Promise { const testSource = fs.readFileSync(path, 'utf8'); const docblockPragmas = docblock.parse(docblock.extract(testSource)); @@ -282,25 +281,21 @@ async function runTestInternal( } } -const sendMessageToJest = (eventName, args) => { - messageParent(eventName, args); -}; - export default async function runTest( path: Config.Path, globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, resolver: Resolver, + sendMessageToJest: Function, context?: TestRunnerContext, - sendMessageToJest?: Function = sendMessageToJest, ): Promise { const {leakDetector, result} = await runTestInternal( path, globalConfig, config, resolver, - context, sendMessageToJest, + context, ); if (leakDetector) { diff --git a/packages/jest-runner/src/testWorker.ts b/packages/jest-runner/src/testWorker.ts index 73f7346a4bf3..8fbbe8b515a6 100644 --- a/packages/jest-runner/src/testWorker.ts +++ b/packages/jest-runner/src/testWorker.ts @@ -91,11 +91,11 @@ export async function worker({ globalConfig, config, getResolver(config), + sendMessageToJest, context && { ...context, changedFiles: context.changedFiles && new Set(context.changedFiles), }, - sendMessageToJest, ); } catch (error) { throw formatError(error); diff --git a/packages/jest-runner/src/types.ts b/packages/jest-runner/src/types.ts index 4dbc37f6568e..d65635bbcb4a 100644 --- a/packages/jest-runner/src/types.ts +++ b/packages/jest-runner/src/types.ts @@ -43,6 +43,7 @@ export type TestFramework = ( environment: JestEnvironment, runtime: Runtime, testPath: string, + sendMessageToJest?: Function, ) => Promise; export type TestRunnerOptions = { From df6271386f3648a2af5adf81f687ebfb10d160f9 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Tue, 1 Oct 2019 21:30:51 -0700 Subject: [PATCH 11/43] Fix tests and prevent breaking api --- packages/jest-core/src/TestScheduler.ts | 97 +++++++++++-------- .../src/__tests__/testRunner.test.ts | 7 +- packages/jest-runner/src/index.ts | 3 + .../src/__performance_tests__/workers/pi.js | 4 - 4 files changed, 61 insertions(+), 50 deletions(-) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 453c445c7fe6..fb455c21da80 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -210,47 +210,64 @@ export default class TestScheduler { serial: runInBand || Boolean(testRunner.isSerial), }; - const unsubscribes: Array<() => void> = []; - - if (typeof testRunner.eventEmitter !== 'undefined') { - unsubscribes.concat([ - testRunner.eventEmitter.on( - 'test-file-start', - ([test]: [TestRunner.Test]) => onTestFileStart(test), - ), - testRunner.eventEmitter.on( - 'test-file-success', - ([test, testResult]: [TestRunner.Test, TestResult]) => - onResult(test, testResult), - ), - testRunner.eventEmitter.on( - 'test-file-failure', - ([test, error]: [TestRunner.Test, SerializableError]) => - onFailure(test, error), - ), - testRunner.eventEmitter.on( - 'test-case-result', - ([testPath, testCase, testCaseResult]: [ - Config.Path, - TestCase, - AssertionResult, - ]) => { - if (context) { - const test: TestRunner.Test = {context, path: testPath}; - this._dispatcher.onTestCaseResult( - test, - testCase, - testCaseResult, - ); - } - }, - ), - ]); + /** + * Test runners with event emitters are still not supported + * for third party test runners. + */ + if (testRunner.__PRIVATE_UNSTABLE_API_supportsEventEmmiters__) { + const unsubscribes: Array<() => void> = []; + + if (typeof testRunner.eventEmitter !== 'undefined') { + unsubscribes.concat([ + testRunner.eventEmitter.on( + 'test-file-start', + ([test]: [TestRunner.Test]) => onTestFileStart(test), + ), + testRunner.eventEmitter.on( + 'test-file-success', + ([test, testResult]: [TestRunner.Test, TestResult]) => + onResult(test, testResult), + ), + testRunner.eventEmitter.on( + 'test-file-failure', + ([test, error]: [TestRunner.Test, SerializableError]) => + onFailure(test, error), + ), + testRunner.eventEmitter.on( + 'test-case-result', + ([testPath, testCase, testCaseResult]: [ + Config.Path, + TestCase, + AssertionResult, + ]) => { + if (context) { + const test: TestRunner.Test = {context, path: testPath}; + this._dispatcher.onTestCaseResult( + test, + testCase, + testCaseResult, + ); + } + }, + ), + ]); + } + + await testRunner.runTests(tests, watcher, testRunnerOptions); + + unsubscribes.forEach(sub => sub()); + } else { + await testRunner.runTests( + tests, + watcher, + onTestFileStart, + onResult, + onFailure, + { + serial: runInBand || Boolean(testRunners[runner].isSerial), + }, + ); } - - await testRunner.runTests(tests, watcher, testRunnerOptions); - - unsubscribes.forEach(sub => sub()); } } catch (error) { if (!watcher.isInterrupted()) { diff --git a/packages/jest-runner/src/__tests__/testRunner.test.ts b/packages/jest-runner/src/__tests__/testRunner.test.ts index 8853a1c8b9bd..a9d37843a42c 100644 --- a/packages/jest-runner/src/__tests__/testRunner.test.ts +++ b/packages/jest-runner/src/__tests__/testRunner.test.ts @@ -8,6 +8,7 @@ import {TestWatcher} from '@jest/core'; import TestRunner from '../index'; +import {Config} from '@jest/types'; let mockWorkerFarm; @@ -38,9 +39,6 @@ test('injects the serializable module map into each worker in watch mode', async await new TestRunner(globalConfig).runTests( [{context, path: './file.test.js'}, {context, path: './file2.test.js'}], new TestWatcher({isWatchMode: globalConfig.watch}), - () => {}, - () => {}, - () => {}, {serial: false}, ); @@ -72,9 +70,6 @@ test('assign process.env.JEST_WORKER_ID = 1 when in runInBand mode', async () => await new TestRunner(globalConfig).runTests( [{context, path: './file.test.js'}], new TestWatcher({isWatchMode: globalConfig.watch}), - () => {}, - () => {}, - () => {}, {serial: true}, ); diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index c92f3c2b8986..b975be632dd6 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -47,6 +47,8 @@ class TestRunner { private _context: JestTestRunnerContext; public eventEmitter: Emittery; + public __PRIVATE_UNSTABLE_API_supportsEventEmmiters__: true = true; + constructor( globalConfig: Config.GlobalConfig, context?: JestTestRunnerContext, @@ -59,6 +61,7 @@ class TestRunner { async runTests( tests: Array, watcher: JestTestWatcher, + options: JestTestRunnerOptions, ): Promise { return await (options.serial diff --git a/packages/jest-worker/src/__performance_tests__/workers/pi.js b/packages/jest-worker/src/__performance_tests__/workers/pi.js index 2e2a9f58d288..bf2c043f45ec 100644 --- a/packages/jest-worker/src/__performance_tests__/workers/pi.js +++ b/packages/jest-worker/src/__performance_tests__/workers/pi.js @@ -7,16 +7,12 @@ 'use strict'; -const { messageParent } = require('jest-worker'); - module.exports = function() { const points = 10000; let inside = 0; - messageParent({ r: 'Lucas' }) for (let i = 0; i < points; i++) { if (Math.pow(Math.random(), 2) + Math.pow(Math.random(), 2) <= 1) { - messageParent({ i }) inside++; } } From a7741c33fd1122b18c376714c15a4a8728a23627 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Thu, 3 Oct 2019 10:07:50 -0700 Subject: [PATCH 12/43] Fix lint issues --- .vscode/settings.json | 2 +- .../src/legacy-code-todo-rewrite/jestAdapter.ts | 2 +- .../src/legacy-code-todo-rewrite/jestAdapterInit.ts | 2 +- packages/jest-circus/src/testCaseReportHandler.ts | 2 +- packages/jest-circus/src/utils.ts | 6 +++--- packages/jest-core/src/ReporterDispatcher.ts | 2 +- packages/jest-core/src/TestScheduler.ts | 4 ++-- packages/jest-reporters/src/Status.ts | 2 +- packages/jest-reporters/src/default_reporter.ts | 2 +- packages/jest-reporters/src/types.ts | 2 +- packages/jest-runner/src/__tests__/testRunner.test.ts | 1 - packages/jest-runner/src/testWorker.ts | 2 +- packages/jest-worker/src/Farm.ts | 8 ++++---- packages/jest-worker/src/WorkerPool.ts | 2 +- packages/jest-worker/src/__tests__/Farm.test.js | 1 - packages/jest-worker/src/index.ts | 2 +- packages/jest-worker/src/workers/ChildProcessWorker.ts | 10 +++------- packages/jest-worker/src/workers/NodeThreadsWorker.ts | 10 +++------- 18 files changed, 26 insertions(+), 36 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 07d18558adbe..c4951686b125 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,5 @@ "flow.useNPMPackagedFlow": true, "javascript.validate.enable": false, "jest.pathToJest": "yarn jest --", - "prettier.eslintIntegration": false + "prettier.eslintIntegration": true } diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index debdc139ba94..838a1b2bec0e 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -45,8 +45,8 @@ const jestAdapter = async ( globalConfig, localRequire: runtime.requireModule.bind(runtime), parentProcess: process, - testPath, sendMessageToJest, + testPath, }); if (config.timers === 'fake') { diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 4aaea52c1445..17765d23a779 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -30,8 +30,8 @@ import { } from '../state'; import {getTestID} from '../utils'; import run from '../run'; -import globals from '..'; import testCaseReportHandler from '../testCaseReportHandler'; +import globals from '..'; type Process = NodeJS.Process; diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index d3f9db4d4e5a..2ff0c165e7c8 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -11,10 +11,10 @@ const testCaseReportHandler = ( const testResult = makeSingleTestResult(event.test); const testCaseResult: TestCaseResult = parseSingleTestResult(testResult); const testCase: TestCase = { + ancestorTitles: testCaseResult.ancestorTitles, fullName: testCaseResult.fullName, location: testCaseResult.location, title: testCaseResult.title, - ancestorTitles: testCaseResult.ancestorTitles, }; sendMessageToJest('test-case-result', [ testPath, diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index 4c5df9f34f6a..759831a75f9a 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -11,8 +11,8 @@ import isGeneratorFn from 'is-generator-fn'; import co from 'co'; import StackUtils = require('stack-utils'); import prettyFormat = require('pretty-format'); -import {getState, ROOT_DESCRIBE_BLOCK_NAME} from './state'; import {AssertionResult, Status} from '@jest/test-result'; +import {ROOT_DESCRIBE_BLOCK_NAME, getState} from './state'; const stackUtils = new StackUtils({cwd: 'A path that does not exist'}); @@ -396,7 +396,7 @@ export const parseSingleTestResult = ( }; }; -export const parseTestResults = (testResults: Circus.TestResult[]) => { +export const parseTestResults = (testResults: Array) => { let numFailingTests = 0; let numPassingTests = 0; let numPendingTests = 0; @@ -419,10 +419,10 @@ export const parseTestResults = (testResults: Circus.TestResult[]) => { ); return { + assertionResults, numFailingTests, numPassingTests, numPendingTests, numTodoTests, - assertionResults, }; }; diff --git a/packages/jest-core/src/ReporterDispatcher.ts b/packages/jest-core/src/ReporterDispatcher.ts index 65dac81e8dc7..7f7876e210ab 100644 --- a/packages/jest-core/src/ReporterDispatcher.ts +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -7,9 +7,9 @@ import { AggregatedResult, - TestResult, TestCase, TestCaseResult, + TestResult, } from '@jest/test-result'; import {Test} from 'jest-runner'; import {Context} from 'jest-runtime'; diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index fb455c21da80..243390ea8825 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -22,13 +22,13 @@ import { import exit = require('exit'); import { AggregatedResult, + AssertionResult, SerializableError, + TestCase, TestResult, addResult, buildFailureTestResult, makeEmptyAggregatedTestResult, - TestCase, - AssertionResult, } from '@jest/test-result'; import ReporterDispatcher from './ReporterDispatcher'; import TestWatcher from './TestWatcher'; diff --git a/packages/jest-reporters/src/Status.ts b/packages/jest-reporters/src/Status.ts index 5f3d2acfd062..32dec184f5ff 100644 --- a/packages/jest-reporters/src/Status.ts +++ b/packages/jest-reporters/src/Status.ts @@ -6,7 +6,7 @@ */ import {Config} from '@jest/types'; -import {AggregatedResult, TestResult, TestCaseResult} from '@jest/test-result'; +import {AggregatedResult, TestCaseResult, TestResult} from '@jest/test-result'; import chalk from 'chalk'; import stringLength = require('string-length'); import {ReporterOnStartOptions, Test} from './types'; diff --git a/packages/jest-reporters/src/default_reporter.ts b/packages/jest-reporters/src/default_reporter.ts index 961263610ddc..919f445bf0a2 100644 --- a/packages/jest-reporters/src/default_reporter.ts +++ b/packages/jest-reporters/src/default_reporter.ts @@ -8,9 +8,9 @@ import {Config} from '@jest/types'; import { AggregatedResult, - TestResult, TestCase, TestCaseResult, + TestResult, } from '@jest/test-result'; import {clearLine, isInteractive} from 'jest-util'; import {getConsoleOutput} from '@jest/console'; diff --git a/packages/jest-reporters/src/types.ts b/packages/jest-reporters/src/types.ts index f80a592243d2..e22fa886e312 100644 --- a/packages/jest-reporters/src/types.ts +++ b/packages/jest-reporters/src/types.ts @@ -9,9 +9,9 @@ import {Config} from '@jest/types'; import { AggregatedResult, SerializableError, - TestResult, TestCase, TestCaseResult, + TestResult, } from '@jest/test-result'; import {JestEnvironment as Environment} from '@jest/environment'; import {FS as HasteFS, ModuleMap} from 'jest-haste-map'; diff --git a/packages/jest-runner/src/__tests__/testRunner.test.ts b/packages/jest-runner/src/__tests__/testRunner.test.ts index a9d37843a42c..ffc30029fd65 100644 --- a/packages/jest-runner/src/__tests__/testRunner.test.ts +++ b/packages/jest-runner/src/__tests__/testRunner.test.ts @@ -8,7 +8,6 @@ import {TestWatcher} from '@jest/core'; import TestRunner from '../index'; -import {Config} from '@jest/types'; let mockWorkerFarm; diff --git a/packages/jest-runner/src/testWorker.ts b/packages/jest-runner/src/testWorker.ts index 8fbbe8b515a6..3fed3f43fdea 100644 --- a/packages/jest-runner/src/testWorker.ts +++ b/packages/jest-runner/src/testWorker.ts @@ -13,9 +13,9 @@ import exit = require('exit'); import {separateMessageFromStack} from 'jest-message-util'; import Runtime = require('jest-runtime'); import Resolver = require('jest-resolve'); +import {messageParent} from 'jest-worker'; import {ErrorWithCode, TestRunnerSerializedContext} from './types'; import runTest from './runTest'; -import {messageParent} from 'jest-worker'; export type SerializableResolver = { config: Config.ProjectConfig; diff --git a/packages/jest-worker/src/Farm.ts b/packages/jest-worker/src/Farm.ts index ce310af22a02..270e4e9d2443 100644 --- a/packages/jest-worker/src/Farm.ts +++ b/packages/jest-worker/src/Farm.ts @@ -9,13 +9,13 @@ import { CHILD_MESSAGE_CALL, ChildMessage, FarmOptions, + OnCustomMessage, OnEnd, OnStart, + PromiseWithCustomMessage, QueueChildMessage, QueueItem, WorkerInterface, - PromiseWithCustomMessage, - OnCustomMessage, } from './types'; export default class Farm { @@ -50,7 +50,7 @@ export default class Farm { method: string, ...args: Array ): PromiseWithCustomMessage { - let customMessageListeners: OnCustomMessage[] = []; + let customMessageListeners: Array = []; const addCustomMessageListener = (listener: OnCustomMessage) => { customMessageListeners.push(listener); @@ -93,7 +93,7 @@ export default class Farm { } }; - const task = {onEnd, onStart, request, onCustomMessage}; + const task = {onCustomMessage, onEnd, onStart, request}; if (worker) { this._enqueue(task, worker.getWorkerId()); diff --git a/packages/jest-worker/src/WorkerPool.ts b/packages/jest-worker/src/WorkerPool.ts index b904df4698c4..3f10059626d8 100644 --- a/packages/jest-worker/src/WorkerPool.ts +++ b/packages/jest-worker/src/WorkerPool.ts @@ -9,12 +9,12 @@ import BaseWorkerPool from './base/BaseWorkerPool'; import { ChildMessage, + OnCustomMessage, OnEnd, OnStart, WorkerInterface, WorkerOptions, WorkerPoolInterface, - OnCustomMessage, } from './types'; const canUseWorkerThreads = () => { diff --git a/packages/jest-worker/src/__tests__/Farm.test.js b/packages/jest-worker/src/__tests__/Farm.test.js index 230e4015bf5f..daf5b9a36891 100644 --- a/packages/jest-worker/src/__tests__/Farm.test.js +++ b/packages/jest-worker/src/__tests__/Farm.test.js @@ -98,7 +98,6 @@ describe('Farm', () => { }); it('handles null computeWorkerKey, sending to first worker', async () => { - process.send([-1, 'ROGELIo']) const computeWorkerKey = jest.fn(() => null); const farm = new Farm(4, callback, computeWorkerKey); diff --git a/packages/jest-worker/src/index.ts b/packages/jest-worker/src/index.ts index a56a9ff270b2..41a6c5049eb7 100644 --- a/packages/jest-worker/src/index.ts +++ b/packages/jest-worker/src/index.ts @@ -11,9 +11,9 @@ import Farm from './Farm'; import { FarmOptions, PoolExitResult, + PromiseWithCustomMessage, WorkerPoolInterface, WorkerPoolOptions, - PromiseWithCustomMessage, } from './types'; import _messageParent from './workers/messageParent'; diff --git a/packages/jest-worker/src/workers/ChildProcessWorker.ts b/packages/jest-worker/src/workers/ChildProcessWorker.ts index aa051d6887f4..ff6f8f50f370 100644 --- a/packages/jest-worker/src/workers/ChildProcessWorker.ts +++ b/packages/jest-worker/src/workers/ChildProcessWorker.ts @@ -13,16 +13,16 @@ import {stdout as stdoutSupportsColor} from 'supports-color'; import { CHILD_MESSAGE_INITIALIZE, ChildMessage, + OnCustomMessage, OnEnd, OnStart, PARENT_MESSAGE_CLIENT_ERROR, + PARENT_MESSAGE_CUSTOM, PARENT_MESSAGE_OK, PARENT_MESSAGE_SETUP_ERROR, - PARENT_MESSAGE_CUSTOM, ParentMessage, WorkerInterface, WorkerOptions, - OnCustomMessage, } from '../types'; const SIGNAL_BASE_EXIT_CODE = 128; @@ -233,11 +233,7 @@ export default class ChildProcessWorker implements WorkerInterface { return onProcessEnd(...args); }; - this._onCustomMessage = (...arg) => { - if (onCustomMessage) { - return onCustomMessage(...arg); - } - }; + this._onCustomMessage = (...arg) => onCustomMessage(...arg); this._request = request; this._retries = 0; diff --git a/packages/jest-worker/src/workers/NodeThreadsWorker.ts b/packages/jest-worker/src/workers/NodeThreadsWorker.ts index a39cc6e94520..7b49eda114f6 100644 --- a/packages/jest-worker/src/workers/NodeThreadsWorker.ts +++ b/packages/jest-worker/src/workers/NodeThreadsWorker.ts @@ -15,16 +15,16 @@ import mergeStream = require('merge-stream'); import { CHILD_MESSAGE_INITIALIZE, ChildMessage, + OnCustomMessage, OnEnd, OnStart, PARENT_MESSAGE_CLIENT_ERROR, + PARENT_MESSAGE_CUSTOM, PARENT_MESSAGE_OK, PARENT_MESSAGE_SETUP_ERROR, - PARENT_MESSAGE_CUSTOM, ParentMessage, WorkerInterface, WorkerOptions, - OnCustomMessage, } from '../types'; export default class ExperimentalWorker implements WorkerInterface { @@ -218,11 +218,7 @@ export default class ExperimentalWorker implements WorkerInterface { return onProcessEnd(...args); }; - this._onCustomMessage = (...arg) => { - if (onCustomMessage) { - return onCustomMessage(...arg); - } - }; + this._onCustomMessage = (...arg) => onCustomMessage(...arg); this._request = request; this._retries = 0; From a045229789cf6a5d9597254eff2f587b23563027 Mon Sep 17 00:00:00 2001 From: Rogelio Guzman Date: Thu, 3 Oct 2019 10:27:21 -0700 Subject: [PATCH 13/43] Add copyright header to new files --- packages/jest-circus/src/testCaseReportHandler.ts | 7 +++++++ packages/jest-worker/src/workers/messageParent.ts | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index 2ff0c165e7c8..06487fb8df8b 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import {Circus} from '@jest/types'; import {TestCase, TestCaseResult} from '@jest/test-result'; import {makeSingleTestResult, parseSingleTestResult} from './utils'; diff --git a/packages/jest-worker/src/workers/messageParent.ts b/packages/jest-worker/src/workers/messageParent.ts index 7ec34b3e492b..4b21812a0339 100644 --- a/packages/jest-worker/src/workers/messageParent.ts +++ b/packages/jest-worker/src/workers/messageParent.ts @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import {PARENT_MESSAGE_CUSTOM} from '../types'; const isWorkerThread = () => { From 0a135c627626d7ecb5dd3542de31ca11459de507 Mon Sep 17 00:00:00 2001 From: Kunal Kushwaha Date: Mon, 22 Jun 2020 01:40:32 +0530 Subject: [PATCH 14/43] merged feature/custom-messages --- .gitignore | 1 + .../jest-core/src/getChangedFilesPromise.ts | 3 -- packages/jest-worker/src/Farm.ts | 27 +++++++------ .../jest-worker/src/__tests__/Farm.test.js | 36 ++++++++++++++++++ packages/jest-worker/src/index.ts | 2 +- packages/jest-worker/src/types.ts | 4 +- .../src/workers/ChildProcessWorker.ts | 7 ++-- .../src/workers/NodeThreadsWorker.ts | 2 +- .../__tests__/ChildProcessWorker.test.js | 38 +++++++++++++++++++ .../__tests__/NodeThreadsWorker.test.js | 38 +++++++++++++++++++ .../jest-worker/src/workers/messageParent.ts | 6 +-- 11 files changed, 136 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index c6b727d6dfa1..36a8de27bd81 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ /node_modules /packages/*/build/ +/packages/*/build-es5/ /packages/*/coverage/ /packages/*/node_modules/ /packages/*/package-lock.json diff --git a/packages/jest-core/src/getChangedFilesPromise.ts b/packages/jest-core/src/getChangedFilesPromise.ts index 8e75aaa33d56..61364a25cd1b 100644 --- a/packages/jest-core/src/getChangedFilesPromise.ts +++ b/packages/jest-core/src/getChangedFilesPromise.ts @@ -37,9 +37,6 @@ export default ( console.error(chalk.red(`\n\n${message}`)); process.exit(1); - - // We do process.exit, so this is dead code - return Promise.reject(e); }); } diff --git a/packages/jest-worker/src/Farm.ts b/packages/jest-worker/src/Farm.ts index 270e4e9d2443..1f123526107d 100644 --- a/packages/jest-worker/src/Farm.ts +++ b/packages/jest-worker/src/Farm.ts @@ -50,18 +50,22 @@ export default class Farm { method: string, ...args: Array ): PromiseWithCustomMessage { - let customMessageListeners: Array = []; + + const customMessageListeners: Set = new Set(); const addCustomMessageListener = (listener: OnCustomMessage) => { - customMessageListeners.push(listener); + customMessageListeners.add(listener); return () => { - customMessageListeners = customMessageListeners.filter( - l => l !== listener, - ); + // Check if the following check is required + customMessageListeners.forEach(customListener => { + if (customListener === listener) { + customMessageListeners.delete(customListener); + } + }); }; }; - const onCustomMessage: OnCustomMessage = (message: any) => { + const onCustomMessage: OnCustomMessage = message => { customMessageListeners.forEach(listener => listener(message)); }; @@ -85,12 +89,8 @@ export default class Farm { }; const onEnd: OnEnd = (error: Error | null, result: unknown) => { - customMessageListeners = []; - if (error) { - reject(error); - } else { - resolve(result); - } + customMessageListeners.clear(); + return error ? reject(error) : resolve(result); }; const task = {onCustomMessage, onEnd, onStart, request}; @@ -103,8 +103,7 @@ export default class Farm { }, ); - promise.onCustomMessage = addCustomMessageListener; - + promise.UNSTABLE_onCustomMessage = addCustomMessageListener; return promise; } diff --git a/packages/jest-worker/src/__tests__/Farm.test.js b/packages/jest-worker/src/__tests__/Farm.test.js index daf5b9a36891..fcdaef7c54cd 100644 --- a/packages/jest-worker/src/__tests__/Farm.test.js +++ b/packages/jest-worker/src/__tests__/Farm.test.js @@ -25,11 +25,16 @@ function workerReply(i, error, result) { workerReplyEnd(i, error, result); } +function workerReplyCustomMessage(i, message) { + mockWorkerCalls[i].onCustomMessage(message); +} + describe('Farm', () => { beforeEach(() => { mockWorkerCalls = []; callback = jest.fn((...args) => { mockWorkerCalls.push({ + onCustomMessage: args[4], onEnd: args[3], onStart: args[2], passed: args[1], @@ -347,4 +352,35 @@ describe('Farm', () => { await expect(p6).resolves.toBe('response-6'); await expect(p7).resolves.toBe('response-7'); }); + + it('can receive custom messages from workers', async () => { + expect.assertions(2); + const farm = new Farm(2, callback); + + const p0 = farm.doWork('work-0'); + const p1 = farm.doWork('work-1'); + + const unsubscribe = p0.UNSTABLE_onCustomMessage(message => { + expect(message).toEqual({key: 0, message: 'foo'}); + }); + + p1.UNSTABLE_onCustomMessage(message => { + expect(message).toEqual({key: 1, message: 'bar'}); + }); + + workerReplyStart(0); + workerReplyStart(1); + workerReplyCustomMessage(0, {key: 0, message: 'foo'}); + workerReplyCustomMessage(1, {key: 1, message: 'bar'}); + + unsubscribe(); + // This message will not received because the listener already + // unsubscribed. + workerReplyCustomMessage(0, {key: 0, message: 'baz'}); + + workerReply(0, null, 17); + workerReply(1, null, 17); + await p0; + await p1; + }); }); diff --git a/packages/jest-worker/src/index.ts b/packages/jest-worker/src/index.ts index 87bba807a4b2..b8d149c3afe1 100644 --- a/packages/jest-worker/src/index.ts +++ b/packages/jest-worker/src/index.ts @@ -149,5 +149,5 @@ export default class JestWorker { } } -export {PromiseWithCustomMessage}; +export type {PromiseWithCustomMessage}; export const messageParent = _messageParent; diff --git a/packages/jest-worker/src/types.ts b/packages/jest-worker/src/types.ts index cd701c75364d..08e992f1172b 100644 --- a/packages/jest-worker/src/types.ts +++ b/packages/jest-worker/src/types.ts @@ -19,7 +19,7 @@ export const CHILD_MESSAGE_END: 2 = 2; export const PARENT_MESSAGE_OK: 0 = 0; export const PARENT_MESSAGE_CLIENT_ERROR: 1 = 1; export const PARENT_MESSAGE_SETUP_ERROR: 2 = 2; -export const PARENT_MESSAGE_CUSTOM: -1 = -1; +export const PARENT_MESSAGE_CUSTOM: 3 = 3; export type PARENT_MESSAGE_ERROR = | typeof PARENT_MESSAGE_CLIENT_ERROR @@ -60,7 +60,7 @@ export type PoolExitResult = { }; export interface PromiseWithCustomMessage extends Promise { - onCustomMessage?: (listener: OnCustomMessage) => () => void; + UNSTABLE_onCustomMessage?: (listener: OnCustomMessage) => () => void; } // Option objects. diff --git a/packages/jest-worker/src/workers/ChildProcessWorker.ts b/packages/jest-worker/src/workers/ChildProcessWorker.ts index 429650adabb3..d1f925a2ad7a 100644 --- a/packages/jest-worker/src/workers/ChildProcessWorker.ts +++ b/packages/jest-worker/src/workers/ChildProcessWorker.ts @@ -158,7 +158,8 @@ export default class ChildProcessWorker implements WorkerInterface { } private _onMessage(response: ParentMessage) { - let error; + // TODO: Add appropriate type check + let error: any; switch (response[0]) { case PARENT_MESSAGE_OK: this._onProcessEnd(null, response[1]); @@ -178,7 +179,6 @@ export default class ChildProcessWorker implements WorkerInterface { error.stack = response[3]; for (const key in extra) { - // @ts-expect-error: adding custom properties to errors. error[key] = extra[key]; } } @@ -189,7 +189,6 @@ export default class ChildProcessWorker implements WorkerInterface { case PARENT_MESSAGE_SETUP_ERROR: error = new Error('Error when calling setup: ' + response[2]); - // @ts-expect-error: adding custom properties to errors. error.type = response[1]; error.stack = response[3]; @@ -224,7 +223,7 @@ export default class ChildProcessWorker implements WorkerInterface { onProcessStart: OnStart, onProcessEnd: OnEnd, onCustomMessage: OnCustomMessage, - ) { + ): void { onProcessStart(this); this._onProcessEnd = (...args) => { // Clean the request to avoid sending past requests to workers that fail diff --git a/packages/jest-worker/src/workers/NodeThreadsWorker.ts b/packages/jest-worker/src/workers/NodeThreadsWorker.ts index ce89bec4197a..57a71ef1ec39 100644 --- a/packages/jest-worker/src/workers/NodeThreadsWorker.ts +++ b/packages/jest-worker/src/workers/NodeThreadsWorker.ts @@ -207,7 +207,7 @@ export default class ExperimentalWorker implements WorkerInterface { onProcessStart: OnStart, onProcessEnd: OnEnd, onCustomMessage: OnCustomMessage, - ) { + ): void { onProcessStart(this); this._onProcessEnd = (...args) => { // Clean the request to avoid sending past requests to workers that fail diff --git a/packages/jest-worker/src/workers/__tests__/ChildProcessWorker.test.js b/packages/jest-worker/src/workers/__tests__/ChildProcessWorker.test.js index 98cd27a6796a..97a427309991 100644 --- a/packages/jest-worker/src/workers/__tests__/ChildProcessWorker.test.js +++ b/packages/jest-worker/src/workers/__tests__/ChildProcessWorker.test.js @@ -15,6 +15,7 @@ import { CHILD_MESSAGE_CALL, CHILD_MESSAGE_INITIALIZE, PARENT_MESSAGE_CLIENT_ERROR, + PARENT_MESSAGE_CUSTOM, PARENT_MESSAGE_OK, } from '../../types'; @@ -225,6 +226,43 @@ it('calls the onProcessStart method synchronously if the queue is empty', () => expect(onProcessEnd).toHaveBeenCalledTimes(1); }); +it('can send multiple messages to parent', () => { + const worker = new Worker({ + forkOptions: {}, + maxRetries: 3, + workerPath: '/tmp/foo', + }); + + const onProcessStart = jest.fn(); + const onProcessEnd = jest.fn(); + const onCustomMessage = jest.fn(); + + worker.send( + [CHILD_MESSAGE_CALL, false, 'foo', []], + onProcessStart, + onProcessEnd, + onCustomMessage, + ); + + // Only onProcessStart has been called + expect(onProcessStart).toHaveBeenCalledTimes(1); + expect(onProcessEnd).not.toHaveBeenCalled(); + expect(onCustomMessage).not.toHaveBeenCalled(); + + // then first call replies... + forkInterface.emit('message', [ + PARENT_MESSAGE_CUSTOM, + {message: 'foo bar', otherKey: 1}, + ]); + + expect(onProcessEnd).not.toHaveBeenCalled(); + expect(onCustomMessage).toHaveBeenCalledTimes(1); + expect(onCustomMessage).toHaveBeenCalledWith({ + message: 'foo bar', + otherKey: 1, + }); +}); + it('creates error instances for known errors', () => { const worker = new Worker({ forkOptions: {}, diff --git a/packages/jest-worker/src/workers/__tests__/NodeThreadsWorker.test.js b/packages/jest-worker/src/workers/__tests__/NodeThreadsWorker.test.js index 509f22df5b24..c6dab4e0779d 100644 --- a/packages/jest-worker/src/workers/__tests__/NodeThreadsWorker.test.js +++ b/packages/jest-worker/src/workers/__tests__/NodeThreadsWorker.test.js @@ -14,6 +14,7 @@ import { CHILD_MESSAGE_CALL, CHILD_MESSAGE_INITIALIZE, PARENT_MESSAGE_CLIENT_ERROR, + PARENT_MESSAGE_CUSTOM, PARENT_MESSAGE_OK, } from '../../types'; @@ -233,6 +234,43 @@ it('calls the onProcessStart method synchronously if the queue is empty', () => expect(onProcessEnd).toHaveBeenCalledTimes(1); }); +it('can send multiple messages to parent', () => { + const worker = new Worker({ + forkOptions: {}, + maxRetries: 3, + workerPath: '/tmp/foo', + }); + + const onProcessStart = jest.fn(); + const onProcessEnd = jest.fn(); + const onCustomMessage = jest.fn(); + + worker.send( + [CHILD_MESSAGE_CALL, false, 'foo', []], + onProcessStart, + onProcessEnd, + onCustomMessage, + ); + + // Only onProcessStart has been called + expect(onProcessStart).toHaveBeenCalledTimes(1); + expect(onProcessEnd).not.toHaveBeenCalled(); + expect(onCustomMessage).not.toHaveBeenCalled(); + + // then first call replies... + worker._worker.emit('message', [ + PARENT_MESSAGE_CUSTOM, + {message: 'foo bar', otherKey: 1}, + ]); + + expect(onProcessEnd).not.toHaveBeenCalled(); + expect(onCustomMessage).toHaveBeenCalledTimes(1); + expect(onCustomMessage).toHaveBeenCalledWith({ + message: 'foo bar', + otherKey: 1, + }); +}); + it('creates error instances for known errors', () => { const worker = new Worker({ forkOptions: {}, diff --git a/packages/jest-worker/src/workers/messageParent.ts b/packages/jest-worker/src/workers/messageParent.ts index 4b21812a0339..d9e768ae6734 100644 --- a/packages/jest-worker/src/workers/messageParent.ts +++ b/packages/jest-worker/src/workers/messageParent.ts @@ -11,15 +11,15 @@ const isWorkerThread = () => { try { const {isMainThread, parentPort} = require('worker_threads'); return !isMainThread && parentPort; - } catch (_) { + } catch { return false; } }; const messageParent = ( - message: any, + message: unknown, parentProcess: NodeJS.Process = process, -) => { +): void => { if (isWorkerThread()) { const {parentPort} = require('worker_threads'); parentPort.postMessage([PARENT_MESSAGE_CUSTOM, message]); From 295f7fe7ef59a52c4038ed334e27349c4e512c99 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Tue, 23 Jun 2020 22:32:23 +0530 Subject: [PATCH 15/43] wip: jest circus issue remains --- .../jest-circus/src/testCaseReportHandler.ts | 4 ++-- packages/jest-circus/src/utils.ts | 4 ++-- packages/jest-core/src/ReporterDispatcher.ts | 19 ++++++++++--------- packages/jest-reporters/src/Status.ts | 12 ++++++++---- packages/jest-reporters/src/base_reporter.ts | 13 ++++++++++++- .../jest-reporters/src/default_reporter.ts | 8 ++++---- packages/jest-reporters/src/utils.ts | 10 +++++----- packages/jest-runner/src/index.ts | 8 ++++---- packages/jest-runner/src/testWorker.ts | 2 +- packages/jest-test-result/src/types.ts | 2 +- packages/jest-types/src/Circus.ts | 3 +++ packages/jest-types/src/TestResult.ts | 2 +- 12 files changed, 53 insertions(+), 34 deletions(-) diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index 06487fb8df8b..51779c66190e 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -5,8 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import {Circus} from '@jest/types'; -import {TestCase, TestCaseResult} from '@jest/test-result'; +import type {Circus} from '@jest/types'; +import type {TestCase, TestCaseResult} from '@jest/test-result'; import {makeSingleTestResult, parseSingleTestResult} from './utils'; const testCaseReportHandler = ( diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index 806ee1201480..f5b4eeafab7f 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -12,7 +12,7 @@ import co from 'co'; import dedent = require('dedent'); import StackUtils = require('stack-utils'); import prettyFormat = require('pretty-format'); -import {AssertionResult, Status} from '@jest/test-result'; +import type {AssertionResult, Status} from '@jest/test-result'; import {ROOT_DESCRIBE_BLOCK_NAME, getState} from './state'; const stackUtils = new StackUtils({cwd: 'A path that does not exist'}); @@ -404,7 +404,7 @@ export function invariant( if (!condition) { throw new Error(message); } -}; +} export const parseSingleTestResult = ( testResult: Circus.TestResult, diff --git a/packages/jest-core/src/ReporterDispatcher.ts b/packages/jest-core/src/ReporterDispatcher.ts index 7677d7198102..bed67271bc78 100644 --- a/packages/jest-core/src/ReporterDispatcher.ts +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -5,15 +5,15 @@ * LICENSE file in the root directory of this source tree. */ -import { +import type { AggregatedResult, TestCase, TestCaseResult, TestResult, } from '@jest/test-result'; -import {Test} from 'jest-runner'; -import {Context} from 'jest-runtime'; -import {Reporter, ReporterOnStartOptions} from '@jest/reporters'; +import type {Test} from 'jest-runner'; +import type {Context} from 'jest-runtime'; +import type {Reporter, ReporterOnStartOptions} from '@jest/reporters'; export default class ReporterDispatcher { private _reporters: Array; @@ -51,8 +51,7 @@ export default class ReporterDispatcher { testResult.console = undefined; } - - async onTestFileStart(test: Test) { + async onTestFileStart(test: Test): Promise { for (const reporter of this._reporters) { if (reporter.onTestFileStart) { await reporter.onTestFileStart(test); @@ -71,19 +70,21 @@ export default class ReporterDispatcher { } } - async onTestCaseResult( test: Test, testCase: TestCase, testCaseResult: TestCaseResult, - ) { + ): Promise { for (const reporter of this._reporters) { reporter.onTestCaseResult && (await reporter.onTestCaseResult(test, testCase, testCaseResult)); } } - async onRunComplete(contexts: Set, results: AggregatedResult) { + async onRunComplete( + contexts: Set, + results: AggregatedResult, + ): Promise { for (const reporter of this._reporters) { reporter.onRunComplete && (await reporter.onRunComplete(contexts, results)); diff --git a/packages/jest-reporters/src/Status.ts b/packages/jest-reporters/src/Status.ts index dd291da3ea16..a57e0b1a4caf 100644 --- a/packages/jest-reporters/src/Status.ts +++ b/packages/jest-reporters/src/Status.ts @@ -5,11 +5,15 @@ * LICENSE file in the root directory of this source tree. */ -import {Config} from '@jest/types'; -import {AggregatedResult, TestCaseResult, TestResult} from '@jest/test-result'; -import chalk from 'chalk'; +import type {Config} from '@jest/types'; +import type { + AggregatedResult, + TestCaseResult, + TestResult, +} from '@jest/test-result'; +import chalk = require('chalk'); import stringLength = require('string-length'); -import {ReporterOnStartOptions, Test} from './types'; +import type {ReporterOnStartOptions, Test} from './types'; import { getSummary, printDisplayName, diff --git a/packages/jest-reporters/src/base_reporter.ts b/packages/jest-reporters/src/base_reporter.ts index e8ded25dd089..30104bbd6e98 100644 --- a/packages/jest-reporters/src/base_reporter.ts +++ b/packages/jest-reporters/src/base_reporter.ts @@ -5,7 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import type {AggregatedResult, TestResult} from '@jest/test-result'; +import type { + AggregatedResult, + TestCase, + TestCaseResult, + TestResult, +} from '@jest/test-result'; import {preRunMessage} from 'jest-util'; import type {Context, Reporter, ReporterOnStartOptions, Test} from './types'; @@ -25,6 +30,12 @@ export default class BaseReporter implements Reporter { preRunMessageRemove(process.stderr); } + onTestCaseResult( + _test: Test, + _testCase: TestCase, + _testCaseResult: TestCaseResult, + ): void {} + onTestResult( _test?: Test, _testResult?: TestResult, diff --git a/packages/jest-reporters/src/default_reporter.ts b/packages/jest-reporters/src/default_reporter.ts index 63f09d1a4c84..601b275c1579 100644 --- a/packages/jest-reporters/src/default_reporter.ts +++ b/packages/jest-reporters/src/default_reporter.ts @@ -5,8 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import {Config} from '@jest/types'; -import { +import type {Config} from '@jest/types'; +import type { AggregatedResult, TestCase, TestCaseResult, @@ -140,11 +140,11 @@ export default class DefaultReporter extends BaseReporter { test: Test, _testCase: TestCase, testCaseResult: TestCaseResult, - ) { + ): void { this._status.addTestCaseResult(test, testCaseResult); } - onRunComplete() { + onRunComplete(): void { this.forceFlushBufferedOutput(); this._status.runFinished(); process.stdout.write = this._out; diff --git a/packages/jest-reporters/src/utils.ts b/packages/jest-reporters/src/utils.ts index 8b6b529433e7..59782c854a0c 100644 --- a/packages/jest-reporters/src/utils.ts +++ b/packages/jest-reporters/src/utils.ts @@ -6,12 +6,12 @@ */ import * as path from 'path'; -import {Config} from '@jest/types'; -import {AggregatedResult, TestCaseResult} from '@jest/test-result'; -import chalk from 'chalk'; +import type {Config} from '@jest/types'; +import type {AggregatedResult, TestCaseResult} from '@jest/test-result'; +import chalk = require('chalk'); import slash = require('slash'); -import {pluralize} from 'jest-util'; -import {SummaryOptions, Test} from './types'; +import {formatTime, pluralize} from 'jest-util'; +import type {SummaryOptions, Test} from './types'; const PROGRESS_BAR_WIDTH = 40; diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index e15145471c64..954a6d23292c 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -5,8 +5,8 @@ * LICENSE file in the root directory of this source tree. */ -import {Config} from '@jest/types'; -import {SerializableError, TestResult} from '@jest/test-result'; +import type {Config} from '@jest/types'; +import type {SerializableError, TestResult} from '@jest/test-result'; import exit = require('exit'); import chalk = require('chalk'); import throat from 'throat'; @@ -170,8 +170,8 @@ class TestRunner { path: test.path, }) as PromiseWithCustomMessage; - if (promise.onCustomMessage) { - promise.onCustomMessage(([event, payload]: any) => { + if (promise.UNSTABLE_onCustomMessage) { + promise.UNSTABLE_onCustomMessage(([event, payload]: any) => { this.eventEmitter.emit(event, payload); }); } diff --git a/packages/jest-runner/src/testWorker.ts b/packages/jest-runner/src/testWorker.ts index 6b93c7a7b2dd..11d7bac7ef14 100644 --- a/packages/jest-runner/src/testWorker.ts +++ b/packages/jest-runner/src/testWorker.ts @@ -14,7 +14,7 @@ import {separateMessageFromStack} from 'jest-message-util'; import Runtime = require('jest-runtime'); import Resolver = require('jest-resolve'); import {messageParent} from 'jest-worker'; -import {ErrorWithCode, TestRunnerSerializedContext} from './types'; +import type {ErrorWithCode, TestRunnerSerializedContext} from './types'; import runTest from './runTest'; export type SerializableResolver = { diff --git a/packages/jest-test-result/src/types.ts b/packages/jest-test-result/src/types.ts index 30c3a6c807af..4e820f166fb6 100644 --- a/packages/jest-test-result/src/types.ts +++ b/packages/jest-test-result/src/types.ts @@ -83,7 +83,7 @@ export type TestCaseResult = AssertionResult; export type TestCase = { ancestorTitles: Array; fullName: string; - location: Callsite | null | undefined; + location: TestResult.Callsite | null | undefined; title: string; }; diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index c1ef85c79892..9b0347a22ce0 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -226,4 +226,7 @@ export type TestEntry = { duration?: number | null; status?: TestStatus | null; // whether the test has been skipped or run already timeout?: number; + // children: Array; // Added to include property from DescribeBlock + // hooks: Array; // Added to include property from DescribeBlock + // tests: Array; // Added to include property from DescribeBlock }; diff --git a/packages/jest-types/src/TestResult.ts b/packages/jest-types/src/TestResult.ts index 7b2c16b47b86..47411d47926c 100644 --- a/packages/jest-types/src/TestResult.ts +++ b/packages/jest-types/src/TestResult.ts @@ -9,7 +9,7 @@ export type Milliseconds = number; type Status = 'passed' | 'failed' | 'skipped' | 'pending' | 'todo' | 'disabled'; -type Callsite = { +export type Callsite = { column: number; line: number; }; From 0937cf3129032aa77545a7a6c74518ca7d9531d1 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Tue, 23 Jun 2020 22:46:18 +0530 Subject: [PATCH 16/43] fix: circus testResults concat only when type `DescribeBlock` --- packages/jest-circus/src/utils.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index f5b4eeafab7f..fa6238176b9f 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -333,7 +333,13 @@ const makeTestResults = ( ); for (const child of describeBlock.children) { - testResults = testResults.concat(makeTestResults(child)); + switch (child.type) { + case 'describeBlock': + testResults = testResults.concat(makeTestResults(child)); + break; + case 'test': + break; + } } return testResults; From 6aee98d36592308df6f84f8869ee253cc7c2df9c Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Tue, 23 Jun 2020 23:19:24 +0530 Subject: [PATCH 17/43] fix: removed test logs and comments --- packages/jest-circus/src/utils.ts | 5 ++++- packages/jest-core/src/TestScheduler.ts | 6 ++++-- packages/jest-reporters/src/Status.ts | 4 ++-- packages/jest-reporters/src/utils.ts | 1 - packages/jest-types/src/Circus.ts | 12 +++++++++--- packages/jest-worker/src/Farm.ts | 1 - 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index fa6238176b9f..7b62a457d4b0 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -13,6 +13,7 @@ import dedent = require('dedent'); import StackUtils = require('stack-utils'); import prettyFormat = require('pretty-format'); import type {AssertionResult, Status} from '@jest/test-result'; +import type {ParseTestResults} from '@jest/types/src/Circus'; import {ROOT_DESCRIBE_BLOCK_NAME, getState} from './state'; const stackUtils = new StackUtils({cwd: 'A path that does not exist'}); @@ -446,7 +447,9 @@ export const parseSingleTestResult = ( }; }; -export const parseTestResults = (testResults: Array) => { +export const parseTestResults = ( + testResults: Array, +): ParseTestResults => { let numFailingTests = 0; let numPassingTests = 0; let numPendingTests = 0; diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 276b9e5baf19..653027207150 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -74,7 +74,10 @@ export default class TestScheduler { this._dispatcher.unregister(ReporterClass); } - async scheduleTests(tests: Array, watcher: TestWatcher) { + async scheduleTests( + tests: Array, + watcher: TestWatcher, + ): Promise { const onTestFileStart = this._dispatcher.onTestFileStart.bind( this._dispatcher, ); @@ -185,7 +188,6 @@ export default class TestScheduler { showStatus: !runInBand, }); - const testRunners = Object.create(null); const contextsByTestRunner = new WeakMap(); contexts.forEach(context => { diff --git a/packages/jest-reporters/src/Status.ts b/packages/jest-reporters/src/Status.ts index a57e0b1a4caf..ce0edc40650b 100644 --- a/packages/jest-reporters/src/Status.ts +++ b/packages/jest-reporters/src/Status.ts @@ -117,7 +117,7 @@ export default class Status { this._emit(); } - addTestCaseResult(test: Test, testCaseResult: TestCaseResult) { + addTestCaseResult(test: Test, testCaseResult: TestCaseResult): void { this._currentTestCases.push({test, testCaseResult}); if (!this._showStatus) { this._emit(); @@ -126,7 +126,7 @@ export default class Status { } } - testStarted(testPath: Config.Path, config: Config.ProjectConfig) { + testStarted(testPath: Config.Path, config: Config.ProjectConfig): void { this._currentTests.add(testPath, config); if (!this._showStatus) { this._emit(); diff --git a/packages/jest-reporters/src/utils.ts b/packages/jest-reporters/src/utils.ts index 59782c854a0c..9f1a4e32f543 100644 --- a/packages/jest-reporters/src/utils.ts +++ b/packages/jest-reporters/src/utils.ts @@ -127,7 +127,6 @@ export const getSummary = ( const valuesForCurrentTestCases = getValuesCurrentTestCases( options ? options.currentTestCases : [], ); - // console.log(aggregatedQuickStats.numPassingTests); const estimatedTime = (options && options.estimatedTime) || 0; const snapshotResults = aggregatedResults.snapshot; diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index 9b0347a22ce0..c7edf9b054bf 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -6,6 +6,7 @@ */ import type * as Global from './Global'; +import type {AssertionResult} from './TestResult'; type Process = NodeJS.Process; @@ -226,7 +227,12 @@ export type TestEntry = { duration?: number | null; status?: TestStatus | null; // whether the test has been skipped or run already timeout?: number; - // children: Array; // Added to include property from DescribeBlock - // hooks: Array; // Added to include property from DescribeBlock - // tests: Array; // Added to include property from DescribeBlock +}; + +export type ParseTestResults = { + assertionResults: Array; + numFailingTests: number; + numPassingTests: number; + numPendingTests: number; + numTodoTests: number; }; diff --git a/packages/jest-worker/src/Farm.ts b/packages/jest-worker/src/Farm.ts index 1f123526107d..f0109fcf3d1f 100644 --- a/packages/jest-worker/src/Farm.ts +++ b/packages/jest-worker/src/Farm.ts @@ -50,7 +50,6 @@ export default class Farm { method: string, ...args: Array ): PromiseWithCustomMessage { - const customMessageListeners: Set = new Set(); const addCustomMessageListener = (listener: OnCustomMessage) => { From 15279db04935459ddd25269a682d8ec50eb0ac98 Mon Sep 17 00:00:00 2001 From: Kunal Kushwaha Date: Thu, 25 Jun 2020 00:22:13 +0530 Subject: [PATCH 18/43] requested changes made --- .gitignore | 1 - .../legacy-code-todo-rewrite/jestAdapter.ts | 2 +- .../jestAdapterInit.ts | 2 +- .../jest-circus/src/testCaseReportHandler.ts | 4 +-- packages/jest-circus/src/utils.ts | 35 ++++++++----------- packages/jest-core/src/TestScheduler.ts | 2 +- packages/jest-reporters/src/Status.ts | 9 +++-- packages/jest-runner/src/runTest.ts | 4 +-- packages/jest-runner/src/testWorker.ts | 2 +- packages/jest-runner/src/types.ts | 2 +- packages/jest-worker/src/Farm.ts | 4 +-- 11 files changed, 32 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 36a8de27bd81..c6b727d6dfa1 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ /node_modules /packages/*/build/ -/packages/*/build-es5/ /packages/*/coverage/ /packages/*/node_modules/ /packages/*/package-lock.json diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index c1473179f9c7..8de13345ccd2 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -22,7 +22,7 @@ const jestAdapter = async ( environment: JestEnvironment, runtime: Runtime, testPath: string, - sendMessageToJest?: Function, + sendMessageToJest?: (arg: unknown) => unknown, ): Promise => { const { initialize, diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index b7e766ec7025..a80a6b120378 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -56,7 +56,7 @@ export const initialize = async ({ localRequire: (path: Config.Path) => any; testPath: Config.Path; parentProcess: Process; - sendMessageToJest?: Function; + sendMessageToJest?: (arg: unknown) => unknown; }) => { if (globalConfig.testTimeout) { getRunnerState().testTimeout = globalConfig.testTimeout; diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index 51779c66190e..35a5bef75d8a 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -6,7 +6,7 @@ */ import type {Circus} from '@jest/types'; -import type {TestCase, TestCaseResult} from '@jest/test-result'; +import type {TestCase} from '@jest/test-result'; import {makeSingleTestResult, parseSingleTestResult} from './utils'; const testCaseReportHandler = ( @@ -16,7 +16,7 @@ const testCaseReportHandler = ( switch (event.name) { case 'test_done': { const testResult = makeSingleTestResult(event.test); - const testCaseResult: TestCaseResult = parseSingleTestResult(testResult); + const testCaseResult = parseSingleTestResult(testResult); const testCase: TestCase = { ancestorTitles: testCaseResult.ancestorTitles, fullName: testCaseResult.fullName, diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index 7b62a457d4b0..005edc9d65e3 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -296,9 +296,7 @@ export const makeSingleTestResult = ( const {status} = test; - if (!status) { - throw new Error('Status should be present after tests are run.'); - } + invariant(status, 'Status should be present after tests are run.'); let location = null; if (includeTestLocationInResult) { @@ -453,23 +451,20 @@ export const parseTestResults = ( let numFailingTests = 0; let numPassingTests = 0; let numPendingTests = 0; - let numTodoTests = 0; - - const assertionResults: Array = testResults.map( - testResult => { - if (testResult.status === 'skip') { - numPendingTests += 1; - } else if (testResult.status === 'todo') { - numTodoTests += 1; - } else if (testResult.errors.length) { - numFailingTests += 1; - } else { - numPassingTests += 1; - } - - return parseSingleTestResult(testResult); - }, - ); + const numTodoTests = 0; + + const assertionResults = testResults.map(testResult => { + if (testResult.status === 'skip') { + numPendingTests++; + } else if (testResult.status === 'todo') { + numPendingTests++; + } else if (testResult.errors.length) { + numFailingTests++; + } else { + numPassingTests++; + } + return parseSingleTestResult(testResult); + }); return { assertionResults, diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 653027207150..66a68ab15f5b 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -77,7 +77,7 @@ export default class TestScheduler { async scheduleTests( tests: Array, watcher: TestWatcher, - ): Promise { + ): Promise { const onTestFileStart = this._dispatcher.onTestFileStart.bind( this._dispatcher, ); diff --git a/packages/jest-reporters/src/Status.ts b/packages/jest-reporters/src/Status.ts index ce0edc40650b..8eb9a154a120 100644 --- a/packages/jest-reporters/src/Status.ts +++ b/packages/jest-reporters/src/Status.ts @@ -143,9 +143,12 @@ export default class Status { const {testFilePath} = testResult; this._aggregatedResults = aggregatedResults; this._currentTests.delete(testFilePath); - this._currentTestCases = this._currentTestCases.filter(({test}) => - _config === test.context.config ? test.path !== testFilePath : true, - ); + this._currentTestCases = this._currentTestCases.filter(({test}) => { + if (_config !== test.context.config) { + return true; + } + return test.path !== testFilePath; + }); this._debouncedEmit(); } diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index d9748e5a642c..3e051db9d151 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -80,7 +80,7 @@ async function runTestInternal( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, resolver: Resolver, - sendMessageToJest: Function, + sendMessageToJest: (eventName: string, arg: Array) => void, context?: TestRunnerContext, ): Promise { const testSource = fs.readFileSync(path, 'utf8'); @@ -314,7 +314,7 @@ export default async function runTest( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, resolver: Resolver, - sendMessageToJest: Function, + sendMessageToJest: (eventName: string, arg: Array) => void, context?: TestRunnerContext, ): Promise { const {leakDetector, result} = await runTestInternal( diff --git a/packages/jest-runner/src/testWorker.ts b/packages/jest-runner/src/testWorker.ts index 11d7bac7ef14..330bbfc0c154 100644 --- a/packages/jest-runner/src/testWorker.ts +++ b/packages/jest-runner/src/testWorker.ts @@ -75,7 +75,7 @@ export function setup(setupData: { } } -const sendMessageToJest = (eventName: string, args: Array) => { +const sendMessageToJest = (eventName: string, args: Array) => { messageParent([eventName, args]); }; diff --git a/packages/jest-runner/src/types.ts b/packages/jest-runner/src/types.ts index 40fb8cca6b3d..7ffece09fefe 100644 --- a/packages/jest-runner/src/types.ts +++ b/packages/jest-runner/src/types.ts @@ -43,7 +43,7 @@ export type TestFramework = ( environment: JestEnvironment, runtime: Runtime, testPath: string, - sendMessageToJest?: Function, + sendMessageToJest?: (eventName: string, arg: Array) => void, ) => Promise; export type TestRunnerOptions = { diff --git a/packages/jest-worker/src/Farm.ts b/packages/jest-worker/src/Farm.ts index f0109fcf3d1f..f1aee3c2950d 100644 --- a/packages/jest-worker/src/Farm.ts +++ b/packages/jest-worker/src/Farm.ts @@ -48,9 +48,9 @@ export default class Farm { doWork( method: string, - ...args: Array + ...args: Array ): PromiseWithCustomMessage { - const customMessageListeners: Set = new Set(); + const customMessageListeners = new Set(); const addCustomMessageListener = (listener: OnCustomMessage) => { customMessageListeners.add(listener); From 679d59e9d7af33848d9b1b8b9c93d4c87b8ef10a Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Thu, 25 Jun 2020 02:44:21 +0530 Subject: [PATCH 19/43] fix: changes + type updated --- .gitignore | 1 - .../legacy-code-todo-rewrite/jestAdapter.ts | 2 +- .../jestAdapterInit.ts | 2 +- .../jest-circus/src/testCaseReportHandler.ts | 6 +-- packages/jest-circus/src/utils.ts | 47 +++++++++---------- packages/jest-core/src/TestScheduler.ts | 2 +- packages/jest-reporters/src/Status.ts | 9 ++-- packages/jest-runner/src/index.ts | 5 +- packages/jest-runner/src/runTest.ts | 4 +- packages/jest-runner/src/testWorker.ts | 2 +- packages/jest-runner/src/types.ts | 2 +- packages/jest-worker/src/Farm.ts | 6 +-- packages/jest-worker/src/types.ts | 2 +- 13 files changed, 45 insertions(+), 45 deletions(-) diff --git a/.gitignore b/.gitignore index 36a8de27bd81..c6b727d6dfa1 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,6 @@ /node_modules /packages/*/build/ -/packages/*/build-es5/ /packages/*/coverage/ /packages/*/node_modules/ /packages/*/package-lock.json diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index c1473179f9c7..a4be03b6c231 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -22,7 +22,7 @@ const jestAdapter = async ( environment: JestEnvironment, runtime: Runtime, testPath: string, - sendMessageToJest?: Function, + sendMessageToJest?: (eventName: string, args: Array) => unknown, ): Promise => { const { initialize, diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index b7e766ec7025..153256972f20 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -56,7 +56,7 @@ export const initialize = async ({ localRequire: (path: Config.Path) => any; testPath: Config.Path; parentProcess: Process; - sendMessageToJest?: Function; + sendMessageToJest?: (eventName: string, args: Array) => unknown; }) => { if (globalConfig.testTimeout) { getRunnerState().testTimeout = globalConfig.testTimeout; diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index 51779c66190e..e119c90f63f0 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -6,17 +6,17 @@ */ import type {Circus} from '@jest/types'; -import type {TestCase, TestCaseResult} from '@jest/test-result'; +import type {TestCase} from '@jest/test-result'; import {makeSingleTestResult, parseSingleTestResult} from './utils'; const testCaseReportHandler = ( testPath: string, - sendMessageToJest: Function, + sendMessageToJest: (eventName: string, args: Array) => unknown, ) => (event: Circus.Event) => { switch (event.name) { case 'test_done': { const testResult = makeSingleTestResult(event.test); - const testCaseResult: TestCaseResult = parseSingleTestResult(testResult); + const testCaseResult = parseSingleTestResult(testResult); const testCase: TestCase = { ancestorTitles: testCaseResult.ancestorTitles, fullName: testCaseResult.fullName, diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index 7b62a457d4b0..be96faea6685 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -290,15 +290,13 @@ export const makeSingleTestResult = ( const {includeTestLocationInResult} = getState(); const testPath = []; let parent: Circus.TestEntry | Circus.DescribeBlock | undefined = test; - do { - testPath.unshift(parent.name); - } while ((parent = parent.parent)); const {status} = test; + invariant(status, 'Status should be present after tests are run.'); - if (!status) { - throw new Error('Status should be present after tests are run.'); - } + do { + testPath.unshift(parent.name); + } while ((parent = parent.parent)); let location = null; if (includeTestLocationInResult) { @@ -329,17 +327,19 @@ export const makeSingleTestResult = ( const makeTestResults = ( describeBlock: Circus.DescribeBlock, ): Circus.TestResults => { - let testResults: Circus.TestResults = describeBlock.tests.map( + const testResults: Circus.TestResults = describeBlock.tests.map( makeSingleTestResult, ); for (const child of describeBlock.children) { switch (child.type) { - case 'describeBlock': - testResults = testResults.concat(makeTestResults(child)); + case 'describeBlock': { + testResults.push(...makeTestResults(child)); break; - case 'test': + } + case 'test': { break; + } } } @@ -455,21 +455,18 @@ export const parseTestResults = ( let numPendingTests = 0; let numTodoTests = 0; - const assertionResults: Array = testResults.map( - testResult => { - if (testResult.status === 'skip') { - numPendingTests += 1; - } else if (testResult.status === 'todo') { - numTodoTests += 1; - } else if (testResult.errors.length) { - numFailingTests += 1; - } else { - numPassingTests += 1; - } - - return parseSingleTestResult(testResult); - }, - ); + const assertionResults = testResults.map(testResult => { + if (testResult.status === 'skip') { + numPendingTests++; + } else if (testResult.status === 'todo') { + numTodoTests++; + } else if (testResult.errors.length) { + numFailingTests++; + } else { + numPassingTests++; + } + return parseSingleTestResult(testResult); + }); return { assertionResults, diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 653027207150..66a68ab15f5b 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -77,7 +77,7 @@ export default class TestScheduler { async scheduleTests( tests: Array, watcher: TestWatcher, - ): Promise { + ): Promise { const onTestFileStart = this._dispatcher.onTestFileStart.bind( this._dispatcher, ); diff --git a/packages/jest-reporters/src/Status.ts b/packages/jest-reporters/src/Status.ts index ce0edc40650b..8eb9a154a120 100644 --- a/packages/jest-reporters/src/Status.ts +++ b/packages/jest-reporters/src/Status.ts @@ -143,9 +143,12 @@ export default class Status { const {testFilePath} = testResult; this._aggregatedResults = aggregatedResults; this._currentTests.delete(testFilePath); - this._currentTestCases = this._currentTestCases.filter(({test}) => - _config === test.context.config ? test.path !== testFilePath : true, - ); + this._currentTestCases = this._currentTestCases.filter(({test}) => { + if (_config !== test.context.config) { + return true; + } + return test.path !== testFilePath; + }); this._debouncedEmit(); } diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 954a6d23292c..345a58b2795d 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -88,9 +88,9 @@ class TestRunner { const sendMessageToJest = ( eventName: string, - arg: Array, + args: Array, ) => { - this.eventEmitter.emit(eventName, arg); + this.eventEmitter.emit(eventName, args); }; await this.eventEmitter.emit('test-file-start', [test]); @@ -171,6 +171,7 @@ class TestRunner { }) as PromiseWithCustomMessage; if (promise.UNSTABLE_onCustomMessage) { + // TODO: Get appropriate type for `onCustomMessage` promise.UNSTABLE_onCustomMessage(([event, payload]: any) => { this.eventEmitter.emit(event, payload); }); diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index d9748e5a642c..9401a54174f1 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -80,7 +80,7 @@ async function runTestInternal( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, resolver: Resolver, - sendMessageToJest: Function, + sendMessageToJest: (eventName: string, args: Array) => unknown, context?: TestRunnerContext, ): Promise { const testSource = fs.readFileSync(path, 'utf8'); @@ -314,7 +314,7 @@ export default async function runTest( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, resolver: Resolver, - sendMessageToJest: Function, + sendMessageToJest: (eventName: string, args: Array) => unknown, context?: TestRunnerContext, ): Promise { const {leakDetector, result} = await runTestInternal( diff --git a/packages/jest-runner/src/testWorker.ts b/packages/jest-runner/src/testWorker.ts index 11d7bac7ef14..330bbfc0c154 100644 --- a/packages/jest-runner/src/testWorker.ts +++ b/packages/jest-runner/src/testWorker.ts @@ -75,7 +75,7 @@ export function setup(setupData: { } } -const sendMessageToJest = (eventName: string, args: Array) => { +const sendMessageToJest = (eventName: string, args: Array) => { messageParent([eventName, args]); }; diff --git a/packages/jest-runner/src/types.ts b/packages/jest-runner/src/types.ts index 40fb8cca6b3d..ce1b40192aaf 100644 --- a/packages/jest-runner/src/types.ts +++ b/packages/jest-runner/src/types.ts @@ -43,7 +43,7 @@ export type TestFramework = ( environment: JestEnvironment, runtime: Runtime, testPath: string, - sendMessageToJest?: Function, + sendMessageToJest?: (eventName: string, args: Array) => unknown, ) => Promise; export type TestRunnerOptions = { diff --git a/packages/jest-worker/src/Farm.ts b/packages/jest-worker/src/Farm.ts index f0109fcf3d1f..6157d31ae373 100644 --- a/packages/jest-worker/src/Farm.ts +++ b/packages/jest-worker/src/Farm.ts @@ -48,9 +48,9 @@ export default class Farm { doWork( method: string, - ...args: Array + ...args: Array ): PromiseWithCustomMessage { - const customMessageListeners: Set = new Set(); + const customMessageListeners = new Set(); const addCustomMessageListener = (listener: OnCustomMessage) => { customMessageListeners.add(listener); @@ -64,7 +64,7 @@ export default class Farm { }; }; - const onCustomMessage: OnCustomMessage = message => { + const onCustomMessage: OnCustomMessage = (message): void => { customMessageListeners.forEach(listener => listener(message)); }; diff --git a/packages/jest-worker/src/types.ts b/packages/jest-worker/src/types.ts index 08e992f1172b..23421d6a8306 100644 --- a/packages/jest-worker/src/types.ts +++ b/packages/jest-worker/src/types.ts @@ -162,7 +162,7 @@ export type ParentMessage = export type OnStart = (worker: WorkerInterface) => void; export type OnEnd = (err: Error | null, result: unknown) => void; -export type OnCustomMessage = (message: unknown) => void; +export type OnCustomMessage = (message: Array | unknown) => void; export type QueueChildMessage = { request: ChildMessage; From 4be18940d51e1cea282dbc7293447a15eb755101 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Thu, 25 Jun 2020 19:29:21 +0530 Subject: [PATCH 20/43] fix: `sourcesRelatedToTestsInChangedFiles` added as paramter --- packages/jest-core/src/TestScheduler.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 66a68ab15f5b..6f9f02f4b069 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -196,6 +196,8 @@ export default class TestScheduler { const Runner: typeof TestRunner = require(config.runner); const runner = new Runner(this._globalConfig, { changedFiles: this._context && this._context.changedFiles, + sourcesRelatedToTestsInChangedFiles: + this._context && this._context.sourcesRelatedToTestsInChangedFiles, }); testRunners[config.runner] = runner; contextsByTestRunner.set(runner, context); From 92e407e5f7e4eead41762943e8c7ccaa41b8e9de Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Thu, 2 Jul 2020 02:04:41 +0530 Subject: [PATCH 21/43] update: removed `testCase` not needed anymore --- packages/jest-circus/src/testCaseReportHandler.ts | 13 +------------ packages/jest-core/src/ReporterDispatcher.ts | 4 +--- packages/jest-core/src/TestScheduler.ts | 10 ++-------- packages/jest-reporters/src/base_reporter.ts | 7 +------ packages/jest-reporters/src/default_reporter.ts | 7 +------ packages/jest-reporters/src/types.ts | 10 ++++------ packages/jest-test-result/src/index.ts | 1 - packages/jest-test-result/src/types.ts | 7 ------- 8 files changed, 10 insertions(+), 49 deletions(-) diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index e119c90f63f0..15317912d123 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -6,7 +6,6 @@ */ import type {Circus} from '@jest/types'; -import type {TestCase} from '@jest/test-result'; import {makeSingleTestResult, parseSingleTestResult} from './utils'; const testCaseReportHandler = ( @@ -17,17 +16,7 @@ const testCaseReportHandler = ( case 'test_done': { const testResult = makeSingleTestResult(event.test); const testCaseResult = parseSingleTestResult(testResult); - const testCase: TestCase = { - ancestorTitles: testCaseResult.ancestorTitles, - fullName: testCaseResult.fullName, - location: testCaseResult.location, - title: testCaseResult.title, - }; - sendMessageToJest('test-case-result', [ - testPath, - testCase, - testCaseResult, - ]); + sendMessageToJest('test-case-result', [testPath, testCaseResult]); break; } } diff --git a/packages/jest-core/src/ReporterDispatcher.ts b/packages/jest-core/src/ReporterDispatcher.ts index bed67271bc78..c16c52915b62 100644 --- a/packages/jest-core/src/ReporterDispatcher.ts +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -7,7 +7,6 @@ import type { AggregatedResult, - TestCase, TestCaseResult, TestResult, } from '@jest/test-result'; @@ -72,12 +71,11 @@ export default class ReporterDispatcher { async onTestCaseResult( test: Test, - testCase: TestCase, testCaseResult: TestCaseResult, ): Promise { for (const reporter of this._reporters) { reporter.onTestCaseResult && - (await reporter.onTestCaseResult(test, testCase, testCaseResult)); + (await reporter.onTestCaseResult(test, testCaseResult)); } } diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 6f9f02f4b069..621286c1b770 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -24,7 +24,6 @@ import { AggregatedResult, AssertionResult, SerializableError, - TestCase, TestResult, addResult, buildFailureTestResult, @@ -242,18 +241,13 @@ export default class TestScheduler { ), testRunner.eventEmitter.on( 'test-case-result', - ([testPath, testCase, testCaseResult]: [ + ([testPath, testCaseResult]: [ Config.Path, - TestCase, AssertionResult, ]) => { if (context) { const test: TestRunner.Test = {context, path: testPath}; - this._dispatcher.onTestCaseResult( - test, - testCase, - testCaseResult, - ); + this._dispatcher.onTestCaseResult(test, testCaseResult); } }, ), diff --git a/packages/jest-reporters/src/base_reporter.ts b/packages/jest-reporters/src/base_reporter.ts index 30104bbd6e98..a40034f272b9 100644 --- a/packages/jest-reporters/src/base_reporter.ts +++ b/packages/jest-reporters/src/base_reporter.ts @@ -7,7 +7,6 @@ import type { AggregatedResult, - TestCase, TestCaseResult, TestResult, } from '@jest/test-result'; @@ -30,11 +29,7 @@ export default class BaseReporter implements Reporter { preRunMessageRemove(process.stderr); } - onTestCaseResult( - _test: Test, - _testCase: TestCase, - _testCaseResult: TestCaseResult, - ): void {} + onTestCaseResult(_test: Test, _testCaseResult: TestCaseResult): void {} onTestResult( _test?: Test, diff --git a/packages/jest-reporters/src/default_reporter.ts b/packages/jest-reporters/src/default_reporter.ts index 601b275c1579..e39238841c58 100644 --- a/packages/jest-reporters/src/default_reporter.ts +++ b/packages/jest-reporters/src/default_reporter.ts @@ -8,7 +8,6 @@ import type {Config} from '@jest/types'; import type { AggregatedResult, - TestCase, TestCaseResult, TestResult, } from '@jest/test-result'; @@ -136,11 +135,7 @@ export default class DefaultReporter extends BaseReporter { this._status.testStarted(test.path, test.context.config); } - onTestCaseResult( - test: Test, - _testCase: TestCase, - testCaseResult: TestCaseResult, - ): void { + onTestCaseResult(test: Test, testCaseResult: TestCaseResult): void { this._status.addTestCaseResult(test, testCaseResult); } diff --git a/packages/jest-reporters/src/types.ts b/packages/jest-reporters/src/types.ts index 1d7cc67692a9..397e50b80f38 100644 --- a/packages/jest-reporters/src/types.ts +++ b/packages/jest-reporters/src/types.ts @@ -9,7 +9,6 @@ import type {Config} from '@jest/types'; import type { AggregatedResult, SerializableError, - TestCase, TestCaseResult, TestResult, } from '@jest/test-result'; @@ -67,7 +66,6 @@ export interface Reporter { ) => Promise | void; readonly onTestCaseResult?: ( test: Test, - testCase: TestCase, testCaseResult: TestCaseResult, ) => Promise | void; readonly onRunStart: ( @@ -76,10 +74,10 @@ export interface Reporter { ) => Promise | void; readonly onTestStart?: (test: Test) => Promise | void; readonly onTestFileStart?: (test: Test) => Promise | void; - readonly onTestCaseStart?: ( - test: Test, - testCase: TestCase, - ) => Promise | void; + // readonly onTestCaseStart?: ( + // test: Test, + // testCase: TestCase, + // ) => Promise | void; readonly onRunComplete: ( contexts: Set, results: AggregatedResult, diff --git a/packages/jest-test-result/src/index.ts b/packages/jest-test-result/src/index.ts index 63df3208647f..6f43aba84ce3 100644 --- a/packages/jest-test-result/src/index.ts +++ b/packages/jest-test-result/src/index.ts @@ -24,7 +24,6 @@ export type { Status, Suite, TestResult, - TestCase, TestCaseResult, V8CoverageResult, } from './types'; diff --git a/packages/jest-test-result/src/types.ts b/packages/jest-test-result/src/types.ts index 4e820f166fb6..375aede4065e 100644 --- a/packages/jest-test-result/src/types.ts +++ b/packages/jest-test-result/src/types.ts @@ -80,13 +80,6 @@ export type Suite = { export type TestCaseResult = AssertionResult; -export type TestCase = { - ancestorTitles: Array; - fullName: string; - location: TestResult.Callsite | null | undefined; - title: string; -}; - export type TestResult = { console?: ConsoleBuffer; coverage?: CoverageMapData; From f7e4d8eea1216adf4ffd8478ce33d63bc6473f77 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Thu, 2 Jul 2020 02:17:55 +0530 Subject: [PATCH 22/43] chore: added @deprecated message --- packages/jest-core/src/ReporterDispatcher.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/jest-core/src/ReporterDispatcher.ts b/packages/jest-core/src/ReporterDispatcher.ts index c16c52915b62..c12be167d7ab 100644 --- a/packages/jest-core/src/ReporterDispatcher.ts +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -31,6 +31,25 @@ export default class ReporterDispatcher { ); } + /** + * @deprecated + */ + async onTestResult( + test: Test, + testResult: TestResult, + results: AggregatedResult, + ): Promise { + for (const reporter of this._reporters) { + reporter.onTestResult && + (await reporter.onTestResult(test, testResult, results)); + } + + // Release memory if unused later. + testResult.sourceMaps = undefined; + testResult.coverage = undefined; + testResult.console = undefined; + } + async onTestFileResult( test: Test, testResult: TestResult, From 57bc280da7370ae5e2c7b95cb568c288e2d874a9 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Thu, 2 Jul 2020 20:28:38 +0530 Subject: [PATCH 23/43] `ParseTestResults` not needed anymore --- packages/jest-circus/src/utils.ts | 63 ++++++++++++++-------------- packages/jest-reporters/src/types.ts | 4 -- packages/jest-types/src/Circus.ts | 9 ---- 3 files changed, 31 insertions(+), 45 deletions(-) diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index be96faea6685..ad96595d945f 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -13,7 +13,6 @@ import dedent = require('dedent'); import StackUtils = require('stack-utils'); import prettyFormat = require('pretty-format'); import type {AssertionResult, Status} from '@jest/test-result'; -import type {ParseTestResults} from '@jest/types/src/Circus'; import {ROOT_DESCRIBE_BLOCK_NAME, getState} from './state'; const stackUtils = new StackUtils({cwd: 'A path that does not exist'}); @@ -320,7 +319,7 @@ export const makeSingleTestResult = ( invocations: test.invocations, location, status, - testPath, + testPath: Array.from(testPath), }; }; @@ -435,7 +434,7 @@ export const parseSingleTestResult = ( return { ancestorTitles, duration: testResult.duration, - failureMessages: testResult.errors, + failureMessages: Array.from(testResult.errors), fullName: title ? ancestorTitles.concat(title).join(' ') : ancestorTitles.join(' '), @@ -447,32 +446,32 @@ export const parseSingleTestResult = ( }; }; -export const parseTestResults = ( - testResults: Array, -): ParseTestResults => { - let numFailingTests = 0; - let numPassingTests = 0; - let numPendingTests = 0; - let numTodoTests = 0; - - const assertionResults = testResults.map(testResult => { - if (testResult.status === 'skip') { - numPendingTests++; - } else if (testResult.status === 'todo') { - numTodoTests++; - } else if (testResult.errors.length) { - numFailingTests++; - } else { - numPassingTests++; - } - return parseSingleTestResult(testResult); - }); - - return { - assertionResults, - numFailingTests, - numPassingTests, - numPendingTests, - numTodoTests, - }; -}; +// export const parseTestResults = ( +// testResults: Array, +// ): ParseTestResults => { +// let numFailingTests = 0; +// let numPassingTests = 0; +// let numPendingTests = 0; +// let numTodoTests = 0; + +// const assertionResults = testResults.map(testResult => { +// if (testResult.status === 'skip') { +// numPendingTests++; +// } else if (testResult.status === 'todo') { +// numTodoTests++; +// } else if (testResult.errors.length) { +// numFailingTests++; +// } else { +// numPassingTests++; +// } +// return parseSingleTestResult(testResult); +// }); + +// return { +// assertionResults: Array.from(assertionResults), +// numFailingTests, +// numPassingTests, +// numPendingTests, +// numTodoTests, +// }; +// }; diff --git a/packages/jest-reporters/src/types.ts b/packages/jest-reporters/src/types.ts index 397e50b80f38..5a56f07ef176 100644 --- a/packages/jest-reporters/src/types.ts +++ b/packages/jest-reporters/src/types.ts @@ -74,10 +74,6 @@ export interface Reporter { ) => Promise | void; readonly onTestStart?: (test: Test) => Promise | void; readonly onTestFileStart?: (test: Test) => Promise | void; - // readonly onTestCaseStart?: ( - // test: Test, - // testCase: TestCase, - // ) => Promise | void; readonly onRunComplete: ( contexts: Set, results: AggregatedResult, diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index c7edf9b054bf..c1ef85c79892 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -6,7 +6,6 @@ */ import type * as Global from './Global'; -import type {AssertionResult} from './TestResult'; type Process = NodeJS.Process; @@ -228,11 +227,3 @@ export type TestEntry = { status?: TestStatus | null; // whether the test has been skipped or run already timeout?: number; }; - -export type ParseTestResults = { - assertionResults: Array; - numFailingTests: number; - numPassingTests: number; - numPendingTests: number; - numTodoTests: number; -}; From f57b2a7eeebc9b799d8d671721ee9f46b91602e2 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Thu, 2 Jul 2020 20:31:38 +0530 Subject: [PATCH 24/43] feat: memory-leak fixed --- packages/jest-runner/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 345a58b2795d..3500a007bd7b 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -11,6 +11,7 @@ import exit = require('exit'); import chalk = require('chalk'); import throat from 'throat'; import Worker, {PromiseWithCustomMessage} from 'jest-worker'; +import {deepCyclicCopy} from 'jest-util'; import runTest from './runTest'; import type {SerializableResolver, worker} from './testWorker'; import type { @@ -90,7 +91,7 @@ class TestRunner { eventName: string, args: Array, ) => { - this.eventEmitter.emit(eventName, args); + this.eventEmitter.emit(eventName, deepCyclicCopy(args)); }; await this.eventEmitter.emit('test-file-start', [test]); From 44d9c4ee56f45d55414010c1900b5767fde38379 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Fri, 10 Jul 2020 03:40:22 +0530 Subject: [PATCH 25/43] fixes + opt-in breaking change + event-types --- .../legacy-code-todo-rewrite/jestAdapter.ts | 3 +- .../jestAdapterInit.ts | 3 +- .../jest-circus/src/testCaseReportHandler.ts | 3 +- packages/jest-circus/src/utils.ts | 35 +---- packages/jest-core/src/ReporterDispatcher.ts | 29 +---- packages/jest-core/src/TestScheduler.ts | 12 +- packages/jest-reporters/src/utils.ts | 74 +++++++---- packages/jest-runner/src/index.ts | 123 +++++++++++++----- packages/jest-runner/src/runTest.ts | 6 +- packages/jest-runner/src/testWorker.ts | 8 +- packages/jest-runner/src/types.ts | 40 +++++- packages/jest-worker/src/Farm.ts | 5 +- 12 files changed, 210 insertions(+), 131 deletions(-) diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index a4be03b6c231..918549c4ae6e 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -9,6 +9,7 @@ import * as path from 'path'; import type {Config} from '@jest/types'; import type {JestEnvironment} from '@jest/environment'; import type {TestResult} from '@jest/test-result'; +import TestRunner = require('jest-runner'); import type {RuntimeType as Runtime} from 'jest-runtime'; import type {SnapshotStateType} from 'jest-snapshot'; import {deepCyclicCopy} from 'jest-util'; @@ -22,7 +23,7 @@ const jestAdapter = async ( environment: JestEnvironment, runtime: Runtime, testPath: string, - sendMessageToJest?: (eventName: string, args: Array) => unknown, + sendMessageToJest?: TestRunner.TestFileEvent, ): Promise => { const { initialize, diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 153256972f20..c146ac11a993 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -15,6 +15,7 @@ import { } from '@jest/test-result'; import {extractExpectedAssertionsErrors, getState, setState} from 'expect'; import {formatExecError, formatResultsErrors} from 'jest-message-util'; +import TestRunner = require('jest-runner'); import { SnapshotState, SnapshotStateType, @@ -56,7 +57,7 @@ export const initialize = async ({ localRequire: (path: Config.Path) => any; testPath: Config.Path; parentProcess: Process; - sendMessageToJest?: (eventName: string, args: Array) => unknown; + sendMessageToJest?: TestRunner.TestFileEvent; }) => { if (globalConfig.testTimeout) { getRunnerState().testTimeout = globalConfig.testTimeout; diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index 15317912d123..9356fb2cd023 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -6,11 +6,12 @@ */ import type {Circus} from '@jest/types'; +import TestRunner = require('jest-runner'); import {makeSingleTestResult, parseSingleTestResult} from './utils'; const testCaseReportHandler = ( testPath: string, - sendMessageToJest: (eventName: string, args: Array) => unknown, + sendMessageToJest: TestRunner.TestFileEvent, ) => (event: Circus.Event) => { switch (event.name) { case 'test_done': { diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index ad96595d945f..db1cde7a3cc0 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -326,9 +326,7 @@ export const makeSingleTestResult = ( const makeTestResults = ( describeBlock: Circus.DescribeBlock, ): Circus.TestResults => { - const testResults: Circus.TestResults = describeBlock.tests.map( - makeSingleTestResult, - ); + const testResults: Circus.TestResults = []; for (const child of describeBlock.children) { switch (child.type) { @@ -337,6 +335,7 @@ const makeTestResults = ( break; } case 'test': { + testResults.push(makeSingleTestResult(child)); break; } } @@ -445,33 +444,3 @@ export const parseSingleTestResult = ( title: testResult.testPath[testResult.testPath.length - 1], }; }; - -// export const parseTestResults = ( -// testResults: Array, -// ): ParseTestResults => { -// let numFailingTests = 0; -// let numPassingTests = 0; -// let numPendingTests = 0; -// let numTodoTests = 0; - -// const assertionResults = testResults.map(testResult => { -// if (testResult.status === 'skip') { -// numPendingTests++; -// } else if (testResult.status === 'todo') { -// numTodoTests++; -// } else if (testResult.errors.length) { -// numFailingTests++; -// } else { -// numPassingTests++; -// } -// return parseSingleTestResult(testResult); -// }); - -// return { -// assertionResults: Array.from(assertionResults), -// numFailingTests, -// numPassingTests, -// numPendingTests, -// numTodoTests, -// }; -// }; diff --git a/packages/jest-core/src/ReporterDispatcher.ts b/packages/jest-core/src/ReporterDispatcher.ts index c12be167d7ab..32a358e49d5f 100644 --- a/packages/jest-core/src/ReporterDispatcher.ts +++ b/packages/jest-core/src/ReporterDispatcher.ts @@ -31,25 +31,6 @@ export default class ReporterDispatcher { ); } - /** - * @deprecated - */ - async onTestResult( - test: Test, - testResult: TestResult, - results: AggregatedResult, - ): Promise { - for (const reporter of this._reporters) { - reporter.onTestResult && - (await reporter.onTestResult(test, testResult, results)); - } - - // Release memory if unused later. - testResult.sourceMaps = undefined; - testResult.coverage = undefined; - testResult.console = undefined; - } - async onTestFileResult( test: Test, testResult: TestResult, @@ -93,8 +74,9 @@ export default class ReporterDispatcher { testCaseResult: TestCaseResult, ): Promise { for (const reporter of this._reporters) { - reporter.onTestCaseResult && - (await reporter.onTestCaseResult(test, testCaseResult)); + if (reporter.onTestCaseResult) { + await reporter.onTestCaseResult(test, testCaseResult); + } } } @@ -103,8 +85,9 @@ export default class ReporterDispatcher { results: AggregatedResult, ): Promise { for (const reporter of this._reporters) { - reporter.onRunComplete && - (await reporter.onRunComplete(contexts, results)); + if (reporter.onRunComplete) { + await reporter.onRunComplete(contexts, results); + } } } diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 621286c1b770..bce7600b854b 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -194,9 +194,9 @@ export default class TestScheduler { if (!testRunners[config.runner]) { const Runner: typeof TestRunner = require(config.runner); const runner = new Runner(this._globalConfig, { - changedFiles: this._context && this._context.changedFiles, - sourcesRelatedToTestsInChangedFiles: - this._context && this._context.sourcesRelatedToTestsInChangedFiles, + changedFiles: this._context?.changedFiles, + sourcesRelatedToTestsInChangedFiles: this._context + ?.sourcesRelatedToTestsInChangedFiles, }); testRunners[config.runner] = runner; contextsByTestRunner.set(runner, context); @@ -261,12 +261,12 @@ export default class TestScheduler { await testRunner.runTests( tests, watcher, - onTestFileStart, - onResult, - onFailure, { serial: runInBand || Boolean(testRunners[runner].isSerial), }, + onTestFileStart, + onResult, + onFailure, ); } } diff --git a/packages/jest-reporters/src/utils.ts b/packages/jest-reporters/src/utils.ts index 9f1a4e32f543..3a96abbb459a 100644 --- a/packages/jest-reporters/src/utils.ts +++ b/packages/jest-reporters/src/utils.ts @@ -99,11 +99,25 @@ const getValuesCurrentTestCases = ( let numTodoTests = 0; let numTotalTests = 0; currentTestCases.forEach(({testCaseResult: {status}}) => { - numFailingTests += status === 'failed' ? 1 : 0; - numPassingTests += status === 'passed' ? 1 : 0; - numPendingTests += status === 'skipped' ? 1 : 0; - numTodoTests += status === 'todo' ? 1 : 0; - numTotalTests += 1; + switch (status) { + case 'failed': { + numFailingTests++; + break; + } + case 'passed': { + numPassingTests++; + break; + } + case 'skipped': { + numPendingTests++; + break; + } + case 'todo': { + numTodoTests++; + break; + } + } + numTotalTests++; }); return { @@ -162,29 +176,37 @@ export const getSummary = ( : suitesTotal) + ` total`; + const updatedTestsFailed = testsFailed + ? chalk.bold.red( + `${testsFailed + valuesForCurrentTestCases.numFailingTests} failed`, + ) + ', ' + : ''; + const updatedTestsPending = testsPending + ? chalk.bold.yellow( + `${testsPending + valuesForCurrentTestCases.numPendingTests} skipped`, + ) + ', ' + : ''; + const updatedTestsTodo = testsTodo + ? chalk.bold.magenta( + `${testsTodo + valuesForCurrentTestCases.numTodoTests} todo`, + ) + ', ' + : ''; + const updatedTestsPassed = testsPassed + ? chalk.bold.green( + `${testsPassed + valuesForCurrentTestCases.numPassingTests} passed`, + ) + ', ' + : ''; + const updatedTestsTotal = `${ + testsTotal + valuesForCurrentTestCases.numTotalTests + } total`; + const tests = chalk.bold('Tests: ') + - (testsFailed - ? chalk.bold.red( - `${testsFailed + valuesForCurrentTestCases.numFailingTests} failed`, - ) + ', ' - : '') + - (testsPending - ? chalk.bold.yellow( - `${testsPending + valuesForCurrentTestCases.numPendingTests} skipped`, - ) + ', ' - : '') + - (testsTodo - ? chalk.bold.magenta( - `${testsTodo + valuesForCurrentTestCases.numTodoTests} todo`, - ) + ', ' - : '') + - (testsPassed - ? chalk.bold.green( - `${testsPassed + valuesForCurrentTestCases.numPassingTests} passed`, - ) + ', ' - : '') + - `${testsTotal + valuesForCurrentTestCases.numTotalTests} total`; + updatedTestsFailed + + updatedTestsPending + + updatedTestsTodo + + updatedTestsPassed + + updatedTestsTotal; const snapshots = chalk.bold('Snapshots: ') + diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 3500a007bd7b..ad0ec648631d 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -9,6 +9,7 @@ import type {Config} from '@jest/types'; import type {SerializableError, TestResult} from '@jest/test-result'; import exit = require('exit'); import chalk = require('chalk'); +import Emittery = require('emittery'); import throat from 'throat'; import Worker, {PromiseWithCustomMessage} from 'jest-worker'; import {deepCyclicCopy} from 'jest-util'; @@ -19,12 +20,12 @@ import type { OnTestStart as JestOnTestStart, OnTestSuccess as JestOnTestSuccess, Test as JestTest, + TestFileEvent as JestTestFileEvent, TestRunnerContext as JestTestRunnerContext, TestRunnerOptions as JestTestRunnerOptions, TestWatcher as JestTestWatcher, WatcherState, } from './types'; -import Emittery = require('emittery'); const TEST_WORKER_PATH = require.resolve('./testWorker'); @@ -40,6 +41,7 @@ namespace TestRunner { export type TestWatcher = JestTestWatcher; export type TestRunnerContext = JestTestRunnerContext; export type TestRunnerOptions = JestTestRunnerOptions; + export type TestFileEvent = JestTestFileEvent; } /* eslint-disable-next-line no-redeclare */ @@ -48,7 +50,7 @@ class TestRunner { private _context: JestTestRunnerContext; public eventEmitter: Emittery; - public __PRIVATE_UNSTABLE_API_supportsEventEmmiters__: true = true; + public __PRIVATE_UNSTABLE_API_supportsEventEmmiters__: boolean = false; readonly isSerial?: boolean; @@ -64,17 +66,29 @@ class TestRunner { async runTests( tests: Array, watcher: JestTestWatcher, - options: JestTestRunnerOptions, + + onStart?: JestOnTestStart, + onResult?: JestOnTestSuccess, + onFailure?: JestOnTestFailure, ): Promise { return await (options.serial - ? this._createInBandTestRun(tests, watcher) - : this._createParallelTestRun(tests, watcher)); + ? this._createInBandTestRun(tests, watcher, onStart, onResult, onFailure) + : this._createParallelTestRun( + tests, + watcher, + onStart, + onResult, + onFailure, + )); } private async _createInBandTestRun( tests: Array, watcher: JestTestWatcher, + onStart?: JestOnTestStart, + onResult?: JestOnTestSuccess, + onFailure?: JestOnTestFailure, ) { process.env.JEST_WORKER_ID = '1'; const mutex = throat(1); @@ -86,30 +100,55 @@ class TestRunner { if (watcher.isInterrupted()) { throw new CancelRun(); } + let sendMessageToJest: JestTestFileEvent; - const sendMessageToJest = ( - eventName: string, - args: Array, - ) => { - this.eventEmitter.emit(eventName, deepCyclicCopy(args)); - }; - - await this.eventEmitter.emit('test-file-start', [test]); - return runTest( - test.path, - this._globalConfig, - test.context.config, - test.context.resolver, - sendMessageToJest, - this._context, - ); + // Remove `if(onStart)` + if (onStart) { + await onStart(test); + return runTest( + test.path, + this._globalConfig, + test.context.config, + test.context.resolver, + undefined, + this._context, + ); + } else { + sendMessageToJest = (eventName, args) => { + // `deepCyclicCopy` used here to avoid mem-leak + this.eventEmitter.emit( + eventName, + deepCyclicCopy(args, {keepPrototype: false}), + ); + }; + await this.eventEmitter.emit('test-file-start', [test]); + return runTest( + test.path, + this._globalConfig, + test.context.config, + test.context.resolver, + sendMessageToJest, + this._context, + ); + } }) - .then(result => - this.eventEmitter.emit('test-file-success', [test, result]), - ) - .catch(err => - this.eventEmitter.emit('test-file-failure', [test, err]), - ), + .then(result => { + if (onResult) { + return onResult(test, result); + } else { + return this.eventEmitter.emit('test-file-success', [ + test, + result, + ]); + } + }) + .catch(err => { + if (onFailure) { + return onFailure(test, err); + } else { + return this.eventEmitter.emit('test-file-failure', [test, err]); + } + }), ), Promise.resolve(), ); @@ -118,6 +157,9 @@ class TestRunner { private async _createParallelTestRun( tests: Array, watcher: JestTestWatcher, + onStart?: JestOnTestStart, + onResult?: JestOnTestSuccess, + onFailure?: JestOnTestFailure, ) { const resolvers: Map = new Map(); for (const test of tests) { @@ -154,7 +196,12 @@ class TestRunner { return Promise.reject(); } - await this.eventEmitter.emit('test-file-start', [test]); + // Remove `if(onStart)` + if (onStart) { + await onStart(test); + } else { + await this.eventEmitter.emit('test-file-start', [test]); + } const promise = worker.worker({ config: test.context.config, @@ -182,7 +229,12 @@ class TestRunner { }); const onError = async (err: SerializableError, test: JestTest) => { - await this.eventEmitter.emit('test-file-failure', [test, err]); + // Remove `if(onFailure)` + if (onFailure) { + onFailure(test, err); + } else { + await this.eventEmitter.emit('test-file-failure', [test, err]); + } if (err.type === 'ProcessTerminatedError') { console.error( 'A worker process has quit unexpectedly! ' + @@ -203,9 +255,16 @@ class TestRunner { const runAllTests = Promise.all( tests.map(test => runTestInWorker(test) - .then(result => - this.eventEmitter.emit('test-file-success', [test, result]), - ) + .then(result => { + if (onResult) { + return onResult(test, result); + } else { + return this.eventEmitter.emit('test-file-success', [ + test, + result, + ]); + } + }) .catch(error => onError(error, test)), ), ); diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index 9401a54174f1..d259d2786a31 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -27,7 +27,7 @@ import * as docblock from 'jest-docblock'; import {formatExecError} from 'jest-message-util'; import sourcemapSupport = require('source-map-support'); import chalk = require('chalk'); -import type {TestFramework, TestRunnerContext} from './types'; +import type {TestFileEvent, TestFramework, TestRunnerContext} from './types'; type RunTestInternalResult = { leakDetector: LeakDetector | null; @@ -80,7 +80,7 @@ async function runTestInternal( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, resolver: Resolver, - sendMessageToJest: (eventName: string, args: Array) => unknown, + sendMessageToJest?: TestFileEvent, context?: TestRunnerContext, ): Promise { const testSource = fs.readFileSync(path, 'utf8'); @@ -314,7 +314,7 @@ export default async function runTest( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, resolver: Resolver, - sendMessageToJest: (eventName: string, args: Array) => unknown, + sendMessageToJest?: TestFileEvent, context?: TestRunnerContext, ): Promise { const {leakDetector, result} = await runTestInternal( diff --git a/packages/jest-runner/src/testWorker.ts b/packages/jest-runner/src/testWorker.ts index 330bbfc0c154..b6979c2daf9b 100644 --- a/packages/jest-runner/src/testWorker.ts +++ b/packages/jest-runner/src/testWorker.ts @@ -14,7 +14,11 @@ import {separateMessageFromStack} from 'jest-message-util'; import Runtime = require('jest-runtime'); import Resolver = require('jest-resolve'); import {messageParent} from 'jest-worker'; -import type {ErrorWithCode, TestRunnerSerializedContext} from './types'; +import type { + ErrorWithCode, + TestFileEvent, + TestRunnerSerializedContext, +} from './types'; import runTest from './runTest'; export type SerializableResolver = { @@ -75,7 +79,7 @@ export function setup(setupData: { } } -const sendMessageToJest = (eventName: string, args: Array) => { +const sendMessageToJest: TestFileEvent = (eventName, args) => { messageParent([eventName, args]); }; diff --git a/packages/jest-runner/src/types.ts b/packages/jest-runner/src/types.ts index ce1b40192aaf..fef5eef2213b 100644 --- a/packages/jest-runner/src/types.ts +++ b/packages/jest-runner/src/types.ts @@ -7,7 +7,11 @@ import type {EventEmitter} from 'events'; import type {Config} from '@jest/types'; -import type {SerializableError, TestResult} from '@jest/test-result'; +import type { + AssertionResult, + SerializableError, + TestResult, +} from '@jest/test-result'; import type {JestEnvironment} from '@jest/environment'; import type {FS as HasteFS, ModuleMap} from 'jest-haste-map'; import HasteResolver = require('jest-resolve'); @@ -37,13 +41,45 @@ export type OnTestSuccess = ( testResult: TestResult, ) => Promise; +// Typings for `sendMessageToJest` events + +export type TestFileStart = { + eventName: 'test-file-start'; + args: [Test]; +}; +export type TestFileSuccess = { + eventName: 'test-file-success'; + args: [Test, TestResult]; +}; +export type TestFileFailure = { + eventName: 'test-file-failure'; + args: [Test, SerializableError]; +}; +export type TestFileResult = { + eventName: 'test-case-result'; + args: [Config.Path, AssertionResult]; +}; + +export type TestFileEvent = ( + eventName: + | TestFileStart['eventName'] + | TestFileSuccess['eventName'] + | TestFileFailure['eventName'] + | TestFileResult['eventName'], + args: + | TestFileStart['args'] + | TestFileSuccess['args'] + | TestFileFailure['args'] + | TestFileResult['args'], +) => unknown; + export type TestFramework = ( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, environment: JestEnvironment, runtime: Runtime, testPath: string, - sendMessageToJest?: (eventName: string, args: Array) => unknown, + sendMessageToJest?: TestFileEvent, ) => Promise; export type TestRunnerOptions = { diff --git a/packages/jest-worker/src/Farm.ts b/packages/jest-worker/src/Farm.ts index 6157d31ae373..58acdfec8a4f 100644 --- a/packages/jest-worker/src/Farm.ts +++ b/packages/jest-worker/src/Farm.ts @@ -89,7 +89,10 @@ export default class Farm { const onEnd: OnEnd = (error: Error | null, result: unknown) => { customMessageListeners.clear(); - return error ? reject(error) : resolve(result); + if (error) { + return reject(error); + } + return resolve(result); }; const task = {onCustomMessage, onEnd, onStart, request}; From 01837854305d9ecb5cd0c64d81aaaba5fbf75828 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Fri, 10 Jul 2020 04:07:11 +0530 Subject: [PATCH 26/43] tests fixed --- packages/jest-core/src/__tests__/TestScheduler.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/jest-core/src/__tests__/TestScheduler.test.js b/packages/jest-core/src/__tests__/TestScheduler.test.js index dbbe8c052165..f14f72bbdba5 100644 --- a/packages/jest-core/src/__tests__/TestScheduler.test.js +++ b/packages/jest-core/src/__tests__/TestScheduler.test.js @@ -101,7 +101,7 @@ test('schedule tests run in parallel per default', async () => { await scheduler.scheduleTests(tests, {isInterrupted: jest.fn()}); expect(mockParallelRunner.runTests).toHaveBeenCalled(); - expect(mockParallelRunner.runTests.mock.calls[0][5].serial).toBeFalsy(); + expect(mockParallelRunner.runTests.mock.calls[0][2].serial).toBeFalsy(); }); test('schedule tests run in serial if the runner flags them', async () => { @@ -122,7 +122,7 @@ test('schedule tests run in serial if the runner flags them', async () => { await scheduler.scheduleTests(tests, {isInterrupted: jest.fn()}); expect(mockSerialRunner.runTests).toHaveBeenCalled(); - expect(mockSerialRunner.runTests.mock.calls[0][5].serial).toBeTruthy(); + expect(mockSerialRunner.runTests.mock.calls[0][2].serial).toBeTruthy(); }); test('should bail after `n` failures', async () => { @@ -147,7 +147,7 @@ test('should bail after `n` failures', async () => { isWatchMode: () => true, setState, }); - await mockSerialRunner.runTests.mock.calls[0][3](test, { + await mockSerialRunner.runTests.mock.calls[0][4](test, { numFailingTests: 2, snapshot: {}, testResults: [{}], @@ -206,7 +206,7 @@ test('should set runInBand to run in serial', async () => { expect(spyShouldRunInBand).toHaveBeenCalled(); expect(mockParallelRunner.runTests).toHaveBeenCalled(); - expect(mockParallelRunner.runTests.mock.calls[0][5].serial).toBeTruthy(); + expect(mockParallelRunner.runTests.mock.calls[0][2].serial).toBeTruthy(); }); test('should set runInBand to not run in serial', async () => { From 7f314d4ba1a203e82f532dd5f8be46e8e994b0af Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Tue, 21 Jul 2020 20:30:56 +0530 Subject: [PATCH 27/43] update: added emittery and enable test-reporting --- packages/jest-runner/package.json | 2 +- packages/jest-runner/src/index.ts | 2 +- packages/jest-worker/src/Farm.ts | 2 +- yarn.lock | 10 +++++++++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/jest-runner/package.json b/packages/jest-runner/package.json index d4bdfbbd2d81..2bdda92ac681 100644 --- a/packages/jest-runner/package.json +++ b/packages/jest-runner/package.json @@ -10,13 +10,13 @@ "main": "build/index.js", "types": "build/index.d.ts", "dependencies": { - "emittery": "^0.5.1", "@jest/console": "^26.1.0", "@jest/environment": "^26.1.0", "@jest/test-result": "^26.1.0", "@jest/types": "^26.1.0", "@types/node": "*", "chalk": "^4.0.0", + "emittery": "^0.5.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "jest-config": "^26.1.0", diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index ad0ec648631d..7feb18481d12 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -50,7 +50,7 @@ class TestRunner { private _context: JestTestRunnerContext; public eventEmitter: Emittery; - public __PRIVATE_UNSTABLE_API_supportsEventEmmiters__: boolean = false; + public __PRIVATE_UNSTABLE_API_supportsEventEmmiters__: boolean = true; readonly isSerial?: boolean; diff --git a/packages/jest-worker/src/Farm.ts b/packages/jest-worker/src/Farm.ts index e06df7d7c2fd..151f2783f5a5 100644 --- a/packages/jest-worker/src/Farm.ts +++ b/packages/jest-worker/src/Farm.ts @@ -48,7 +48,7 @@ export default class Farm { doWork( method: string, - ...args: Array + ...args: Array ): PromiseWithCustomMessage { const customMessageListeners = new Set(); diff --git a/yarn.lock b/yarn.lock index 42b35e08e785..cdd85b6c165a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,7 +3,7 @@ __metadata: version: 4 - cacheKey: 5 + cacheKey: 6 "@angular/common@npm:^10.0.2": version: 10.0.2 @@ -7224,6 +7224,13 @@ __metadata: languageName: node linkType: hard +"emittery@npm:^0.5.1": + version: 0.5.1 + resolution: "emittery@npm:0.5.1" + checksum: f972aacc49c041002b0d2b2f64f62c3f492a7068c863bc5d86bcf4b749ebef2c6f93dc9765f4d73b627ae9f926474be0ea4485c4ae88219ebb7eca923148a3f7 + languageName: node + linkType: hard + "emoji-regex@npm:>=6.0.0 <=6.1.1": version: 6.1.1 resolution: "emoji-regex@npm:6.1.1" @@ -11454,6 +11461,7 @@ fsevents@^1.2.7: "@types/node": "*" "@types/source-map-support": ^0.5.0 chalk: ^4.0.0 + emittery: ^0.5.1 exit: ^0.1.2 graceful-fs: ^4.2.4 jest-circus: ^26.1.0 From dc8f206ef6525d9bb1dddd0bcbf96b95d6e22da1 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Fri, 24 Jul 2020 02:03:30 +0530 Subject: [PATCH 28/43] fix: types updated + minor fixes --- packages/jest-reporters/src/utils.ts | 44 ++++++++++++---------------- packages/jest-runner/src/index.ts | 16 +++++----- 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/packages/jest-reporters/src/utils.ts b/packages/jest-reporters/src/utils.ts index 3a96abbb459a..bd61f88ab181 100644 --- a/packages/jest-reporters/src/utils.ts +++ b/packages/jest-reporters/src/utils.ts @@ -98,8 +98,8 @@ const getValuesCurrentTestCases = ( let numPendingTests = 0; let numTodoTests = 0; let numTotalTests = 0; - currentTestCases.forEach(({testCaseResult: {status}}) => { - switch (status) { + currentTestCases.forEach(testCase => { + switch (testCase.testCaseResult.status) { case 'failed': { numFailingTests++; break; @@ -176,36 +176,28 @@ export const getSummary = ( : suitesTotal) + ` total`; - const updatedTestsFailed = testsFailed - ? chalk.bold.red( - `${testsFailed + valuesForCurrentTestCases.numFailingTests} failed`, - ) + ', ' - : ''; - const updatedTestsPending = testsPending - ? chalk.bold.yellow( - `${testsPending + valuesForCurrentTestCases.numPendingTests} skipped`, - ) + ', ' - : ''; - const updatedTestsTodo = testsTodo - ? chalk.bold.magenta( - `${testsTodo + valuesForCurrentTestCases.numTodoTests} todo`, - ) + ', ' - : ''; - const updatedTestsPassed = testsPassed - ? chalk.bold.green( - `${testsPassed + valuesForCurrentTestCases.numPassingTests} passed`, - ) + ', ' - : ''; + const updatedTestsFailed = `${ + testsFailed + valuesForCurrentTestCases.numFailingTests + } failed`; + const updatedTestsPending = `${ + testsPending + valuesForCurrentTestCases.numPendingTests + } skipped`; + const updatedTestsTodo = `${ + testsTodo + valuesForCurrentTestCases.numTodoTests + } todo`; + const updatedTestsPassed = `${ + testsPassed + valuesForCurrentTestCases.numPassingTests + } passed`; const updatedTestsTotal = `${ testsTotal + valuesForCurrentTestCases.numTotalTests } total`; const tests = chalk.bold('Tests: ') + - updatedTestsFailed + - updatedTestsPending + - updatedTestsTodo + - updatedTestsPassed + + (testsFailed ? chalk.bold.red(updatedTestsFailed) + ', ' : '') + + (testsPending ? chalk.bold.yellow(updatedTestsPending) + ', ' : '') + + (testsTodo ? chalk.bold.magenta(updatedTestsTodo) + ', ' : '') + + (testsPassed ? chalk.bold.green(updatedTestsPassed) + ', ' : '') + updatedTestsTotal; const snapshots = diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 7feb18481d12..210a54c32b46 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -60,7 +60,9 @@ class TestRunner { ) { this._globalConfig = globalConfig; this._context = context || {}; - this.eventEmitter = new Emittery(); + this.eventEmitter = new Emittery.Typed<{ + eventName: Parameters[1]; + }>(); } async runTests( @@ -102,7 +104,7 @@ class TestRunner { } let sendMessageToJest: JestTestFileEvent; - // Remove `if(onStart)` + // Remove `if(onStart)` on next release if (onStart) { await onStart(test); return runTest( @@ -114,13 +116,13 @@ class TestRunner { this._context, ); } else { - sendMessageToJest = (eventName, args) => { - // `deepCyclicCopy` used here to avoid mem-leak + // `deepCyclicCopy` used here to avoid mem-leak + sendMessageToJest = (eventName, args) => this.eventEmitter.emit( eventName, deepCyclicCopy(args, {keepPrototype: false}), ); - }; + await this.eventEmitter.emit('test-file-start', [test]); return runTest( test.path, @@ -196,7 +198,7 @@ class TestRunner { return Promise.reject(); } - // Remove `if(onStart)` + // Remove `if(onStart)` on next release if (onStart) { await onStart(test); } else { @@ -229,7 +231,7 @@ class TestRunner { }); const onError = async (err: SerializableError, test: JestTest) => { - // Remove `if(onFailure)` + // Remove `if(onFailure)` on next release if (onFailure) { onFailure(test, err); } else { From 8d4f25a383bf70033a63e586e2bca84e01b5ddc8 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Fri, 24 Jul 2020 14:38:25 +0530 Subject: [PATCH 29/43] update: changelog added --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d58d366357f..c0f7f2bd2cc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features +- `[jest-circus]` Added support for reporting individual test cases using jest-circus ([#10227](https://github.com/facebook/jest/pull/10227)) - `[jest-worker]` Added support for workers to send custom messages to parent in jest-worker ([#10293](https://github.com/facebook/jest/pull/10293)) - `[pretty-format]` Added support for serializing custom elements (web components) ([#10217](https://github.com/facebook/jest/pull/10237)) From 1106c1ebbf9c31820b39dbac1b4dffc1ea574360 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Mon, 27 Jul 2020 11:30:43 +0530 Subject: [PATCH 30/43] update: cleaner typings --- packages/jest-runner/src/index.ts | 5 ++--- packages/jest-runner/src/types.ts | 35 +++++++------------------------ 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 210a54c32b46..7b886406dbcb 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -20,6 +20,7 @@ import type { OnTestStart as JestOnTestStart, OnTestSuccess as JestOnTestSuccess, Test as JestTest, + TestEvents as JestTestEvents, TestFileEvent as JestTestFileEvent, TestRunnerContext as JestTestRunnerContext, TestRunnerOptions as JestTestRunnerOptions, @@ -60,9 +61,7 @@ class TestRunner { ) { this._globalConfig = globalConfig; this._context = context || {}; - this.eventEmitter = new Emittery.Typed<{ - eventName: Parameters[1]; - }>(); + this.eventEmitter = new Emittery.Typed(); } async runTests( diff --git a/packages/jest-runner/src/types.ts b/packages/jest-runner/src/types.ts index fef5eef2213b..6bb9fae77c4a 100644 --- a/packages/jest-runner/src/types.ts +++ b/packages/jest-runner/src/types.ts @@ -42,35 +42,16 @@ export type OnTestSuccess = ( ) => Promise; // Typings for `sendMessageToJest` events - -export type TestFileStart = { - eventName: 'test-file-start'; - args: [Test]; -}; -export type TestFileSuccess = { - eventName: 'test-file-success'; - args: [Test, TestResult]; -}; -export type TestFileFailure = { - eventName: 'test-file-failure'; - args: [Test, SerializableError]; -}; -export type TestFileResult = { - eventName: 'test-case-result'; - args: [Config.Path, AssertionResult]; +export type TestEvents = { + 'test-file-start': [Test]; + 'test-file-success': [Test, TestResult]; + 'test-file-failure': [Test, SerializableError]; + 'test-case-result': [Config.Path, AssertionResult]; }; -export type TestFileEvent = ( - eventName: - | TestFileStart['eventName'] - | TestFileSuccess['eventName'] - | TestFileFailure['eventName'] - | TestFileResult['eventName'], - args: - | TestFileStart['args'] - | TestFileSuccess['args'] - | TestFileFailure['args'] - | TestFileResult['args'], +export type TestFileEvent = ( + eventName: T, + args: TestEvents[T], ) => unknown; export type TestFramework = ( From 056eec3dfc0ce43aa72fe7ddfde5f6cfe924f9d8 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Mon, 27 Jul 2020 11:44:34 +0200 Subject: [PATCH 31/43] add dep on runner to circus, and remove unused jasmine dep from runner --- packages/jest-circus/package.json | 1 + .../jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts | 4 ++-- .../src/legacy-code-todo-rewrite/jestAdapterInit.ts | 4 ++-- packages/jest-circus/src/testCaseReportHandler.ts | 4 ++-- packages/jest-circus/tsconfig.json | 1 + packages/jest-runner/package.json | 1 - yarn.lock | 2 +- 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/jest-circus/package.json b/packages/jest-circus/package.json index 5c618968dd2f..6ed60c32fcea 100644 --- a/packages/jest-circus/package.json +++ b/packages/jest-circus/package.json @@ -23,6 +23,7 @@ "jest-each": "^26.1.0", "jest-matcher-utils": "^26.1.0", "jest-message-util": "^26.1.0", + "jest-runner": "^26.1.0", "jest-runtime": "^26.1.0", "jest-snapshot": "^26.1.0", "jest-util": "^26.1.0", diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts index 918549c4ae6e..e666b2230434 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapter.ts @@ -9,7 +9,7 @@ import * as path from 'path'; import type {Config} from '@jest/types'; import type {JestEnvironment} from '@jest/environment'; import type {TestResult} from '@jest/test-result'; -import TestRunner = require('jest-runner'); +import type {TestFileEvent} from 'jest-runner'; import type {RuntimeType as Runtime} from 'jest-runtime'; import type {SnapshotStateType} from 'jest-snapshot'; import {deepCyclicCopy} from 'jest-util'; @@ -23,7 +23,7 @@ const jestAdapter = async ( environment: JestEnvironment, runtime: Runtime, testPath: string, - sendMessageToJest?: TestRunner.TestFileEvent, + sendMessageToJest?: TestFileEvent, ): Promise => { const { initialize, diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index c146ac11a993..de8850dbee85 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -15,7 +15,7 @@ import { } from '@jest/test-result'; import {extractExpectedAssertionsErrors, getState, setState} from 'expect'; import {formatExecError, formatResultsErrors} from 'jest-message-util'; -import TestRunner = require('jest-runner'); +import type {TestFileEvent} from 'jest-runner'; import { SnapshotState, SnapshotStateType, @@ -57,7 +57,7 @@ export const initialize = async ({ localRequire: (path: Config.Path) => any; testPath: Config.Path; parentProcess: Process; - sendMessageToJest?: TestRunner.TestFileEvent; + sendMessageToJest?: TestFileEvent; }) => { if (globalConfig.testTimeout) { getRunnerState().testTimeout = globalConfig.testTimeout; diff --git a/packages/jest-circus/src/testCaseReportHandler.ts b/packages/jest-circus/src/testCaseReportHandler.ts index 9356fb2cd023..4c7e7fe77609 100644 --- a/packages/jest-circus/src/testCaseReportHandler.ts +++ b/packages/jest-circus/src/testCaseReportHandler.ts @@ -6,12 +6,12 @@ */ import type {Circus} from '@jest/types'; -import TestRunner = require('jest-runner'); +import type {TestFileEvent} from 'jest-runner'; import {makeSingleTestResult, parseSingleTestResult} from './utils'; const testCaseReportHandler = ( testPath: string, - sendMessageToJest: TestRunner.TestFileEvent, + sendMessageToJest: TestFileEvent, ) => (event: Circus.Event) => { switch (event.name) { case 'test_done': { diff --git a/packages/jest-circus/tsconfig.json b/packages/jest-circus/tsconfig.json index 10a995ffa2ba..cc427109b912 100644 --- a/packages/jest-circus/tsconfig.json +++ b/packages/jest-circus/tsconfig.json @@ -9,6 +9,7 @@ {"path": "../jest-environment"}, {"path": "../jest-matcher-utils"}, {"path": "../jest-message-util"}, + {"path": "../jest-runner"}, {"path": "../jest-runtime"}, {"path": "../jest-snapshot"}, {"path": "../jest-test-result"}, diff --git a/packages/jest-runner/package.json b/packages/jest-runner/package.json index 2bdda92ac681..a3fec5720f86 100644 --- a/packages/jest-runner/package.json +++ b/packages/jest-runner/package.json @@ -22,7 +22,6 @@ "jest-config": "^26.1.0", "jest-docblock": "^26.0.0", "jest-haste-map": "^26.1.0", - "jest-jasmine2": "^26.1.0", "jest-leak-detector": "^26.1.0", "jest-message-util": "^26.1.0", "jest-resolve": "^26.1.0", diff --git a/yarn.lock b/yarn.lock index 742dcc094f0f..bba759e9bd7d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11062,6 +11062,7 @@ fsevents@^1.2.7: jest-each: ^26.1.0 jest-matcher-utils: ^26.1.0 jest-message-util: ^26.1.0 + jest-runner: ^26.1.0 jest-runtime: ^26.1.0 jest-snapshot: ^26.1.0 jest-util: ^26.1.0 @@ -11467,7 +11468,6 @@ fsevents@^1.2.7: jest-config: ^26.1.0 jest-docblock: ^26.0.0 jest-haste-map: ^26.1.0 - jest-jasmine2: ^26.1.0 jest-leak-detector: ^26.1.0 jest-message-util: ^26.1.0 jest-resolve: ^26.1.0 From 489423e5dc1c0eba36760f4c766af0c859a2495b Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Mon, 27 Jul 2020 17:13:52 +0530 Subject: [PATCH 32/43] update: add @SimenB's changes --- packages/jest-core/src/TestScheduler.ts | 62 ++++++++++++------------- packages/jest-runner/src/index.ts | 30 ++++++------ 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index bce7600b854b..692389498eb8 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -224,34 +224,36 @@ export default class TestScheduler { const unsubscribes: Array<() => void> = []; if (typeof testRunner.eventEmitter !== 'undefined') { - unsubscribes.concat([ - testRunner.eventEmitter.on( - 'test-file-start', - ([test]: [TestRunner.Test]) => onTestFileStart(test), - ), - testRunner.eventEmitter.on( - 'test-file-success', - ([test, testResult]: [TestRunner.Test, TestResult]) => - onResult(test, testResult), - ), - testRunner.eventEmitter.on( - 'test-file-failure', - ([test, error]: [TestRunner.Test, SerializableError]) => - onFailure(test, error), - ), - testRunner.eventEmitter.on( - 'test-case-result', - ([testPath, testCaseResult]: [ - Config.Path, - AssertionResult, - ]) => { - if (context) { - const test: TestRunner.Test = {context, path: testPath}; - this._dispatcher.onTestCaseResult(test, testCaseResult); - } - }, - ), - ]); + unsubscribes.push( + ...[ + testRunner.eventEmitter.on( + 'test-file-start', + ([test]: [TestRunner.Test]) => onTestFileStart(test), + ), + testRunner.eventEmitter.on( + 'test-file-success', + ([test, testResult]: [TestRunner.Test, TestResult]) => + onResult(test, testResult), + ), + testRunner.eventEmitter.on( + 'test-file-failure', + ([test, error]: [TestRunner.Test, SerializableError]) => + onFailure(test, error), + ), + testRunner.eventEmitter.on( + 'test-case-result', + ([testPath, testCaseResult]: [ + Config.Path, + AssertionResult, + ]) => { + if (context) { + const test: TestRunner.Test = {context, path: testPath}; + this._dispatcher.onTestCaseResult(test, testCaseResult); + } + }, + ), + ], + ); } await testRunner.runTests(tests, watcher, testRunnerOptions); @@ -261,9 +263,7 @@ export default class TestScheduler { await testRunner.runTests( tests, watcher, - { - serial: runInBand || Boolean(testRunners[runner].isSerial), - }, + testRunnerOptions, onTestFileStart, onResult, onFailure, diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 7b886406dbcb..155cf3220e80 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -49,7 +49,7 @@ namespace TestRunner { class TestRunner { private _globalConfig: Config.GlobalConfig; private _context: JestTestRunnerContext; - public eventEmitter: Emittery; + private UNSTABLE_eventEmitter = new Emittery.Typed(); public __PRIVATE_UNSTABLE_API_supportsEventEmmiters__: boolean = true; @@ -61,7 +61,6 @@ class TestRunner { ) { this._globalConfig = globalConfig; this._context = context || {}; - this.eventEmitter = new Emittery.Typed(); } async runTests( @@ -103,7 +102,7 @@ class TestRunner { } let sendMessageToJest: JestTestFileEvent; - // Remove `if(onStart)` on next release + // Remove `if(onStart)` in Jest 27 if (onStart) { await onStart(test); return runTest( @@ -117,12 +116,14 @@ class TestRunner { } else { // `deepCyclicCopy` used here to avoid mem-leak sendMessageToJest = (eventName, args) => - this.eventEmitter.emit( + this.UNSTABLE_eventEmitter.emit( eventName, deepCyclicCopy(args, {keepPrototype: false}), ); - await this.eventEmitter.emit('test-file-start', [test]); + await this.UNSTABLE_eventEmitter.emit('test-file-start', [ + test, + ]); return runTest( test.path, this._globalConfig, @@ -137,7 +138,7 @@ class TestRunner { if (onResult) { return onResult(test, result); } else { - return this.eventEmitter.emit('test-file-success', [ + return this.UNSTABLE_eventEmitter.emit('test-file-success', [ test, result, ]); @@ -147,7 +148,10 @@ class TestRunner { if (onFailure) { return onFailure(test, err); } else { - return this.eventEmitter.emit('test-file-failure', [test, err]); + return this.UNSTABLE_eventEmitter.emit('test-file-failure', [ + test, + err, + ]); } }), ), @@ -197,11 +201,11 @@ class TestRunner { return Promise.reject(); } - // Remove `if(onStart)` on next release + // Remove `if(onStart)` in Jest 27 if (onStart) { await onStart(test); } else { - await this.eventEmitter.emit('test-file-start', [test]); + await this.UNSTABLE_eventEmitter.emit('test-file-start', [test]); } const promise = worker.worker({ @@ -222,7 +226,7 @@ class TestRunner { if (promise.UNSTABLE_onCustomMessage) { // TODO: Get appropriate type for `onCustomMessage` promise.UNSTABLE_onCustomMessage(([event, payload]: any) => { - this.eventEmitter.emit(event, payload); + this.UNSTABLE_eventEmitter.emit(event, payload); }); } @@ -230,11 +234,11 @@ class TestRunner { }); const onError = async (err: SerializableError, test: JestTest) => { - // Remove `if(onFailure)` on next release + // Remove `if(onFailure)` in Jest 27 if (onFailure) { onFailure(test, err); } else { - await this.eventEmitter.emit('test-file-failure', [test, err]); + await this.UNSTABLE_eventEmitter.emit('test-file-failure', [test, err]); } if (err.type === 'ProcessTerminatedError') { console.error( @@ -260,7 +264,7 @@ class TestRunner { if (onResult) { return onResult(test, result); } else { - return this.eventEmitter.emit('test-file-success', [ + return this.UNSTABLE_eventEmitter.emit('test-file-success', [ test, result, ]); From 7221be724f2240c41ce3bd75edcd9150163217c5 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Mon, 27 Jul 2020 19:04:18 +0530 Subject: [PATCH 33/43] hotfix: missed changes --- packages/jest-core/src/TestScheduler.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 692389498eb8..7bde62bc562c 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -223,24 +223,24 @@ export default class TestScheduler { if (testRunner.__PRIVATE_UNSTABLE_API_supportsEventEmmiters__) { const unsubscribes: Array<() => void> = []; - if (typeof testRunner.eventEmitter !== 'undefined') { + if (typeof testRunner.UNSTABLE_eventEmitter !== 'undefined') { unsubscribes.push( ...[ - testRunner.eventEmitter.on( + testRunner.UNSTABLE_eventEmitter.on( 'test-file-start', ([test]: [TestRunner.Test]) => onTestFileStart(test), ), - testRunner.eventEmitter.on( + testRunner.UNSTABLE_eventEmitter.on( 'test-file-success', ([test, testResult]: [TestRunner.Test, TestResult]) => onResult(test, testResult), ), - testRunner.eventEmitter.on( + testRunner.UNSTABLE_eventEmitter.on( 'test-file-failure', ([test, error]: [TestRunner.Test, SerializableError]) => onFailure(test, error), ), - testRunner.eventEmitter.on( + testRunner.UNSTABLE_eventEmitter.on( 'test-case-result', ([testPath, testCaseResult]: [ Config.Path, From ce361dbe59bc9c3f71188215788756bd56926692 Mon Sep 17 00:00:00 2001 From: Kunal Kushwaha Date: Tue, 28 Jul 2020 13:23:35 +0530 Subject: [PATCH 34/43] requested changes made --- packages/jest-circus/src/utils.ts | 2 +- packages/jest-core/src/TestScheduler.ts | 66 +++++++++++-------------- packages/jest-runner/src/index.ts | 2 +- 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/packages/jest-circus/src/utils.ts b/packages/jest-circus/src/utils.ts index db1cde7a3cc0..acf8c56579ec 100644 --- a/packages/jest-circus/src/utils.ts +++ b/packages/jest-circus/src/utils.ts @@ -419,7 +419,7 @@ export const parseSingleTestResult = ( status = 'pending'; } else if (testResult.status === 'todo') { status = 'todo'; - } else if (testResult.errors.length) { + } else if (testResult.errors.length > 0) { status = 'failed'; } else { status = 'passed'; diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 7bde62bc562c..d121697cfefc 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -187,7 +187,7 @@ export default class TestScheduler { showStatus: !runInBand, }); - const testRunners = Object.create(null); + const testRunners: {[key: string]: TestRunner} = Object.create(null); const contextsByTestRunner = new WeakMap(); contexts.forEach(context => { const {config} = context; @@ -220,41 +220,35 @@ export default class TestScheduler { * Test runners with event emitters are still not supported * for third party test runners. */ - if (testRunner.__PRIVATE_UNSTABLE_API_supportsEventEmmiters__) { - const unsubscribes: Array<() => void> = []; - - if (typeof testRunner.UNSTABLE_eventEmitter !== 'undefined') { - unsubscribes.push( - ...[ - testRunner.UNSTABLE_eventEmitter.on( - 'test-file-start', - ([test]: [TestRunner.Test]) => onTestFileStart(test), - ), - testRunner.UNSTABLE_eventEmitter.on( - 'test-file-success', - ([test, testResult]: [TestRunner.Test, TestResult]) => - onResult(test, testResult), - ), - testRunner.UNSTABLE_eventEmitter.on( - 'test-file-failure', - ([test, error]: [TestRunner.Test, SerializableError]) => - onFailure(test, error), - ), - testRunner.UNSTABLE_eventEmitter.on( - 'test-case-result', - ([testPath, testCaseResult]: [ - Config.Path, - AssertionResult, - ]) => { - if (context) { - const test: TestRunner.Test = {context, path: testPath}; - this._dispatcher.onTestCaseResult(test, testCaseResult); - } - }, - ), - ], - ); - } + if ( + testRunner.__PRIVATE_UNSTABLE_API_supportsEventEmmiters__ && + typeof testRunner.UNSTABLE_eventEmitter !== 'undefined' + ) { + const unsubscribes = [ + testRunner.UNSTABLE_eventEmitter.on( + 'test-file-start', + ([test]: [TestRunner.Test]) => onTestFileStart(test), + ), + testRunner.UNSTABLE_eventEmitter.on( + 'test-file-success', + ([test, testResult]: [TestRunner.Test, TestResult]) => + onResult(test, testResult), + ), + testRunner.UNSTABLE_eventEmitter.on( + 'test-file-failure', + ([test, error]: [TestRunner.Test, SerializableError]) => + onFailure(test, error), + ), + testRunner.UNSTABLE_eventEmitter.on( + 'test-case-result', + ([testPath, testCaseResult]: [Config.Path, AssertionResult]) => { + if (context) { + const test: TestRunner.Test = { context, path: testPath }; + this._dispatcher.onTestCaseResult(test, testCaseResult); + } + }, + ), + ]; await testRunner.runTests(tests, watcher, testRunnerOptions); diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 155cf3220e80..ff1c7f59c97c 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -49,7 +49,7 @@ namespace TestRunner { class TestRunner { private _globalConfig: Config.GlobalConfig; private _context: JestTestRunnerContext; - private UNSTABLE_eventEmitter = new Emittery.Typed(); + public UNSTABLE_eventEmitter = new Emittery.Typed(); public __PRIVATE_UNSTABLE_API_supportsEventEmmiters__: boolean = true; From 5540d61de2c7ca3ba492c5f39c938ec0b15053d6 Mon Sep 17 00:00:00 2001 From: Kunal Kushwaha Date: Tue, 28 Jul 2020 14:11:30 +0530 Subject: [PATCH 35/43] added on method in TestRunner --- packages/jest-core/src/TestScheduler.ts | 29 +++++++++---------------- packages/jest-runner/package.json | 2 +- packages/jest-runner/src/index.ts | 4 +++- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index d121697cfefc..95f89e48c6d2 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -22,7 +22,6 @@ import { import exit = require('exit'); import { AggregatedResult, - AssertionResult, SerializableError, TestResult, addResult, @@ -220,30 +219,22 @@ export default class TestScheduler { * Test runners with event emitters are still not supported * for third party test runners. */ - if ( - testRunner.__PRIVATE_UNSTABLE_API_supportsEventEmmiters__ && - typeof testRunner.UNSTABLE_eventEmitter !== 'undefined' - ) { + if (testRunner.__PRIVATE_UNSTABLE_API_supportsEventEmmiters__) { const unsubscribes = [ - testRunner.UNSTABLE_eventEmitter.on( - 'test-file-start', - ([test]: [TestRunner.Test]) => onTestFileStart(test), + testRunner.on('test-file-start', ([test]) => + onTestFileStart(test), ), - testRunner.UNSTABLE_eventEmitter.on( - 'test-file-success', - ([test, testResult]: [TestRunner.Test, TestResult]) => - onResult(test, testResult), + testRunner.on('test-file-success', ([test, testResult]) => + onResult(test, testResult), ), - testRunner.UNSTABLE_eventEmitter.on( - 'test-file-failure', - ([test, error]: [TestRunner.Test, SerializableError]) => - onFailure(test, error), + testRunner.on('test-file-failure', ([test, error]) => + onFailure(test, error), ), - testRunner.UNSTABLE_eventEmitter.on( + testRunner.on( 'test-case-result', - ([testPath, testCaseResult]: [Config.Path, AssertionResult]) => { + ([testPath, testCaseResult]) => { if (context) { - const test: TestRunner.Test = { context, path: testPath }; + const test: TestRunner.Test = {context, path: testPath}; this._dispatcher.onTestCaseResult(test, testCaseResult); } }, diff --git a/packages/jest-runner/package.json b/packages/jest-runner/package.json index a3fec5720f86..fa1a5b9a32e3 100644 --- a/packages/jest-runner/package.json +++ b/packages/jest-runner/package.json @@ -16,7 +16,7 @@ "@jest/types": "^26.1.0", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.5.1", + "emittery": "^0.7.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "jest-config": "^26.1.0", diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index ff1c7f59c97c..7a0e4ee1b404 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -49,7 +49,7 @@ namespace TestRunner { class TestRunner { private _globalConfig: Config.GlobalConfig; private _context: JestTestRunnerContext; - public UNSTABLE_eventEmitter = new Emittery.Typed(); + private UNSTABLE_eventEmitter = new Emittery.Typed(); public __PRIVATE_UNSTABLE_API_supportsEventEmmiters__: boolean = true; @@ -288,6 +288,8 @@ class TestRunner { }; return Promise.race([runAllTests, onInterrupt]).then(cleanup, cleanup); } + + on = this.UNSTABLE_eventEmitter.on.bind(this.UNSTABLE_eventEmitter); } class CancelRun extends Error { From 45382114973aec0267207e53cdae45b745d7e9f9 Mon Sep 17 00:00:00 2001 From: Kunal Kushwaha Date: Tue, 28 Jul 2020 14:43:59 +0530 Subject: [PATCH 36/43] update: add @SimenB's changes --- packages/jest-core/src/TestScheduler.ts | 14 +++++++------- packages/jest-runner/src/index.ts | 11 +++++------ yarn.lock | 10 +++++----- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 95f89e48c6d2..b3543b43cccf 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -47,10 +47,10 @@ export type TestSchedulerContext = { sourcesRelatedToTestsInChangedFiles?: Set; }; export default class TestScheduler { - private _dispatcher: ReporterDispatcher; - private _globalConfig: Config.GlobalConfig; - private _options: TestSchedulerOptions; - private _context: TestSchedulerContext; + private readonly _dispatcher: ReporterDispatcher; + private readonly _globalConfig: Config.GlobalConfig; + private readonly _options: TestSchedulerOptions; + private readonly _context: TestSchedulerContext; constructor( globalConfig: Config.GlobalConfig, @@ -202,7 +202,7 @@ export default class TestScheduler { } }); - const testsByRunner = this._partitionTests(testRunners, tests); + const testsByRunner = TestScheduler._partitionTests(testRunners, tests); if (testsByRunner) { try { @@ -219,7 +219,7 @@ export default class TestScheduler { * Test runners with event emitters are still not supported * for third party test runners. */ - if (testRunner.__PRIVATE_UNSTABLE_API_supportsEventEmmiters__) { + if (testRunner.__PRIVATE_UNSTABLE_API_supportsEventEmitters__) { const unsubscribes = [ testRunner.on('test-file-start', ([test]) => onTestFileStart(test), @@ -281,7 +281,7 @@ export default class TestScheduler { return aggregatedResults; } - private _partitionTests( + private static _partitionTests( testRunners: Record, tests: Array, ): Record> | null { diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 7a0e4ee1b404..e4c49a1dbef9 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -47,11 +47,10 @@ namespace TestRunner { /* eslint-disable-next-line no-redeclare */ class TestRunner { - private _globalConfig: Config.GlobalConfig; - private _context: JestTestRunnerContext; - private UNSTABLE_eventEmitter = new Emittery.Typed(); - - public __PRIVATE_UNSTABLE_API_supportsEventEmmiters__: boolean = true; + private readonly _globalConfig: Config.GlobalConfig; + private readonly _context: JestTestRunnerContext; + private readonly UNSTABLE_eventEmitter = new Emittery.Typed(); + readonly __PRIVATE_UNSTABLE_API_supportsEventEmitters__: boolean = true; readonly isSerial?: boolean; @@ -236,7 +235,7 @@ class TestRunner { const onError = async (err: SerializableError, test: JestTest) => { // Remove `if(onFailure)` in Jest 27 if (onFailure) { - onFailure(test, err); + await onFailure(test, err); } else { await this.UNSTABLE_eventEmitter.emit('test-file-failure', [test, err]); } diff --git a/yarn.lock b/yarn.lock index bba759e9bd7d..317fba10e69d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7224,10 +7224,10 @@ __metadata: languageName: node linkType: hard -"emittery@npm:^0.5.1": - version: 0.5.1 - resolution: "emittery@npm:0.5.1" - checksum: f972aacc49c041002b0d2b2f64f62c3f492a7068c863bc5d86bcf4b749ebef2c6f93dc9765f4d73b627ae9f926474be0ea4485c4ae88219ebb7eca923148a3f7 +"emittery@npm:^0.7.1": + version: 0.7.1 + resolution: "emittery@npm:0.7.1" + checksum: 917b0995126e004ddf175e7d0a74ae8608083846c3f3608e964bf13caba220a003b7455ced5bf813a40e977605be48e53c74f6150fbe587a47ef6b985b8a447e languageName: node linkType: hard @@ -11461,7 +11461,7 @@ fsevents@^1.2.7: "@types/node": "*" "@types/source-map-support": ^0.5.0 chalk: ^4.0.0 - emittery: ^0.5.1 + emittery: ^0.7.1 exit: ^0.1.2 graceful-fs: ^4.2.4 jest-circus: ^26.1.0 From 69a6aa7935932d1e6db62f02266fc97d3e0638f3 Mon Sep 17 00:00:00 2001 From: Kunal Kushwaha Date: Tue, 28 Jul 2020 15:45:00 +0530 Subject: [PATCH 37/43] minor changes --- packages/jest-core/src/TestScheduler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 17ab8f9bd2b8..d93ce2dd7fd7 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -202,7 +202,7 @@ export default class TestScheduler { } }); - const testsByRunner = TestScheduler._partitionTests(testRunners, tests); + const testsByRunner = this._partitionTests(testRunners, tests); if (testsByRunner) { try { From 6ffa6ae7e3067f486e42dd34027216f399282a5f Mon Sep 17 00:00:00 2001 From: Kunal Kushwaha Date: Tue, 28 Jul 2020 15:59:53 +0530 Subject: [PATCH 38/43] update: add @SimenB's changes --- packages/jest-runner/src/runTest.ts | 8 ++------ packages/jest-runner/src/testWorker.ts | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index b64890349765..4d05ea1ff50a 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -79,11 +79,9 @@ async function runTestInternal( path: Config.Path, globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, - resolver: ResolverType, - sendMessageToJest?: TestFileEvent, - context?: TestRunnerContext, + sendMessageToJest?: TestFileEvent, ): Promise { const testSource = fs.readFileSync(path, 'utf8'); const docblockPragmas = docblock.parse(docblock.extract(testSource)); @@ -315,10 +313,8 @@ export default async function runTest( path: Config.Path, globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, - resolver: ResolverType, sendMessageToJest?: TestFileEvent, - context?: TestRunnerContext, ): Promise { const {leakDetector, result} = await runTestInternal( @@ -326,8 +322,8 @@ export default async function runTest( globalConfig, config, resolver, - sendMessageToJest, context, + sendMessageToJest, ); if (leakDetector) { diff --git a/packages/jest-runner/src/testWorker.ts b/packages/jest-runner/src/testWorker.ts index 2d6921db2c51..d1b35875a0ac 100644 --- a/packages/jest-runner/src/testWorker.ts +++ b/packages/jest-runner/src/testWorker.ts @@ -12,7 +12,6 @@ import HasteMap = require('jest-haste-map'); import exit = require('exit'); import {separateMessageFromStack} from 'jest-message-util'; import Runtime = require('jest-runtime'); - import type {ResolverType} from 'jest-resolve'; import {messageParent} from 'jest-worker'; import type { From d08c35d4108d7bbeaacd91765bcf4d39e8da5130 Mon Sep 17 00:00:00 2001 From: Kunal Kushwaha Date: Tue, 28 Jul 2020 16:13:12 +0530 Subject: [PATCH 39/43] removed the UNSTABLE_prefix & resolved usages --- packages/jest-runner/src/index.ts | 29 +++++++++++--------------- packages/jest-runner/src/runTest.ts | 2 +- packages/jest-runner/src/testWorker.ts | 2 +- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index e4c49a1dbef9..95b3f1100d03 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -49,7 +49,7 @@ namespace TestRunner { class TestRunner { private readonly _globalConfig: Config.GlobalConfig; private readonly _context: JestTestRunnerContext; - private readonly UNSTABLE_eventEmitter = new Emittery.Typed(); + private readonly eventEmitter = new Emittery.Typed(); readonly __PRIVATE_UNSTABLE_API_supportsEventEmitters__: boolean = true; readonly isSerial?: boolean; @@ -109,27 +109,25 @@ class TestRunner { this._globalConfig, test.context.config, test.context.resolver, - undefined, this._context, + undefined, ); } else { // `deepCyclicCopy` used here to avoid mem-leak sendMessageToJest = (eventName, args) => - this.UNSTABLE_eventEmitter.emit( + this.eventEmitter.emit( eventName, deepCyclicCopy(args, {keepPrototype: false}), ); - await this.UNSTABLE_eventEmitter.emit('test-file-start', [ - test, - ]); + await this.eventEmitter.emit('test-file-start', [test]); return runTest( test.path, this._globalConfig, test.context.config, test.context.resolver, - sendMessageToJest, this._context, + sendMessageToJest, ); } }) @@ -137,7 +135,7 @@ class TestRunner { if (onResult) { return onResult(test, result); } else { - return this.UNSTABLE_eventEmitter.emit('test-file-success', [ + return this.eventEmitter.emit('test-file-success', [ test, result, ]); @@ -147,10 +145,7 @@ class TestRunner { if (onFailure) { return onFailure(test, err); } else { - return this.UNSTABLE_eventEmitter.emit('test-file-failure', [ - test, - err, - ]); + return this.eventEmitter.emit('test-file-failure', [test, err]); } }), ), @@ -204,7 +199,7 @@ class TestRunner { if (onStart) { await onStart(test); } else { - await this.UNSTABLE_eventEmitter.emit('test-file-start', [test]); + await this.eventEmitter.emit('test-file-start', [test]); } const promise = worker.worker({ @@ -225,7 +220,7 @@ class TestRunner { if (promise.UNSTABLE_onCustomMessage) { // TODO: Get appropriate type for `onCustomMessage` promise.UNSTABLE_onCustomMessage(([event, payload]: any) => { - this.UNSTABLE_eventEmitter.emit(event, payload); + this.eventEmitter.emit(event, payload); }); } @@ -237,7 +232,7 @@ class TestRunner { if (onFailure) { await onFailure(test, err); } else { - await this.UNSTABLE_eventEmitter.emit('test-file-failure', [test, err]); + await this.eventEmitter.emit('test-file-failure', [test, err]); } if (err.type === 'ProcessTerminatedError') { console.error( @@ -263,7 +258,7 @@ class TestRunner { if (onResult) { return onResult(test, result); } else { - return this.UNSTABLE_eventEmitter.emit('test-file-success', [ + return this.eventEmitter.emit('test-file-success', [ test, result, ]); @@ -288,7 +283,7 @@ class TestRunner { return Promise.race([runAllTests, onInterrupt]).then(cleanup, cleanup); } - on = this.UNSTABLE_eventEmitter.on.bind(this.UNSTABLE_eventEmitter); + on = this.eventEmitter.on.bind(this.eventEmitter); } class CancelRun extends Error { diff --git a/packages/jest-runner/src/runTest.ts b/packages/jest-runner/src/runTest.ts index 4d05ea1ff50a..390e0897cf66 100644 --- a/packages/jest-runner/src/runTest.ts +++ b/packages/jest-runner/src/runTest.ts @@ -314,8 +314,8 @@ export default async function runTest( globalConfig: Config.GlobalConfig, config: Config.ProjectConfig, resolver: ResolverType, - sendMessageToJest?: TestFileEvent, context?: TestRunnerContext, + sendMessageToJest?: TestFileEvent, ): Promise { const {leakDetector, result} = await runTestInternal( path, diff --git a/packages/jest-runner/src/testWorker.ts b/packages/jest-runner/src/testWorker.ts index d1b35875a0ac..10e2e3e0b318 100644 --- a/packages/jest-runner/src/testWorker.ts +++ b/packages/jest-runner/src/testWorker.ts @@ -96,7 +96,6 @@ export async function worker({ globalConfig, config, getResolver(config), - sendMessageToJest, context && { ...context, changedFiles: context.changedFiles && new Set(context.changedFiles), @@ -104,6 +103,7 @@ export async function worker({ context.sourcesRelatedToTestsInChangedFiles && new Set(context.sourcesRelatedToTestsInChangedFiles), }, + sendMessageToJest, ); } catch (error) { throw formatError(error); From 1f3d3f591e5c2a715e3023aa2af23501c877c757 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Tue, 28 Jul 2020 16:42:36 +0530 Subject: [PATCH 40/43] fix: update test progress output --- packages/jest-reporters/src/utils.ts | 42 +++++++++++++++------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/packages/jest-reporters/src/utils.ts b/packages/jest-reporters/src/utils.ts index bd61f88ab181..a7255bd9a26a 100644 --- a/packages/jest-reporters/src/utils.ts +++ b/packages/jest-reporters/src/utils.ts @@ -176,29 +176,31 @@ export const getSummary = ( : suitesTotal) + ` total`; - const updatedTestsFailed = `${ - testsFailed + valuesForCurrentTestCases.numFailingTests - } failed`; - const updatedTestsPending = `${ - testsPending + valuesForCurrentTestCases.numPendingTests - } skipped`; - const updatedTestsTodo = `${ - testsTodo + valuesForCurrentTestCases.numTodoTests - } todo`; - const updatedTestsPassed = `${ - testsPassed + valuesForCurrentTestCases.numPassingTests - } passed`; - const updatedTestsTotal = `${ - testsTotal + valuesForCurrentTestCases.numTotalTests - } total`; + const updatedTestsFailed = + testsFailed + valuesForCurrentTestCases.numFailingTests; + const updatedTestsPending = + testsPending + valuesForCurrentTestCases.numPendingTests; + const updatedTestsTodo = testsTodo + valuesForCurrentTestCases.numTodoTests; + const updatedTestsPassed = + testsPassed + valuesForCurrentTestCases.numPassingTests; + const updatedTestsTotal = + testsTotal + valuesForCurrentTestCases.numTotalTests; const tests = chalk.bold('Tests: ') + - (testsFailed ? chalk.bold.red(updatedTestsFailed) + ', ' : '') + - (testsPending ? chalk.bold.yellow(updatedTestsPending) + ', ' : '') + - (testsTodo ? chalk.bold.magenta(updatedTestsTodo) + ', ' : '') + - (testsPassed ? chalk.bold.green(updatedTestsPassed) + ', ' : '') + - updatedTestsTotal; + (updatedTestsFailed > 0 + ? chalk.bold.red(`${updatedTestsFailed} failed`) + ', ' + : '') + + (updatedTestsPending > 0 + ? chalk.bold.yellow(`${updatedTestsPending} skipped`) + ', ' + : '') + + (updatedTestsTodo > 0 + ? chalk.bold.magenta(`${updatedTestsTodo} todo`) + ', ' + : '') + + (updatedTestsPassed > 0 + ? chalk.bold.green(`${updatedTestsPassed} passed`) + ', ' + : '') + + `${updatedTestsTotal} total`; const snapshots = chalk.bold('Snapshots: ') + From 5cc0b97bafa36b2b6eda88185e5d730c36fa7bc6 Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Tue, 28 Jul 2020 17:56:09 +0530 Subject: [PATCH 41/43] update: avoid breaking change + tests updated --- packages/jest-core/src/TestScheduler.ts | 11 +++++++++-- .../jest-core/src/__tests__/TestScheduler.test.js | 8 ++++---- packages/jest-runner/src/__tests__/testRunner.test.ts | 6 ++++++ packages/jest-runner/src/index.ts | 7 +++---- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index d93ce2dd7fd7..4e4ca788edcf 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -241,17 +241,24 @@ export default class TestScheduler { ), ]; - await testRunner.runTests(tests, watcher, testRunnerOptions); + await testRunner.runTests( + tests, + watcher, + undefined, + undefined, + undefined, + testRunnerOptions, + ); unsubscribes.forEach(sub => sub()); } else { await testRunner.runTests( tests, watcher, - testRunnerOptions, onTestFileStart, onResult, onFailure, + testRunnerOptions, ); } } diff --git a/packages/jest-core/src/__tests__/TestScheduler.test.js b/packages/jest-core/src/__tests__/TestScheduler.test.js index f14f72bbdba5..dbbe8c052165 100644 --- a/packages/jest-core/src/__tests__/TestScheduler.test.js +++ b/packages/jest-core/src/__tests__/TestScheduler.test.js @@ -101,7 +101,7 @@ test('schedule tests run in parallel per default', async () => { await scheduler.scheduleTests(tests, {isInterrupted: jest.fn()}); expect(mockParallelRunner.runTests).toHaveBeenCalled(); - expect(mockParallelRunner.runTests.mock.calls[0][2].serial).toBeFalsy(); + expect(mockParallelRunner.runTests.mock.calls[0][5].serial).toBeFalsy(); }); test('schedule tests run in serial if the runner flags them', async () => { @@ -122,7 +122,7 @@ test('schedule tests run in serial if the runner flags them', async () => { await scheduler.scheduleTests(tests, {isInterrupted: jest.fn()}); expect(mockSerialRunner.runTests).toHaveBeenCalled(); - expect(mockSerialRunner.runTests.mock.calls[0][2].serial).toBeTruthy(); + expect(mockSerialRunner.runTests.mock.calls[0][5].serial).toBeTruthy(); }); test('should bail after `n` failures', async () => { @@ -147,7 +147,7 @@ test('should bail after `n` failures', async () => { isWatchMode: () => true, setState, }); - await mockSerialRunner.runTests.mock.calls[0][4](test, { + await mockSerialRunner.runTests.mock.calls[0][3](test, { numFailingTests: 2, snapshot: {}, testResults: [{}], @@ -206,7 +206,7 @@ test('should set runInBand to run in serial', async () => { expect(spyShouldRunInBand).toHaveBeenCalled(); expect(mockParallelRunner.runTests).toHaveBeenCalled(); - expect(mockParallelRunner.runTests.mock.calls[0][2].serial).toBeTruthy(); + expect(mockParallelRunner.runTests.mock.calls[0][5].serial).toBeTruthy(); }); test('should set runInBand to not run in serial', async () => { diff --git a/packages/jest-runner/src/__tests__/testRunner.test.ts b/packages/jest-runner/src/__tests__/testRunner.test.ts index b609a23db2ae..df266697abaf 100644 --- a/packages/jest-runner/src/__tests__/testRunner.test.ts +++ b/packages/jest-runner/src/__tests__/testRunner.test.ts @@ -41,6 +41,9 @@ test('injects the serializable module map into each worker in watch mode', async {context, path: './file2.test.js'}, ], new TestWatcher({isWatchMode: globalConfig.watch}), + undefined, + undefined, + undefined, {serial: false}, ); @@ -72,6 +75,9 @@ test('assign process.env.JEST_WORKER_ID = 1 when in runInBand mode', async () => await new TestRunner(globalConfig).runTests( [{context, path: './file.test.js'}], new TestWatcher({isWatchMode: globalConfig.watch}), + undefined, + undefined, + undefined, {serial: true}, ); diff --git a/packages/jest-runner/src/index.ts b/packages/jest-runner/src/index.ts index 95b3f1100d03..abdba02c39aa 100644 --- a/packages/jest-runner/src/index.ts +++ b/packages/jest-runner/src/index.ts @@ -65,11 +65,10 @@ class TestRunner { async runTests( tests: Array, watcher: JestTestWatcher, + onStart: JestOnTestStart | undefined, + onResult: JestOnTestSuccess | undefined, + onFailure: JestOnTestFailure | undefined, options: JestTestRunnerOptions, - - onStart?: JestOnTestStart, - onResult?: JestOnTestSuccess, - onFailure?: JestOnTestFailure, ): Promise { return await (options.serial ? this._createInBandTestRun(tests, watcher, onStart, onResult, onFailure) From 9c7013eb29540c51a3a4b52475386ea4d245dfcf Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Wed, 29 Jul 2020 22:04:35 +0530 Subject: [PATCH 42/43] fix: added invariant for context and diffs removed --- packages/jest-core/src/TestScheduler.ts | 9 +++++++++ packages/jest-reporters/src/utils.ts | 2 +- packages/jest-types/src/TestResult.ts | 2 +- packages/jest-worker/src/workers/ChildProcessWorker.ts | 1 + 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 4e4ca788edcf..5b14d784593f 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -209,6 +209,9 @@ export default class TestScheduler { for (const runner of Object.keys(testRunners)) { const testRunner = testRunners[runner]; const context = contextsByTestRunner.get(testRunner); + + invariant(context); + const tests = testsByRunner[runner]; const testRunnerOptions = { @@ -439,6 +442,12 @@ export default class TestScheduler { } } +function invariant(condition: unknown, message?: string): asserts condition { + if (!condition) { + throw new Error(message); + } +} + const createAggregatedResults = (numTotalTestSuites: number) => { const result = makeEmptyAggregatedTestResult(); result.numTotalTestSuites = numTotalTestSuites; diff --git a/packages/jest-reporters/src/utils.ts b/packages/jest-reporters/src/utils.ts index a7255bd9a26a..956a1de4a063 100644 --- a/packages/jest-reporters/src/utils.ts +++ b/packages/jest-reporters/src/utils.ts @@ -139,7 +139,7 @@ export const getSummary = ( } const valuesForCurrentTestCases = getValuesCurrentTestCases( - options ? options.currentTestCases : [], + options?.currentTestCases, ); const estimatedTime = (options && options.estimatedTime) || 0; diff --git a/packages/jest-types/src/TestResult.ts b/packages/jest-types/src/TestResult.ts index 47411d47926c..7b2c16b47b86 100644 --- a/packages/jest-types/src/TestResult.ts +++ b/packages/jest-types/src/TestResult.ts @@ -9,7 +9,7 @@ export type Milliseconds = number; type Status = 'passed' | 'failed' | 'skipped' | 'pending' | 'todo' | 'disabled'; -export type Callsite = { +type Callsite = { column: number; line: number; }; diff --git a/packages/jest-worker/src/workers/ChildProcessWorker.ts b/packages/jest-worker/src/workers/ChildProcessWorker.ts index d1f925a2ad7a..4d1822979cb3 100644 --- a/packages/jest-worker/src/workers/ChildProcessWorker.ts +++ b/packages/jest-worker/src/workers/ChildProcessWorker.ts @@ -160,6 +160,7 @@ export default class ChildProcessWorker implements WorkerInterface { private _onMessage(response: ParentMessage) { // TODO: Add appropriate type check let error: any; + switch (response[0]) { case PARENT_MESSAGE_OK: this._onProcessEnd(null, response[1]); From 7b7797c3fdf6844a82959af9c26dcda67211a9dc Mon Sep 17 00:00:00 2001 From: "Saurav M. Hiremath" Date: Thu, 30 Jul 2020 08:16:34 +0530 Subject: [PATCH 43/43] minor fix --- packages/jest-core/src/TestScheduler.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/jest-core/src/TestScheduler.ts b/packages/jest-core/src/TestScheduler.ts index 5b14d784593f..a1eac111ddce 100644 --- a/packages/jest-core/src/TestScheduler.ts +++ b/packages/jest-core/src/TestScheduler.ts @@ -236,10 +236,8 @@ export default class TestScheduler { testRunner.on( 'test-case-result', ([testPath, testCaseResult]) => { - if (context) { - const test: TestRunner.Test = {context, path: testPath}; - this._dispatcher.onTestCaseResult(test, testCaseResult); - } + const test: TestRunner.Test = {context, path: testPath}; + this._dispatcher.onTestCaseResult(test, testCaseResult); }, ), ];