-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
/
index.test.ts
129 lines (102 loc) · 3.51 KB
/
index.test.ts
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
122
123
124
125
126
127
128
129
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
import LeakDetector from '../index';
const gc = global.gc;
// Some tests override the "gc" value. Let's make sure we roll it back to its
// previous value after executing the test.
afterEach(() => {
global.gc = gc;
});
it('complains if the value is a primitive', () => {
expect(() => new LeakDetector(undefined)).toThrowErrorMatchingSnapshot();
expect(() => new LeakDetector(null)).toThrowErrorMatchingSnapshot();
expect(() => new LeakDetector(false)).toThrowErrorMatchingSnapshot();
expect(() => new LeakDetector(42)).toThrowErrorMatchingSnapshot();
expect(() => new LeakDetector('foo')).toThrowErrorMatchingSnapshot();
expect(() => new LeakDetector(Symbol())).toThrowErrorMatchingSnapshot();
expect(() => new LeakDetector(Symbol('foo'))).toThrowErrorMatchingSnapshot();
expect(() => new LeakDetector(NaN)).toThrowErrorMatchingSnapshot();
});
it('does not show the GC if hidden', async () => {
const detector = new LeakDetector({});
// @ts-ignore: purposefully removed
global.gc = undefined;
await detector.isLeaking();
expect(global.gc).not.toBeDefined();
});
it('does not hide the GC if visible', async () => {
const detector = new LeakDetector({});
global.gc = () => {};
await detector.isLeaking();
expect(global.gc).toBeDefined();
});
it('correctly checks simple leaks', async () => {
let reference: unknown = {};
let isLeaking: boolean;
const detector = new LeakDetector(reference);
// Reference is still held in memory.
isLeaking = await detector.isLeaking();
expect(isLeaking).toBe(true);
// We destroy the only reference to the object we had.
reference = null;
// Reference should be gone.
isLeaking = await detector.isLeaking();
expect(isLeaking).toBe(false);
});
it('tests different objects', async () => {
const refs = [
function() {},
() => {},
Object.create(null),
[],
/foo/g,
new Date(1234),
{},
];
const detectors = refs.map(ref => new LeakDetector(ref));
let isLeaking: boolean;
for (const i in detectors) {
isLeaking = await detectors[i].isLeaking();
expect(isLeaking).toBe(true);
refs[i] = null;
}
for (const i in detectors) {
isLeaking = await detectors[i].isLeaking();
expect(isLeaking).toBe(false);
}
});
it('correctly checks more complex leaks', async () => {
let ref1: any = {};
let ref2: any = {};
// Create a circular dependency between ref1 and ref2.
ref1.ref2 = ref2;
ref2.ref1 = ref1;
const detector1 = new LeakDetector(ref1);
const detector2 = new LeakDetector(ref2);
let isLeaking1: boolean;
let isLeaking2: boolean;
// References are still held in memory.
isLeaking1 = await detector1.isLeaking();
expect(isLeaking1).toBe(true);
isLeaking2 = await detector2.isLeaking();
expect(isLeaking2).toBe(true);
// We destroy the reference to ref1.
ref1 = null;
// It will still be referenced by ref2, so both references are still leaking.
isLeaking1 = await detector1.isLeaking();
expect(isLeaking1).toBe(true);
isLeaking2 = await detector2.isLeaking();
expect(isLeaking2).toBe(true);
// We destroy the reference to ref2.
ref2 = null;
// Now both references should be gone (yay mark & sweep!).
isLeaking1 = await detector1.isLeaking();
expect(isLeaking1).toBe(false);
isLeaking2 = await detector2.isLeaking();
expect(isLeaking2).toBe(false);
});