diff --git a/packages/jest-circus/src/__mocks__/testUtils.ts b/packages/jest-circus/src/__mocks__/testUtils.ts index 358c0bf8b685..7dee95a2026e 100644 --- a/packages/jest-circus/src/__mocks__/testUtils.ts +++ b/packages/jest-circus/src/__mocks__/testUtils.ts @@ -47,7 +47,7 @@ export const runTest = ( global.afterAll = circus.afterAll; const testEventHandler = require('${TEST_EVENT_HANDLER_PATH}').default; - const {addEventHandler, getState} = require('${CIRCUS_STATE_PATH}'); + const {addEventHandler, removeEventHandler, getState} = require('${CIRCUS_STATE_PATH}'); getState().randomize = ${opts?.randomize}; getState().seed = ${opts?.seed ?? 0}; addEventHandler(testEventHandler); 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..7915e7182ee7 --- /dev/null +++ b/packages/jest-circus/src/__tests__/eventHandler.test.ts @@ -0,0 +1,25 @@ +/** + * 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. + */ + +// addEventHandler and removeEventHandler are provided in the ./index +import {addEventHandler, removeEventHandler} from '../index'; +// dispatch comes from the ./state +import {dispatch} from '../state'; + +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 eba48fbffdfb..9b4990b06e64 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, convertDescriptorToString, 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 0540dfd41116..8f27b927c5b3 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, ]; @@ -50,17 +50,24 @@ export const setState = (state: Circus.State): Circus.State => /* eslint-enable */ 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 6af26152b661..c60d2ef02263 100644 --- a/packages/jest-circus/src/types.ts +++ b/packages/jest-circus/src/types.ts @@ -11,6 +11,7 @@ export const STATE_SYM = Symbol('JEST_STATE_SYMBOL'); export const RETRY_TIMES = Symbol.for('RETRY_TIMES'); // To pass this value from Runtime object to state we need to use global[sym] export const TEST_TIMEOUT_SYMBOL = Symbol.for('TEST_TIMEOUT_SYMBOL'); +export const EVENT_HANDLERS = Symbol.for('EVENT_HANDLERS'); export const LOG_ERRORS_BEFORE_RETRY = Symbol.for('LOG_ERRORS_BEFORE_RETRY'); declare global { @@ -20,6 +21,7 @@ declare global { [STATE_SYM]: Circus.State; [RETRY_TIMES]: string; [TEST_TIMEOUT_SYMBOL]: number; + [EVENT_HANDLERS]: Array; [LOG_ERRORS_BEFORE_RETRY]: boolean; } }