From d9cda507c07db32a0a38dc112013ac1042058e32 Mon Sep 17 00:00:00 2001 From: satanTime Date: Tue, 7 Nov 2023 15:49:01 +0100 Subject: [PATCH] fix: jest-circus shares events among imports #11483 --- .../jest-circus/src/__mocks__/testUtils.ts | 2 +- .../src/__tests__/eventHandler.test.ts | 25 ++++++++++++++++++ packages/jest-circus/src/index.ts | 8 +++++- packages/jest-circus/src/state.ts | 26 +++++++++++++------ packages/jest-circus/src/types.ts | 1 + 5 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 packages/jest-circus/src/__tests__/eventHandler.test.ts diff --git a/packages/jest-circus/src/__mocks__/testUtils.ts b/packages/jest-circus/src/__mocks__/testUtils.ts index fe903ffb3db6..43858af7fc46 100644 --- a/packages/jest-circus/src/__mocks__/testUtils.ts +++ b/packages/jest-circus/src/__mocks__/testUtils.ts @@ -36,7 +36,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..07fd8e656b19 --- /dev/null +++ b/packages/jest-circus/src/__tests__/eventHandler.test.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * 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: any = 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 deda31560871..0e647514a5c8 100644 --- a/packages/jest-circus/src/state.ts +++ b/packages/jest-circus/src/state.ts @@ -8,13 +8,16 @@ import type {Circus, Global} 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 = [ - eventHandler, - formatNodeAssertErrors, -]; +/* eslint-disable no-restricted-globals */ +const handlers: Array = ((global as Global.Global)[ + EVENT_HANDLERS +] = ((global as Global.Global)[ + EVENT_HANDLERS +] as Array) || [eventHandler, formatNodeAssertErrors]); +/* eslint-enable */ export const ROOT_DESCRIBE_BLOCK_NAME = 'ROOT_DESCRIBE_BLOCK'; @@ -52,17 +55,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 handlers) { await handler(event, getState()); } }; export const dispatchSync = (event: Circus.SyncEvent): void => { - for (const handler of eventHandlers) { + for (const handler of handlers) { handler(event, getState()); } }; export const addEventHandler = (handler: Circus.EventHandler): void => { - eventHandlers.push(handler); + handlers.push(handler); +}; + +export const removeEventHandler = (handler: Circus.EventHandler): void => { + const index = handlers.lastIndexOf(handler); + if (index !== -1) { + handlers.splice(index, 1); + } }; diff --git a/packages/jest-circus/src/types.ts b/packages/jest-circus/src/types.ts index 704a35b3733d..f6b23ee6c07b 100644 --- a/packages/jest-circus/src/types.ts +++ b/packages/jest-circus/src/types.ts @@ -9,4 +9,5 @@ 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');