webpack/test/helpers/createLazyTestEnv.js

133 lines
3.3 KiB
JavaScript
Raw Normal View History

"use strict";
module.exports = (globalTimeout = 2000, nameSuffix = "") => {
2024-07-31 09:37:24 +08:00
const state = global.JEST_STATE_SYMBOL;
let currentDescribeBlock;
let currentlyRunningTest;
let runTests = -1;
const disposables = [];
// this function allows to release memory in fn context
// manually, usually after the suite has been run.
const createDisposableFn = (fn, isTest) => {
if (!fn) return null;
2024-08-02 02:36:27 +08:00
const rfn =
fn.length >= 1
? (done) => {
2024-08-02 02:36:27 +08:00
fn((...args) => {
if (isTest) runTests++;
done(...args);
});
}
: () => {
const r = fn();
if (isTest) runTests++;
return r;
};
disposables.push(() => {
fn = null;
});
return rfn;
2018-10-24 21:21:59 +08:00
};
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;
const inSuite = (fn) => {
const {
currentDescribeBlock: oldCurrentDescribeBlock,
currentlyRunningTest: oldCurrentlyRunningTest,
hasStarted: oldHasStarted
} = state;
state.currentDescribeBlock = currentDescribeBlock;
state.currentlyRunningTest = currentlyRunningTest;
state.hasStarted = false;
try {
fn();
2024-07-31 15:37:05 +08:00
} catch (err) {
/* eslint-disable no-unused-expressions */
// avoid leaking memory
2025-04-16 22:04:11 +08:00
/** @type {EXPECTED_ANY} */
(err).stack;
/* eslint-enable no-unused-expressions */
2024-07-31 15:37:05 +08:00
throw err;
}
state.currentDescribeBlock = oldCurrentDescribeBlock;
state.currentlyRunningTest = oldCurrentlyRunningTest;
state.hasStarted = oldHasStarted;
};
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 {
2025-05-01 22:36:51 +08:00
/**
* @param {number} time time
*/
setDefaultTimeout(time) {
globalTimeout = time;
},
getNumberOfTests() {
return numberOfTests;
},
it(...args) {
numberOfTests++;
if (runTests >= numberOfTests) throw new Error("it called too late");
args[1] = createDisposableFn(args[1], true);
2021-06-25 23:41:52 +08:00
args[2] = args[2] || globalTimeout;
inSuite(() => {
2025-04-16 22:04:11 +08:00
// @ts-expect-error expected
it(...args);
fixAsyncError(
currentDescribeBlock.tests[currentDescribeBlock.tests.length - 1]
);
2018-10-24 21:21:59 +08:00
});
},
beforeEach(...args) {
if (runTests >= numberOfTests) {
throw new Error("beforeEach called too late");
}
args[0] = createDisposableFn(args[0]);
inSuite(() => {
2025-04-16 22:04:11 +08:00
// @ts-expect-error expected
beforeEach(...args);
fixAsyncError(
currentDescribeBlock.hooks[currentDescribeBlock.hooks.length - 1]
);
});
},
afterEach(...args) {
if (runTests >= numberOfTests) {
throw new Error("afterEach called too late");
}
args[0] = createDisposableFn(args[0]);
inSuite(() => {
2025-04-16 22:04:11 +08:00
// @ts-expect-error expected
afterEach(...args);
fixAsyncError(
currentDescribeBlock.hooks[currentDescribeBlock.hooks.length - 1]
);
2018-10-24 21:21:59 +08:00
});
}
};
};