/
createLazyTestEnv.js
121 lines (119 loc) · 2.97 KB
/
createLazyTestEnv.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
module.exports = (globalTimeout = 2000, nameSuffix = "") => {
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;
let rfn;
if (fn.length >= 1) {
rfn = done => {
fn((...args) => {
if (isTest) runTests++;
done(...args);
});
};
} else {
rfn = () => {
const r = fn();
if (isTest) runTests++;
return r;
};
}
disposables.push(() => {
fn = 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;
const inSuite = fn => {
const {
currentDescribeBlock: oldCurrentDescribeBlock,
currentlyRunningTest: oldCurrentlyRunningTest,
hasStarted: oldHasStarted
} = state;
state.currentDescribeBlock = currentDescribeBlock;
state.currentlyRunningTest = currentlyRunningTest;
state.hasStarted = false;
try {
fn();
} catch (e) {
// avoid leaking memory
e.stack;
throw e;
}
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 {
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);
args[2] = args[2] || globalTimeout;
inSuite(() => {
it(...args);
fixAsyncError(
currentDescribeBlock.tests[currentDescribeBlock.tests.length - 1]
);
});
},
beforeEach(...args) {
if (runTests >= numberOfTests)
throw new Error("beforeEach called too late");
args[0] = createDisposableFn(args[0]);
inSuite(() => {
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(() => {
afterEach(...args);
fixAsyncError(
currentDescribeBlock.hooks[currentDescribeBlock.hooks.length - 1]
);
});
}
};
};