jest-doctor 0.0.7 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/env/jsdom.js +4 -2
- package/dist/env/node.js +4 -2
- package/dist/patch/fakeTimers.js +32 -25
- package/dist/patch/timers.d.ts +2 -2
- package/dist/patch/timers.js +63 -52
- package/dist/types.d.ts +2 -12
- package/dist/utils/cleanupAfterTest.js +7 -5
- package/dist/utils/getStack.js +6 -3
- package/dist/utils/reportLeaks.js +19 -7
- package/dist/utils/saveRequire.d.ts +3 -0
- package/dist/utils/saveRequire.js +14 -0
- package/package.json +12 -3
- package/readme.md +17 -5
- package/dist/requireEnvironment.d.ts +0 -61
- package/dist/requireEnvironment.js +0 -20
package/dist/env/jsdom.js
CHANGED
|
@@ -3,5 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const
|
|
7
|
-
|
|
6
|
+
const saveRequire_1 = __importDefault(require("../utils/saveRequire"));
|
|
7
|
+
const createEnvMixin_1 = __importDefault(require("../createEnvMixin"));
|
|
8
|
+
const JSDOMEnvironment = (0, saveRequire_1.default)('jest-environment-jsdom');
|
|
9
|
+
exports.default = (0, createEnvMixin_1.default)(JSDOMEnvironment);
|
package/dist/env/node.js
CHANGED
|
@@ -3,5 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const
|
|
7
|
-
|
|
6
|
+
const saveRequire_1 = __importDefault(require("../utils/saveRequire"));
|
|
7
|
+
const createEnvMixin_1 = __importDefault(require("../createEnvMixin"));
|
|
8
|
+
const NodeEnvironment = (0, saveRequire_1.default)('jest-environment-node');
|
|
9
|
+
exports.default = (0, createEnvMixin_1.default)(NodeEnvironment);
|
package/dist/patch/fakeTimers.js
CHANGED
|
@@ -7,22 +7,16 @@ const getStack_1 = __importDefault(require("../utils/getStack"));
|
|
|
7
7
|
const isIgnored_1 = __importDefault(require("../utils/isIgnored"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
9
|
const patchFakeTimers = (that) => {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const clock = originalFakeTimerInstall(config);
|
|
21
|
-
const originalFakeSetTimeout = clock.setTimeout.bind(clock);
|
|
22
|
-
const originalFakeSetInterval = clock.setInterval.bind(clock);
|
|
23
|
-
const originalFakeClearTimeout = clock.clearTimeout.bind(clock);
|
|
24
|
-
const originalFakeClearInterval = clock.clearInterval.bind(clock);
|
|
25
|
-
clock.setTimeout = function (callback, delay) {
|
|
10
|
+
const env = that.global;
|
|
11
|
+
const patchTimersLifeCycles = (api) => {
|
|
12
|
+
const originalUseFakeTimers = api.useFakeTimers.bind(api);
|
|
13
|
+
api.useFakeTimers = (config) => {
|
|
14
|
+
originalUseFakeTimers(config);
|
|
15
|
+
const originalFakeSetTimeout = env.setTimeout.bind(env);
|
|
16
|
+
const originalFakeSetInterval = env.setInterval.bind(env);
|
|
17
|
+
const originalFakeClearTimeout = env.clearTimeout.bind(env);
|
|
18
|
+
const originalFakeClearInterval = env.clearInterval.bind(env);
|
|
19
|
+
env.setTimeout = Object.assign(function (callback, delay) {
|
|
26
20
|
const fakeTimeout = that.leakRecords.get(that.currentTestName)?.fakeTimers;
|
|
27
21
|
const timerId = originalFakeSetTimeout(() => {
|
|
28
22
|
fakeTimeout?.delete(timerId);
|
|
@@ -37,8 +31,8 @@ const patchFakeTimers = (that) => {
|
|
|
37
31
|
});
|
|
38
32
|
}
|
|
39
33
|
return timerId;
|
|
40
|
-
};
|
|
41
|
-
|
|
34
|
+
}, env.setTimeout);
|
|
35
|
+
env.setInterval = Object.assign(function (callback, delay) {
|
|
42
36
|
const intervalId = originalFakeSetInterval(callback, delay);
|
|
43
37
|
const stack = (0, getStack_1.default)(that.global.setInterval);
|
|
44
38
|
if (!(0, isIgnored_1.default)(stack, that.options.report.fakeTimers.ignore)) {
|
|
@@ -51,22 +45,35 @@ const patchFakeTimers = (that) => {
|
|
|
51
45
|
});
|
|
52
46
|
}
|
|
53
47
|
return intervalId;
|
|
54
|
-
};
|
|
55
|
-
|
|
48
|
+
}, env.setInterval);
|
|
49
|
+
env.clearTimeout = Object.assign((timerId) => {
|
|
56
50
|
that.leakRecords.get(that.currentTestName)?.fakeTimers.delete(timerId);
|
|
57
51
|
originalFakeClearTimeout(timerId);
|
|
58
|
-
};
|
|
59
|
-
|
|
52
|
+
}, env.clearTimeout);
|
|
53
|
+
env.clearInterval = Object.assign((intervalId) => {
|
|
60
54
|
that.leakRecords
|
|
61
55
|
.get(that.currentTestName)
|
|
62
56
|
?.fakeTimers.delete(intervalId);
|
|
63
57
|
originalFakeClearInterval(intervalId);
|
|
64
|
-
};
|
|
65
|
-
return clock;
|
|
58
|
+
}, env.clearInterval);
|
|
66
59
|
};
|
|
60
|
+
const originalClearAllTimers = api.clearAllTimers.bind(api);
|
|
61
|
+
api.clearAllTimers = () => {
|
|
62
|
+
that.leakRecords.get(that.currentTestName)?.fakeTimers.clear();
|
|
63
|
+
originalClearAllTimers();
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
if (that.fakeTimersModern) {
|
|
67
|
+
patchTimersLifeCycles(that.fakeTimersModern);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
that.original.stderr(chalk_1.default.yellow('\nModern fake timers could not be mocked!'));
|
|
71
|
+
}
|
|
72
|
+
if (that.fakeTimers) {
|
|
73
|
+
patchTimersLifeCycles(that.fakeTimers);
|
|
67
74
|
}
|
|
68
75
|
else {
|
|
69
|
-
that.original.stderr(chalk_1.default.yellow('\
|
|
76
|
+
that.original.stderr(chalk_1.default.yellow('\nLegacy fake timers could not be mocked!'));
|
|
70
77
|
}
|
|
71
78
|
};
|
|
72
79
|
exports.default = patchFakeTimers;
|
package/dist/patch/timers.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { JestDoctorEnvironment } from '../types';
|
|
2
|
-
declare const
|
|
3
|
-
export default
|
|
2
|
+
declare const patchTimers: (that: JestDoctorEnvironment) => void;
|
|
3
|
+
export default patchTimers;
|
package/dist/patch/timers.js
CHANGED
|
@@ -6,61 +6,72 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const getStack_1 = __importDefault(require("../utils/getStack"));
|
|
7
7
|
const consts_1 = require("../consts");
|
|
8
8
|
const isIgnored_1 = __importDefault(require("../utils/isIgnored"));
|
|
9
|
-
const
|
|
9
|
+
const patchTimers = (that) => {
|
|
10
10
|
const env = that.global;
|
|
11
11
|
const report = that.options.report;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (
|
|
12
|
+
const patch = () => {
|
|
13
|
+
env.setTimeout = Object.assign(function (callback, delay) {
|
|
14
|
+
const owner = that.currentTestName;
|
|
15
|
+
const leakRecord = that.leakRecords.get(owner);
|
|
16
|
+
const stack = (0, getStack_1.default)(env.setTimeout);
|
|
17
|
+
const isAllowed = report.timers && !(0, isIgnored_1.default)(stack, report.timers.ignore);
|
|
18
|
+
const timerId = that.original.setTimeout(() => {
|
|
19
|
+
if (leakRecord && isAllowed) {
|
|
20
|
+
if (owner !== consts_1.MAIN_THREAD && delay) {
|
|
21
|
+
leakRecord.totalDelay += delay;
|
|
22
|
+
}
|
|
23
|
+
leakRecord.timers.delete(timerId);
|
|
24
|
+
}
|
|
25
|
+
callback();
|
|
26
|
+
}, delay);
|
|
27
|
+
leakRecord?.timers.set(timerId, {
|
|
28
|
+
type: 'timeout',
|
|
29
|
+
delay: delay || 0,
|
|
30
|
+
stack,
|
|
31
|
+
isAllowed,
|
|
32
|
+
});
|
|
33
|
+
return timerId;
|
|
34
|
+
}, that.original.setTimeout);
|
|
35
|
+
env.setInterval = Object.assign(function (callback, delay) {
|
|
36
|
+
const owner = that.currentTestName;
|
|
37
|
+
const leakRecord = that.leakRecords.get(owner);
|
|
38
|
+
const stack = (0, getStack_1.default)(env.setInterval);
|
|
39
|
+
const isAllowed = report.timers && !(0, isIgnored_1.default)(stack, report.timers.ignore);
|
|
40
|
+
const intervalId = that.original.setInterval(() => {
|
|
41
|
+
if (isAllowed && owner !== consts_1.MAIN_THREAD && delay && leakRecord) {
|
|
20
42
|
leakRecord.totalDelay += delay;
|
|
21
43
|
}
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}, delay);
|
|
45
|
-
that.leakRecords.get(owner)?.timers.set(intervalId, {
|
|
46
|
-
type: 'interval',
|
|
47
|
-
delay: delay || 0,
|
|
48
|
-
isAllowed,
|
|
49
|
-
stack,
|
|
50
|
-
});
|
|
51
|
-
return intervalId;
|
|
52
|
-
}, that.original.setInterval);
|
|
53
|
-
env.clearTimeout = (timerId) => {
|
|
54
|
-
that.leakRecords
|
|
55
|
-
.get(that.currentTestName)
|
|
56
|
-
?.timers.delete(timerId);
|
|
57
|
-
that.original.clearTimeout(timerId);
|
|
58
|
-
};
|
|
59
|
-
env.clearInterval = (intervalId) => {
|
|
60
|
-
that.leakRecords
|
|
61
|
-
.get(that.currentTestName)
|
|
62
|
-
?.timers.delete(intervalId);
|
|
63
|
-
that.original.clearInterval(intervalId);
|
|
44
|
+
callback();
|
|
45
|
+
}, delay);
|
|
46
|
+
that.leakRecords.get(owner)?.timers.set(intervalId, {
|
|
47
|
+
type: 'interval',
|
|
48
|
+
delay: delay || 0,
|
|
49
|
+
isAllowed,
|
|
50
|
+
stack,
|
|
51
|
+
});
|
|
52
|
+
return intervalId;
|
|
53
|
+
}, that.original.setInterval);
|
|
54
|
+
env.clearTimeout = (timerId) => {
|
|
55
|
+
that.leakRecords
|
|
56
|
+
.get(that.currentTestName)
|
|
57
|
+
?.timers.delete(timerId);
|
|
58
|
+
that.original.clearTimeout(timerId);
|
|
59
|
+
};
|
|
60
|
+
env.clearInterval = (intervalId) => {
|
|
61
|
+
that.leakRecords
|
|
62
|
+
.get(that.currentTestName)
|
|
63
|
+
?.timers.delete(intervalId);
|
|
64
|
+
that.original.clearInterval(intervalId);
|
|
65
|
+
};
|
|
64
66
|
};
|
|
67
|
+
if (that.fakeTimers) {
|
|
68
|
+
// legacy fake timers will overwrite the existing objects and not restore them
|
|
69
|
+
const originalUseRealTimers = that.fakeTimers.useRealTimers.bind(that.fakeTimers);
|
|
70
|
+
that.fakeTimers.useRealTimers = () => {
|
|
71
|
+
originalUseRealTimers();
|
|
72
|
+
patch();
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
patch();
|
|
65
76
|
};
|
|
66
|
-
exports.default =
|
|
77
|
+
exports.default = patchTimers;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ModernFakeTimers } from '@jest/fake-timers';
|
|
2
1
|
import { JestEnvironment } from '@jest/environment';
|
|
3
2
|
import initOriginal from './utils/initOriginal';
|
|
4
3
|
import type { AsyncHook } from 'node:async_hooks';
|
|
@@ -40,20 +39,12 @@ export interface LeakRecord {
|
|
|
40
39
|
totalDelay: number;
|
|
41
40
|
fakeTimers: Map<number, TimerRecord>;
|
|
42
41
|
}
|
|
43
|
-
interface Clock {
|
|
42
|
+
export interface Clock {
|
|
44
43
|
setTimeout: (callback: () => void, delay?: number) => number;
|
|
45
44
|
setInterval: (callback: () => void, delay?: number) => number;
|
|
46
45
|
clearTimeout: (timeoutId: number) => void;
|
|
47
46
|
clearInterval: (intervalId: number) => void;
|
|
48
47
|
}
|
|
49
|
-
export interface FakeTimers extends Omit<ModernFakeTimers, '_fakeTimers'> {
|
|
50
|
-
_fakeTimers: {
|
|
51
|
-
install: (config: unknown) => Clock;
|
|
52
|
-
};
|
|
53
|
-
_clock: {
|
|
54
|
-
timers: Record<string, unknown>;
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
48
|
export type TimerIsolation = 'afterEach' | 'immediate';
|
|
58
49
|
export type OnError = false | 'throw' | 'warn';
|
|
59
50
|
export type ThrowOrWarn = 'throw' | 'warn';
|
|
@@ -110,9 +101,8 @@ export interface AggregatedReport {
|
|
|
110
101
|
processOutputs: number;
|
|
111
102
|
totalDelay: number;
|
|
112
103
|
}
|
|
113
|
-
export interface JestDoctorEnvironment {
|
|
104
|
+
export interface JestDoctorEnvironment extends JestEnvironment {
|
|
114
105
|
global: JestEnvironment['global'];
|
|
115
|
-
fakeTimersModern: ModernFakeTimers | null;
|
|
116
106
|
original: ReturnType<typeof initOriginal>;
|
|
117
107
|
currentTestName: string;
|
|
118
108
|
leakRecords: Map<string, LeakRecord>;
|
|
@@ -3,11 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const cleanupAfterTest = (that, leakRecord, testName) => {
|
|
4
4
|
if (that.currentAfterEachCount === 0) {
|
|
5
5
|
if (that.options.clearTimers) {
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
// @ts-expect-error it is public but signaled as internal
|
|
7
|
+
if (that.fakeTimers?._fakingTime) {
|
|
8
|
+
that.fakeTimers.clearAllTimers();
|
|
9
|
+
}
|
|
10
|
+
// @ts-expect-error it is public but signaled as internal
|
|
11
|
+
if (that.fakeTimersModern?._fakingTime) {
|
|
12
|
+
that.fakeTimersModern.clearAllTimers();
|
|
11
13
|
}
|
|
12
14
|
for (const [timerId, record] of leakRecord.timers.entries()) {
|
|
13
15
|
if (record.type === 'timeout') {
|
package/dist/utils/getStack.js
CHANGED
|
@@ -6,15 +6,18 @@ const getStack = (stackFrom) => {
|
|
|
6
6
|
};
|
|
7
7
|
Error.captureStackTrace(error, stackFrom);
|
|
8
8
|
const lines = error.stack.replace(/\\/g, '/').split('\n');
|
|
9
|
+
lines.shift();
|
|
9
10
|
const finalStack = [];
|
|
10
11
|
for (const line of lines) {
|
|
11
|
-
if (
|
|
12
|
+
if (/[/\\]/.test(line) && // this will remove all anonymous frames without a path
|
|
13
|
+
!line.includes('(node:internal/') &&
|
|
12
14
|
!line.includes('node_modules/jest-runtime') &&
|
|
13
15
|
!line.includes('node_modules/jest-circus') &&
|
|
14
|
-
!line.includes('node_modules/jest-runner')
|
|
16
|
+
!line.includes('node_modules/jest-runner') &&
|
|
17
|
+
!line.includes('node_modules/jest-doctor')) {
|
|
15
18
|
finalStack.push(line);
|
|
16
19
|
}
|
|
17
20
|
}
|
|
18
|
-
return
|
|
21
|
+
return finalStack.join('\n');
|
|
19
22
|
};
|
|
20
23
|
exports.default = getStack;
|
|
@@ -47,16 +47,28 @@ const reportLeaks = (that, leakRecord) => {
|
|
|
47
47
|
that.aggregatedReport.totalDelay += leakRecord.totalDelay;
|
|
48
48
|
}
|
|
49
49
|
if (that.options.verbose) {
|
|
50
|
-
const logLeak = (
|
|
51
|
-
|
|
50
|
+
const logLeak = (label, message, property) => {
|
|
51
|
+
if (message && report[property] && report[property].onError !== 'warn') {
|
|
52
|
+
that.original.stderr('\n' + chalk_1.default.red(label) + '\n' + chalk_1.default.red(message) + '\n');
|
|
53
|
+
}
|
|
52
54
|
};
|
|
53
|
-
leakRecord.promises.forEach(
|
|
55
|
+
leakRecord.promises.forEach(({ stack }) => {
|
|
56
|
+
logLeak(`Open promise:`, stack, 'promises');
|
|
57
|
+
});
|
|
54
58
|
if (that.currentAfterEachCount === 0) {
|
|
55
|
-
accountAbleTimers.forEach(
|
|
56
|
-
|
|
59
|
+
accountAbleTimers.forEach(({ stack }) => {
|
|
60
|
+
logLeak(`Open timer:`, stack, 'timers');
|
|
61
|
+
});
|
|
62
|
+
leakRecord.fakeTimers.forEach(({ stack }) => {
|
|
63
|
+
logLeak(`Open fake timer:`, stack, 'fakeTimers');
|
|
64
|
+
});
|
|
57
65
|
}
|
|
58
|
-
leakRecord.console.forEach(
|
|
59
|
-
|
|
66
|
+
leakRecord.console.forEach(({ stack }) => {
|
|
67
|
+
logLeak(`Console output:`, stack, 'console');
|
|
68
|
+
});
|
|
69
|
+
leakRecord.processOutputs.forEach(({ stack }) => {
|
|
70
|
+
logLeak(`Process output:`, stack, 'processOutputs');
|
|
71
|
+
});
|
|
60
72
|
}
|
|
61
73
|
try {
|
|
62
74
|
checkErrorArray(leakRecord.console, 'console output(s)', report.console.onError);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const saveRequire = (envName) => {
|
|
4
|
+
try {
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
6
|
+
return require(envName).default;
|
|
7
|
+
}
|
|
8
|
+
catch (error) {
|
|
9
|
+
throw new Error(`${envName} needs to be installed as a peer dependency`, {
|
|
10
|
+
cause: error,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
exports.default = saveRequire;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jest-doctor",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "jest environment for leak detection",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "jest environment for leak and issue detection",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Stephan Dum",
|
|
7
7
|
"type": "commonjs",
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"exports": {
|
|
14
14
|
"./package.json": "./package.json",
|
|
15
15
|
"./createEnvMixin": "./dist/createEnvMixin.js",
|
|
16
|
-
"./require": "./dist/requireEnvironment.js",
|
|
17
16
|
"./env/node": "./dist/env/node.js",
|
|
18
17
|
"./env/jsdom": "./dist/env/jsdom.js",
|
|
19
18
|
"./reporter": "./dist/reporter.js"
|
|
@@ -22,6 +21,16 @@
|
|
|
22
21
|
"dist",
|
|
23
22
|
"readme.md"
|
|
24
23
|
],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"jest",
|
|
26
|
+
"jest-doctor",
|
|
27
|
+
"leak detection",
|
|
28
|
+
"open handles",
|
|
29
|
+
"issue detection",
|
|
30
|
+
"testing",
|
|
31
|
+
"jest environment",
|
|
32
|
+
"test hygien"
|
|
33
|
+
],
|
|
25
34
|
"types": "./dist/types.d.ts",
|
|
26
35
|
"devDependencies": {
|
|
27
36
|
"@dev/eslint": "1.0.0",
|
package/readme.md
CHANGED
|
@@ -100,7 +100,6 @@ export default {
|
|
|
100
100
|
|
|
101
101
|
## Limitations
|
|
102
102
|
- it.concurrent is replaced with a sync version
|
|
103
|
-
- legacy fake timers are not mocked
|
|
104
103
|
- test and hook blocks do not support done callback or generators
|
|
105
104
|
- promises that resolve within the next tick cannot be tracked, for example:
|
|
106
105
|
```js
|
|
@@ -108,11 +107,24 @@ Promise.resolve().then(() => {
|
|
|
108
107
|
/* i am not tracked as unresolved */
|
|
109
108
|
});
|
|
110
109
|
```
|
|
111
|
-
- Promise.race, Promise.any and Promise.all
|
|
110
|
+
- Promise.race, Promise.any and Promise.all do not support nested blocks.
|
|
112
111
|
```js
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
await
|
|
112
|
+
const doSomething = async () => {
|
|
113
|
+
// both promises will be tracked and never released
|
|
114
|
+
await someAsyncTask();
|
|
115
|
+
return new Promise(() => { setTimeout(resolve, 10)})
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const p1 = Promise.resolve()
|
|
119
|
+
.then(() => { /* no problem if not async */});
|
|
120
|
+
|
|
121
|
+
const p2 = Promise.resolve()
|
|
122
|
+
.then(() => new Promise((resolve) => {
|
|
123
|
+
/* the promise will be also always tracked */
|
|
124
|
+
resolve();
|
|
125
|
+
}));
|
|
126
|
+
|
|
127
|
+
await Promise.race([p1, p2, doSomething()]);
|
|
116
128
|
```
|
|
117
129
|
|
|
118
130
|
- setTimeout / setInterval can also be imported and will not participate in leak detection in these cases, but this can also serve as exit hatch if needed.
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { type JestDoctorConstructor } from './createEnvMixin';
|
|
2
|
-
declare const requireEnvironment: (envName: string) => {
|
|
3
|
-
new (config: import("@jest/environment").JestEnvironmentConfig, context: import("@jest/environment").EnvironmentContext): {
|
|
4
|
-
currentTestName: string;
|
|
5
|
-
readonly leakRecords: Map<string, import("./types").LeakRecord>;
|
|
6
|
-
readonly original: {
|
|
7
|
-
setTimeout: typeof setTimeout;
|
|
8
|
-
clearTimeout: typeof clearTimeout;
|
|
9
|
-
setInterval: typeof setInterval;
|
|
10
|
-
clearInterval: typeof clearInterval;
|
|
11
|
-
stdout: {
|
|
12
|
-
(buffer: Uint8Array | string, cb?: (err?: Error | null) => void): boolean;
|
|
13
|
-
(str: Uint8Array | string, encoding?: BufferEncoding, cb?: (err?: Error | null) => void): boolean;
|
|
14
|
-
};
|
|
15
|
-
stderr: {
|
|
16
|
-
(buffer: Uint8Array | string, cb?: (err?: Error | null) => void): boolean;
|
|
17
|
-
(str: Uint8Array | string, encoding?: BufferEncoding, cb?: (err?: Error | null) => void): boolean;
|
|
18
|
-
};
|
|
19
|
-
console: {
|
|
20
|
-
log: (message?: any, ...optionalParams: any[]) => void;
|
|
21
|
-
info: (message?: any, ...optionalParams: any[]) => void;
|
|
22
|
-
warn: (message?: any, ...optionalParams: any[]) => void;
|
|
23
|
-
error: (message?: any, ...optionalParams: any[]) => void;
|
|
24
|
-
debug: (message?: any, ...optionalParams: any[]) => void;
|
|
25
|
-
trace: (message?: any, ...optionalParams: any[]) => void;
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
readonly promiseOwner: Map<number, string>;
|
|
29
|
-
readonly asyncHookDetector?: import("async_hooks").AsyncHook;
|
|
30
|
-
readonly asyncHookCleaner?: import("async_hooks").AsyncHook;
|
|
31
|
-
readonly options: import("./types").NormalizedOptions;
|
|
32
|
-
seenTearDown: boolean;
|
|
33
|
-
currentAfterEachCount: number;
|
|
34
|
-
readonly reporterTmpDir: string;
|
|
35
|
-
readonly testPath: string;
|
|
36
|
-
readonly aggregatedReport: {
|
|
37
|
-
testPath: string;
|
|
38
|
-
promises: number;
|
|
39
|
-
timers: number;
|
|
40
|
-
fakeTimers: number;
|
|
41
|
-
console: number;
|
|
42
|
-
totalDelay: number;
|
|
43
|
-
processOutputs: number;
|
|
44
|
-
};
|
|
45
|
-
tearDownError?: Error;
|
|
46
|
-
asyncIdToPromise: Map<number, Promise<unknown>>;
|
|
47
|
-
asyncRoot: number;
|
|
48
|
-
asyncIdToParentId: Map<number, number>;
|
|
49
|
-
setup(): Promise<void>;
|
|
50
|
-
handleEvent(event: unknown, state: unknown): Promise<void>;
|
|
51
|
-
handleTestEvent: import("@jest/environment").JestEnvironment["handleTestEvent"];
|
|
52
|
-
teardown(): Promise<void>;
|
|
53
|
-
global: import("@jest/environment").JestEnvironment["global"];
|
|
54
|
-
fakeTimers: import("@jest/fake-timers").LegacyFakeTimers<unknown> | null;
|
|
55
|
-
fakeTimersModern: import("@jest/fake-timers").ModernFakeTimers | null;
|
|
56
|
-
moduleMocker: import("jest-mock").ModuleMocker | null;
|
|
57
|
-
getVmContext: () => import("vm").Context | null;
|
|
58
|
-
exportConditions: (() => Array<string>) | undefined;
|
|
59
|
-
};
|
|
60
|
-
} & JestDoctorConstructor;
|
|
61
|
-
export default requireEnvironment;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const createEnvMixin_1 = __importDefault(require("./createEnvMixin"));
|
|
7
|
-
const requireEnvironment = (envName) => {
|
|
8
|
-
try {
|
|
9
|
-
const JsdomEnvironment =
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
11
|
-
require(envName).default;
|
|
12
|
-
return (0, createEnvMixin_1.default)(JsdomEnvironment);
|
|
13
|
-
}
|
|
14
|
-
catch (error) {
|
|
15
|
-
throw new Error(`${envName} needs to be installed as a peer dependency`, {
|
|
16
|
-
cause: error,
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
exports.default = requireEnvironment;
|