From 8315535300a9f7e79300b68eb475166532e1152b Mon Sep 17 00:00:00 2001 From: MG Date: Sat, 5 Jun 2021 09:59:59 +0200 Subject: [PATCH] fix: jest-circus shares events among imports #11483 --- CHANGELOG.md | 1 + .../jest-circus/src/__mocks__/testUtils.ts | 1 + .../__snapshots__/eventHandler.test.ts.snap | 39 ++++++++++++ .../src/__tests__/eventHandler.test.ts | 59 +++++++++++++++++++ packages/jest-circus/src/index.ts | 8 ++- packages/jest-circus/src/state.ts | 17 ++++-- packages/jest-circus/src/types.ts | 4 ++ 7 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 packages/jest-circus/src/__tests__/__snapshots__/eventHandler.test.ts.snap create mode 100644 packages/jest-circus/src/__tests__/eventHandler.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index b6361880a7b5..edbadd578e57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Fixes +- `[jest-circus]` Shares events with event handlers among imports ([#11483](https://github.com/facebook/jest/pull/11483)) - `[jest-reporter]` Allow `node-notifier@10` as peer dependency ([#11523](https://github.com/facebook/jest/pull/11523)) - `[jest-reporter]` Update `v8-to-istanbul` ([#11523](https://github.com/facebook/jest/pull/11523)) diff --git a/packages/jest-circus/src/__mocks__/testUtils.ts b/packages/jest-circus/src/__mocks__/testUtils.ts index 52557f72fcb8..17cbb071281f 100644 --- a/packages/jest-circus/src/__mocks__/testUtils.ts +++ b/packages/jest-circus/src/__mocks__/testUtils.ts @@ -46,6 +46,7 @@ export const runTest = (source: string) => { const testEventHandler = require('${TEST_EVENT_HANDLER_PATH}').default; const addEventHandler = require('${CIRCUS_STATE_PATH}').addEventHandler; + const removeEventHandler = require('${CIRCUS_STATE_PATH}').removeEventHandler; addEventHandler(testEventHandler); ${source}; diff --git a/packages/jest-circus/src/__tests__/__snapshots__/eventHandler.test.ts.snap b/packages/jest-circus/src/__tests__/__snapshots__/eventHandler.test.ts.snap new file mode 100644 index 000000000000..3bce24727354 --- /dev/null +++ b/packages/jest-circus/src/__tests__/__snapshots__/eventHandler.test.ts.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`addEventHandler registers a callback with events 1`] = ` +start_describe_definition: describe +add_test: receives events +finish_describe_definition: describe +run_start +run_describe_start: ROOT_DESCRIBE_BLOCK +run_describe_start: describe +test_start: receives events +test_fn_start: receives events +called true +test_fn_failure: receives events +test_done: receives events +run_describe_finish: describe +run_describe_finish: ROOT_DESCRIBE_BLOCK +run_finish + +unhandledErrors: 0 +`; + +exports[`removeEventHandler unregisters a callback from events 1`] = ` +start_describe_definition: describe +add_test: does not receive events +finish_describe_definition: describe +run_start +run_describe_start: ROOT_DESCRIBE_BLOCK +run_describe_start: describe +test_start: does not receive events +test_fn_start: does not receive events +called false +test_fn_failure: does not receive events +test_done: does not receive events +run_describe_finish: describe +run_describe_finish: ROOT_DESCRIBE_BLOCK +run_finish + +unhandledErrors: 0 +`; diff --git a/packages/jest-circus/src/__tests__/eventHandler.test.ts b/packages/jest-circus/src/__tests__/eventHandler.test.ts new file mode 100644 index 000000000000..65a10e30a762 --- /dev/null +++ b/packages/jest-circus/src/__tests__/eventHandler.test.ts @@ -0,0 +1,59 @@ +/** + * 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 wrap from 'jest-snapshot-serializer-raw'; +import {runTest} from '../__mocks__/testUtils'; +import {addEventHandler, dispatch, removeEventHandler} from '../state'; + +test('addEventHandler registers a callback with events', () => { + const {stdout} = runTest(` + let called = false; + const callback = () => called = true; + addEventHandler(callback); + + describe('describe', () => { + test('receives events', () => { + console.log('called', called); + expect(called).toEqual(true); + }) + }); + `); + + expect(wrap(stdout)).toMatchSnapshot(); +}); + +test('removeEventHandler unregisters a callback from events', () => { + const {stdout} = runTest(` + let called = false; + const callback = () => called = true; + addEventHandler(callback); + removeEventHandler(callback); + + describe('describe', () => { + test('does not receive events', () => { + console.log('called', called); + expect(called).toEqual(false); + }) + }); + `); + + expect(wrap(stdout)).toMatchSnapshot(); +}); + +test('addEventHandler and removeEventHandler control handlers', async () => { + const spy = jest.fn(); + + addEventHandler(spy); + expect(spy).not.toHaveBeenCalledWith({name: 'unknown1'}, expect.anything()); + await dispatch({name: 'unknown1' as any}); + expect(spy).toHaveBeenCalledWith({name: 'unknown1'}, expect.anything()); + + removeEventHandler(spy); + expect(spy).not.toHaveBeenCalledWith({name: 'unknown2'}, expect.anything()); + await dispatch({name: 'unknown2' as any}); + expect(spy).not.toHaveBeenCalledWith({name: 'unknown2'}, expect.anything()); +}); diff --git a/packages/jest-circus/src/index.ts b/packages/jest-circus/src/index.ts index 26052438c6e1..23f80dce6a16 100644 --- a/packages/jest-circus/src/index.ts +++ b/packages/jest-circus/src/index.ts @@ -10,7 +10,13 @@ import {bind as bindEach} from 'jest-each'; import {ErrorWithStack, isPromise} from 'jest-util'; import {dispatchSync} from './state'; -export {setState, getState, resetState} from './state'; +export { + setState, + getState, + resetState, + addEventHandler, + removeEventHandler, +} from './state'; export {default as run} from './run'; type THook = (fn: Circus.HookFn, timeout?: number) => void; diff --git a/packages/jest-circus/src/state.ts b/packages/jest-circus/src/state.ts index 6f208ab04fcf..09030ad0cc5b 100644 --- a/packages/jest-circus/src/state.ts +++ b/packages/jest-circus/src/state.ts @@ -8,10 +8,10 @@ import type {Circus} from '@jest/types'; import eventHandler from './eventHandler'; import formatNodeAssertErrors from './formatNodeAssertErrors'; -import {STATE_SYM} from './types'; +import {EVENT_HANDLERS, STATE_SYM} from './types'; import {makeDescribe} from './utils'; -const eventHandlers: Array = [ +global[EVENT_HANDLERS] = global[EVENT_HANDLERS] || [ eventHandler, formatNodeAssertErrors, ]; @@ -46,17 +46,24 @@ export const setState = (state: Circus.State): Circus.State => (global[STATE_SYM] = state); export const dispatch = async (event: Circus.AsyncEvent): Promise => { - for (const handler of eventHandlers) { + for (const handler of global[EVENT_HANDLERS]) { await handler(event, getState()); } }; export const dispatchSync = (event: Circus.SyncEvent): void => { - for (const handler of eventHandlers) { + for (const handler of global[EVENT_HANDLERS]) { handler(event, getState()); } }; export const addEventHandler = (handler: Circus.EventHandler): void => { - eventHandlers.push(handler); + global[EVENT_HANDLERS].push(handler); +}; + +export const removeEventHandler = (handler: Circus.EventHandler): void => { + const index = global[EVENT_HANDLERS].lastIndexOf(handler); + if (index !== -1) { + global[EVENT_HANDLERS].splice(index, 1); + } }; diff --git a/packages/jest-circus/src/types.ts b/packages/jest-circus/src/types.ts index d381cfec56e1..fc90e5781e4f 100644 --- a/packages/jest-circus/src/types.ts +++ b/packages/jest-circus/src/types.ts @@ -19,6 +19,9 @@ export const RETRY_TIMES = Symbol.for( export const TEST_TIMEOUT_SYMBOL = Symbol.for( 'TEST_TIMEOUT_SYMBOL', ) as unknown as 'TEST_TIMEOUT_SYMBOL'; +export const EVENT_HANDLERS = Symbol.for( + 'EVENT_HANDLERS', +) as unknown as 'EVENT_HANDLERS'; declare global { module NodeJS { @@ -26,6 +29,7 @@ declare global { STATE_SYM_SYMBOL: Circus.State; RETRY_TIMES_SYMBOL: string; TEST_TIMEOUT_SYMBOL: number; + EVENT_HANDLERS: Array; expect: typeof expect; } }