/
githubmirror
/
webpack
Обзор
Документация
Войти
/
githubmirror
/
webpack
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
test/helpers/createLazyTestEnv.js
156 строк
4 KB
Alexander Akait
refactor: strict types for the test suite (#21147)
09 июн 2026, 20:15
Не верифицирован
09 июн 2026, 20:15
9bd0b91
Код
Авторство
О чём код?
"use strict"; /** @typedef {(...args: unknown[]) => unknown} AnyFn */ module.exports = (globalTimeout = 2000, nameSuffix = "") => { const state = global.JEST_STATE_SYMBOL; /** @type {import("@jest/types").Circus.DescribeBlock} */ let currentDescribeBlock; /** @type {import("@jest/types").Circus.TestEntry | null | undefined} */ let currentlyRunningTest; let runTests = -1; /** @type {(() => void)[]} */ const disposables = []; // this function allows to release memory in fn context // manually, usually after the suite has been run. /** * @param {AnyFn | undefined} fn test or hook function * @param {boolean=} isTest whether this wraps a test (vs a hook) * @returns {((done: AnyFn) => void) | (() => unknown) | null} wrapped function */ const createDisposableFn = (fn, isTest) => { if (!fn) return null; /** @type {AnyFn | null} */ let f = fn; const rfn = f.length >= 1 ? (/** @type {AnyFn} */ done) => { /** @type {AnyFn} */ (f)((/** @type {unknown[]} */ ...args) => { if (isTest) runTests++; done(...args); }); } : () => { const r = /** @type {AnyFn} */ (f)(); if (isTest) runTests++; return r; }; disposables.push(() => { f = null; }); return rfn; }; describe( nameSuffix ? `exported tests ${nameSuffix}` : "exported tests", () => { // this must have a child to be handled correctly it("should run the exported tests", () => { runTests++; }); afterAll((done) => { for (const dispose of disposables) { dispose(); } done(); }); currentDescribeBlock = state.currentDescribeBlock; currentlyRunningTest = state.currentlyRunningTest; } ); let numberOfTests = 0; /** * @param {() => void} fn function to run inside the exported suite scope * @returns {void} */ const inSuite = (fn) => { const { currentDescribeBlock: oldCurrentDescribeBlock, currentlyRunningTest: oldCurrentlyRunningTest, hasStarted: oldHasStarted } = state; state.currentDescribeBlock = currentDescribeBlock; state.currentlyRunningTest = currentlyRunningTest; state.hasStarted = false; try { fn(); } catch (err) { /* eslint-disable no-unused-expressions */ // avoid leaking memory /** @type {Error} */ (err).stack; /* eslint-enable no-unused-expressions */ throw err; } state.currentDescribeBlock = oldCurrentDescribeBlock; state.currentlyRunningTest = oldCurrentlyRunningTest; state.hasStarted = oldHasStarted; }; /** * @param {import("@jest/types").Circus.TestEntry | import("@jest/types").Circus.Hook} block test or hook entry * @returns {void} */ const fixAsyncError = (block) => { // By default jest leaks memory as it stores asyncError // for each "it" call to track the origin test suite // We want to evaluate this early here to avoid leaking memory block.asyncError = { stack: block.asyncError.stack }; }; return { /** * @param {number} time time */ setDefaultTimeout(time) { globalTimeout = time; }, getNumberOfTests() { return numberOfTests; }, it(/** @type {unknown[]} */ ...args) { numberOfTests++; if (runTests >= numberOfTests) throw new Error("it called too late"); args[1] = createDisposableFn( /** @type {AnyFn | undefined} */ (args[1]), true ); args[2] = args[2] || globalTimeout; inSuite(() => { // @ts-expect-error expected it(...args); fixAsyncError( currentDescribeBlock.tests[currentDescribeBlock.tests.length - 1] ); }); }, beforeEach(/** @type {unknown[]} */ ...args) { if (runTests >= numberOfTests) { throw new Error("beforeEach called too late"); } args[0] = createDisposableFn(/** @type {AnyFn | undefined} */ (args[0])); inSuite(() => { // @ts-expect-error expected beforeEach(...args); fixAsyncError( currentDescribeBlock.hooks[currentDescribeBlock.hooks.length - 1] ); }); }, afterEach(/** @type {unknown[]} */ ...args) { if (runTests >= numberOfTests) { throw new Error("afterEach called too late"); } args[0] = createDisposableFn(/** @type {AnyFn | undefined} */ (args[0])); inSuite(() => { // @ts-expect-error expected afterEach(...args); fixAsyncError( currentDescribeBlock.hooks[currentDescribeBlock.hooks.length - 1] ); }); } }; };