@memlab/api 1.0.1 → 1.0.4
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/API.d.ts +142 -18
- package/dist/API.js +146 -17
- package/dist/__tests__/API/E2EDetachedDOMAnalysis.test.js +5 -6
- package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.js +5 -6
- package/dist/__tests__/API/E2EFindLeaks.example.d.ts +11 -0
- package/dist/__tests__/API/E2EFindLeaks.example.js +50 -0
- package/dist/__tests__/API/E2EFindMemoryLeaks.test.d.ts +11 -0
- package/dist/__tests__/API/E2EFindMemoryLeaks.test.js +72 -0
- package/dist/__tests__/API/E2EResultReader.test.d.ts +11 -0
- package/dist/__tests__/API/E2EResultReader.test.js +72 -0
- package/dist/__tests__/API/E2ERunSingleSnapshot.example.js +11 -12
- package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.js +8 -17
- package/dist/__tests__/API/E2EStringAnalysis.test.js +19 -15
- package/dist/__tests__/heap/examples/example-1.d.ts +11 -0
- package/dist/__tests__/heap/examples/example-1.js +37 -0
- package/dist/__tests__/heap/examples/example-2.d.ts +11 -0
- package/dist/__tests__/heap/examples/example-2.js +33 -0
- package/dist/__tests__/heap/examples/example-3.d.ts +11 -0
- package/dist/__tests__/heap/examples/example-3.js +33 -0
- package/dist/__tests__/heap/examples/example-4.d.ts +11 -0
- package/dist/__tests__/heap/examples/example-4.js +32 -0
- package/dist/__tests__/heap/examples/example-5.test.d.ts +11 -0
- package/dist/__tests__/heap/examples/example-5.test.js +41 -0
- package/dist/__tests__/heap/examples/example-6.d.ts +11 -0
- package/dist/__tests__/heap/examples/example-6.js +32 -0
- package/dist/__tests__/heap/examples/example-7.test.d.ts +11 -0
- package/dist/__tests__/heap/examples/example-7.test.js +36 -0
- package/dist/__tests__/packages/heap-analysis.test.d.ts +11 -0
- package/dist/__tests__/packages/heap-analysis.test.js +82 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +11 -2
- package/dist/result-reader/BaseResultReader.d.ts +70 -0
- package/dist/result-reader/BaseResultReader.js +96 -0
- package/dist/result-reader/BrowserInteractionResultReader.d.ts +105 -0
- package/dist/result-reader/BrowserInteractionResultReader.js +136 -0
- package/package.json +2 -1
- package/dist/API.d.ts.map +0 -1
- package/dist/__tests__/API/E2EBasicAnalysis.test.d.ts.map +0 -1
- package/dist/__tests__/API/E2EDetachedDOMAnalysis.test.d.ts.map +0 -1
- package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.d.ts.map +0 -1
- package/dist/__tests__/API/E2ERunMultipleSnapshots.example.d.ts.map +0 -1
- package/dist/__tests__/API/E2ERunSingleSnapshot.example.d.ts.map +0 -1
- package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.d.ts.map +0 -1
- package/dist/__tests__/API/E2EStringAnalysis.test.d.ts.map +0 -1
- package/dist/__tests__/API/lib/E2ETestSettings.d.ts.map +0 -1
- package/dist/__tests__/heap/E2EHeapParser.test.d.ts.map +0 -1
- package/dist/__tests__/heap/lib/HeapParserTestUtils.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/APIUtils.d.ts.map +0 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
25
|
+
const fs_1 = __importDefault(require("fs"));
|
|
26
|
+
const BrowserInteractionResultReader_1 = __importDefault(require("../../result-reader/BrowserInteractionResultReader"));
|
|
27
|
+
const index_1 = require("../../index");
|
|
28
|
+
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
29
|
+
beforeEach(E2ETestSettings_1.testSetup);
|
|
30
|
+
function inject() {
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
window.injectHookForLink4 = () => {
|
|
33
|
+
const arr = [];
|
|
34
|
+
for (let i = 0; i < 10000; ++i) {
|
|
35
|
+
arr.push('duplicated string value' + (i % 1));
|
|
36
|
+
}
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
window.__injectedValue = arr;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function checkResultReader(result) {
|
|
42
|
+
const workDir = result.getRootDirectory();
|
|
43
|
+
expect(fs_1.default.existsSync(workDir)).toBe(true);
|
|
44
|
+
const snapshotDir = result.getSnapshotFileDir();
|
|
45
|
+
expect(fs_1.default.existsSync(snapshotDir)).toBe(true);
|
|
46
|
+
const snapshotFiles = result.getSnapshotFiles();
|
|
47
|
+
expect(snapshotFiles.length > 0).toBe(true);
|
|
48
|
+
const steps = result.getInteractionSteps();
|
|
49
|
+
expect(steps.length > 0).toBe(true);
|
|
50
|
+
expect(steps[0].name).toBe('page-load');
|
|
51
|
+
const runMeta = result.getRunMetaInfo();
|
|
52
|
+
expect(runMeta.app).toBe('test-spa');
|
|
53
|
+
result.cleanup();
|
|
54
|
+
expect(fs_1.default.existsSync(workDir)).toBe(false);
|
|
55
|
+
expect(() => result.getRootDirectory()).toThrowError();
|
|
56
|
+
expect(() => result.getSnapshotFileDir()).toThrowError();
|
|
57
|
+
expect(() => result.getSnapshotFiles()).toThrowError();
|
|
58
|
+
}
|
|
59
|
+
test('result data/file reader is working as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
|
+
const result = yield (0, index_1.warmupAndTakeSnapshots)({
|
|
61
|
+
scenario: E2ETestSettings_1.scenario,
|
|
62
|
+
evalInBrowserAfterInitLoad: inject,
|
|
63
|
+
});
|
|
64
|
+
checkResultReader(result);
|
|
65
|
+
}), E2ETestSettings_1.testTimeout);
|
|
66
|
+
test('ResultReader.from is working as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
67
|
+
const result = yield (0, index_1.warmupAndTakeSnapshots)({
|
|
68
|
+
scenario: E2ETestSettings_1.scenario,
|
|
69
|
+
evalInBrowserAfterInitLoad: inject,
|
|
70
|
+
});
|
|
71
|
+
checkResultReader(BrowserInteractionResultReader_1.default.from(result.getRootDirectory()));
|
|
72
|
+
}), E2ETestSettings_1.testTimeout);
|
|
@@ -17,22 +17,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
-
};
|
|
23
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
const path_1 = __importDefault(require("path"));
|
|
25
21
|
const index_1 = require("../../index");
|
|
26
22
|
const scenario = {
|
|
27
23
|
app: () => 'test-spa',
|
|
28
24
|
url: () => '',
|
|
29
25
|
action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
|
|
30
26
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
function test() {
|
|
28
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
29
|
+
const result = yield (0, index_1.warmupAndTakeSnapshots)({
|
|
30
|
+
scenario,
|
|
31
|
+
});
|
|
32
|
+
const analysis = new index_1.StringAnalysis();
|
|
33
|
+
const snapshotFile = result.getSnapshotFiles().pop();
|
|
34
|
+
analysis.analyzeSnapshotFromFile(snapshotFile);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
test();
|
|
@@ -17,12 +17,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
-
};
|
|
23
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
21
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
25
|
-
const path_1 = __importDefault(require("path"));
|
|
26
22
|
const index_1 = require("../../index");
|
|
27
23
|
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
28
24
|
beforeEach(E2ETestSettings_1.testSetup);
|
|
@@ -44,29 +40,24 @@ function inject() {
|
|
|
44
40
|
test('Shape unbound analysis works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
41
|
const repeatScenario = Object.assign({ repeat: () => 2 }, E2ETestSettings_1.scenario);
|
|
46
42
|
// test analysis from auto loading
|
|
47
|
-
const result = yield (0, index_1.
|
|
43
|
+
const result = yield (0, index_1.warmupAndTakeSnapshots)({
|
|
48
44
|
scenario: repeatScenario,
|
|
49
45
|
evalInBrowserAfterInitLoad: inject,
|
|
50
46
|
snapshotForEachStep: true,
|
|
51
47
|
});
|
|
52
48
|
// test analysis from auto loading
|
|
53
49
|
let analysis = new index_1.ShapeUnboundGrowthAnalysis();
|
|
54
|
-
|
|
50
|
+
yield analysis.run();
|
|
51
|
+
let shapeSummary = analysis.getShapesWithUnboundGrowth();
|
|
55
52
|
expect(shapeSummary.reduce((acc, summary) => acc || summary.shape.includes('LeakObject'), false)).toBe(true);
|
|
56
53
|
// test analysis from file
|
|
57
|
-
const snapshotDir =
|
|
54
|
+
const snapshotDir = result.getSnapshotFileDir();
|
|
58
55
|
analysis = new index_1.ShapeUnboundGrowthAnalysis();
|
|
59
|
-
|
|
56
|
+
yield analysis.analyzeSnapshotsInDirectory(snapshotDir);
|
|
57
|
+
shapeSummary = analysis.getShapesWithUnboundGrowth();
|
|
60
58
|
expect(shapeSummary.some((summary) => summary.shape.includes('LeakObject'))).toBe(true);
|
|
61
59
|
// expect incorrect use of heap analysis to throw
|
|
62
|
-
const snapshotFile =
|
|
60
|
+
const snapshotFile = result.getSnapshotFiles().pop();
|
|
63
61
|
analysis = new index_1.ShapeUnboundGrowthAnalysis();
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
yield analysis.analyzeSnapshotFromFile(snapshotFile);
|
|
67
|
-
}
|
|
68
|
-
catch (ex) {
|
|
69
|
-
isThrow = true;
|
|
70
|
-
}
|
|
71
|
-
expect(isThrow).toBe(true);
|
|
62
|
+
expect(() => __awaiter(void 0, void 0, void 0, function* () { return yield analysis.analyzeSnapshotFromFile(snapshotFile); })).rejects.toThrowError();
|
|
72
63
|
}), E2ETestSettings_1.testTimeout);
|
|
@@ -17,12 +17,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
17
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
-
};
|
|
23
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
21
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
25
|
-
const path_1 = __importDefault(require("path"));
|
|
26
22
|
const index_1 = require("../../index");
|
|
27
23
|
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
28
24
|
beforeEach(E2ETestSettings_1.testSetup);
|
|
@@ -38,7 +34,10 @@ function inject() {
|
|
|
38
34
|
};
|
|
39
35
|
}
|
|
40
36
|
test('String analysis works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
41
|
-
const result = yield (0, index_1.
|
|
37
|
+
const result = yield (0, index_1.warmupAndTakeSnapshots)({
|
|
38
|
+
scenario: E2ETestSettings_1.scenario,
|
|
39
|
+
evalInBrowserAfterInitLoad: inject,
|
|
40
|
+
});
|
|
42
41
|
// test analysis from auto loading
|
|
43
42
|
let analysis = new index_1.StringAnalysis();
|
|
44
43
|
yield analysis.run();
|
|
@@ -46,21 +45,26 @@ test('String analysis works as expected', () => __awaiter(void 0, void 0, void 0
|
|
|
46
45
|
expect(dupStrings[0].n).toBe(10000);
|
|
47
46
|
expect(dupStrings[0].str).toBe('duplicated string value0');
|
|
48
47
|
// test analysis from file
|
|
49
|
-
const snapshotFile =
|
|
48
|
+
const snapshotFile = result.getSnapshotFiles().pop();
|
|
50
49
|
analysis = new index_1.StringAnalysis();
|
|
51
50
|
yield analysis.analyzeSnapshotFromFile(snapshotFile);
|
|
52
51
|
dupStrings = analysis.getTopDuplicatedStringsInCount();
|
|
53
52
|
expect(dupStrings[0].n).toBe(10000);
|
|
54
53
|
expect(dupStrings[0].str).toBe('duplicated string value0');
|
|
55
54
|
// expect incorrect use of heap analysis to throw
|
|
56
|
-
const snapshotDir = result.
|
|
55
|
+
const snapshotDir = result.getSnapshotFileDir();
|
|
57
56
|
analysis = new index_1.StringAnalysis();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
|
|
57
|
+
expect(() => __awaiter(void 0, void 0, void 0, function* () { return yield analysis.analyzeSnapshotsInDirectory(snapshotDir); })).rejects.toThrowError();
|
|
58
|
+
}), E2ETestSettings_1.testTimeout);
|
|
59
|
+
test('analyze function works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
60
|
+
const result = yield (0, index_1.warmupAndTakeSnapshots)({
|
|
61
|
+
scenario: E2ETestSettings_1.scenario,
|
|
62
|
+
evalInBrowserAfterInitLoad: inject,
|
|
63
|
+
});
|
|
64
|
+
// test analysis from auto loading
|
|
65
|
+
const analysis = new index_1.StringAnalysis();
|
|
66
|
+
yield (0, index_1.analyze)(result, analysis);
|
|
67
|
+
const dupStrings = analysis.getTopDuplicatedStringsInCount();
|
|
68
|
+
expect(dupStrings[0].n).toBe(10000);
|
|
69
|
+
expect(dupStrings[0].str).toBe('duplicated string value0');
|
|
66
70
|
}), E2ETestSettings_1.testTimeout);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=example-1.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
class TestObject {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.arr1 = [1, 2, 3];
|
|
25
|
+
this.arr2 = ['1', '2', '3'];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
(function () {
|
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
31
|
+
const obj = new TestObject();
|
|
32
|
+
// get a heap snapshot of the current program state
|
|
33
|
+
const heap = yield (0, core_1.getNodeInnocentHeap)();
|
|
34
|
+
const node = heap.getAnyObjectWithClassName('TestObject');
|
|
35
|
+
console.log(node === null || node === void 0 ? void 0 : node.name);
|
|
36
|
+
});
|
|
37
|
+
})();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=example-2.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
const heap_analysis_1 = require("@memlab/heap-analysis");
|
|
23
|
+
(function () {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
const heapFile = (0, core_1.dumpNodeHeapSnapshot)();
|
|
26
|
+
const heap = yield (0, heap_analysis_1.getHeapFromFile)(heapFile);
|
|
27
|
+
// get the total number of heap objects
|
|
28
|
+
heap.nodes.length;
|
|
29
|
+
heap.nodes.forEach((node) => {
|
|
30
|
+
console.log(node.name);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
})();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=example-3.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
const heap_analysis_1 = require("@memlab/heap-analysis");
|
|
23
|
+
(function () {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
const heapFile = (0, core_1.dumpNodeHeapSnapshot)();
|
|
26
|
+
const heap = yield (0, heap_analysis_1.getHeapFromFile)(heapFile);
|
|
27
|
+
// get the total number of heap references
|
|
28
|
+
heap.edges.length;
|
|
29
|
+
heap.edges.forEach((edge) => {
|
|
30
|
+
console.log(edge.name_or_index);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
})();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=example-4.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
const heap_analysis_1 = require("@memlab/heap-analysis");
|
|
23
|
+
(function () {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
const heapFile = (0, core_1.dumpNodeHeapSnapshot)();
|
|
26
|
+
const heap = yield (0, heap_analysis_1.getHeapFromFile)(heapFile);
|
|
27
|
+
const node = heap.getNodeById(1);
|
|
28
|
+
if (node) {
|
|
29
|
+
console.log(node.id);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
})();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=example-5.test.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
class TestObject {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.arr1 = [1, 2, 3];
|
|
25
|
+
this.arr2 = ['1', '2', '3'];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
test('memory test', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
29
|
+
core_1.config.muteConsole = true;
|
|
30
|
+
let obj = new TestObject();
|
|
31
|
+
// get a heap snapshot of the current program state
|
|
32
|
+
let heap = yield (0, core_1.getNodeInnocentHeap)();
|
|
33
|
+
// call some function that may add references to obj
|
|
34
|
+
// rabbitHole()
|
|
35
|
+
expect(heap.hasObjectWithClassName('TestObject')).toBe(true);
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
37
|
+
obj = null;
|
|
38
|
+
heap = yield (0, core_1.getNodeInnocentHeap)();
|
|
39
|
+
// if rabbitHole does not add new references, the obj can be GCed
|
|
40
|
+
expect(heap.hasObjectWithClassName('TestObject')).toBe(false);
|
|
41
|
+
}), 30000);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=example-6.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
const heap_analysis_1 = require("@memlab/heap-analysis");
|
|
23
|
+
(function () {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
26
|
+
const object = { 'memlab-test-heap-property': 'memlab-test-heap-value' };
|
|
27
|
+
const heapFile = (0, core_1.dumpNodeHeapSnapshot)();
|
|
28
|
+
const heap = yield (0, heap_analysis_1.getHeapFromFile)(heapFile);
|
|
29
|
+
// should be true
|
|
30
|
+
console.log(heap.hasObjectWithPropertyName('memlab-test-heap-property'));
|
|
31
|
+
});
|
|
32
|
+
})();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=example-7.test.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
test('memory test', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
+
core_1.config.muteConsole = true;
|
|
24
|
+
const o1 = {};
|
|
25
|
+
let o2 = {};
|
|
26
|
+
// tag o1 with marker: "memlab-mark-1"
|
|
27
|
+
(0, core_1.tagObject)(o1, 'memlab-mark-1');
|
|
28
|
+
// tag o2 with marker: "memlab-mark-2"
|
|
29
|
+
(0, core_1.tagObject)(o2, 'memlab-mark-2');
|
|
30
|
+
o2 = null;
|
|
31
|
+
const heap = yield (0, core_1.getNodeInnocentHeap)();
|
|
32
|
+
// expect object with marker "memlab-mark-1" exists
|
|
33
|
+
expect(heap.hasObjectWithTag('memlab-mark-1')).toBe(true);
|
|
34
|
+
// expect object with marker "memlab-mark-2" can be GCed
|
|
35
|
+
expect(heap.hasObjectWithTag('memlab-mark-2')).toBe(false);
|
|
36
|
+
}), 30000);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=heap-analysis.test.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const heap_analysis_1 = require("@memlab/heap-analysis");
|
|
22
|
+
const index_1 = require("../../index");
|
|
23
|
+
const E2ETestSettings_1 = require("../API/lib/E2ETestSettings");
|
|
24
|
+
const API_1 = require("../../API");
|
|
25
|
+
beforeEach(E2ETestSettings_1.testSetup);
|
|
26
|
+
function injectTestObject() {
|
|
27
|
+
class TestObject {
|
|
28
|
+
}
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
window.injectHookForLink4 = () => {
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
const arr = (window.__injectedValue = window.__injectedValue || []);
|
|
33
|
+
arr.push(new TestObject());
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const selfDefinedScenario = {
|
|
37
|
+
app: () => 'test-spa',
|
|
38
|
+
url: () => '',
|
|
39
|
+
action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
|
|
40
|
+
repeat: () => 3,
|
|
41
|
+
};
|
|
42
|
+
class ExampleAnalysis extends heap_analysis_1.BaseAnalysis {
|
|
43
|
+
constructor() {
|
|
44
|
+
super(...arguments);
|
|
45
|
+
this.isMonotonicIncreasing = false;
|
|
46
|
+
}
|
|
47
|
+
getCommandName() {
|
|
48
|
+
return 'example-analysis';
|
|
49
|
+
}
|
|
50
|
+
getDescription() {
|
|
51
|
+
return 'an example analysis for demo';
|
|
52
|
+
}
|
|
53
|
+
process(options) {
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
// check if the number of TestObject keeps growing overtime
|
|
56
|
+
this.isMonotonicIncreasing = yield (0, heap_analysis_1.snapshotMapReduce)(heap => {
|
|
57
|
+
let cnt = 0;
|
|
58
|
+
heap.nodes.forEach(node => {
|
|
59
|
+
if (node.name === 'TestObject' && node.type === 'object') {
|
|
60
|
+
++cnt;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return cnt;
|
|
64
|
+
}, nodeCounts => nodeCounts[0] === 0 &&
|
|
65
|
+
nodeCounts[nodeCounts.length - 1] === 4 &&
|
|
66
|
+
nodeCounts.every((count, i) => i === 0 || count >= nodeCounts[i - 1]), options);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
test('snapshotMapReduce works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
71
|
+
const results = yield (0, API_1.takeSnapshots)({
|
|
72
|
+
scenario: selfDefinedScenario,
|
|
73
|
+
evalInBrowserAfterInitLoad: injectTestObject,
|
|
74
|
+
snapshotForEachStep: true,
|
|
75
|
+
});
|
|
76
|
+
let analysis = new ExampleAnalysis();
|
|
77
|
+
yield (0, index_1.analyze)(results, analysis);
|
|
78
|
+
expect(analysis.isMonotonicIncreasing).toBe(true);
|
|
79
|
+
analysis = new ExampleAnalysis();
|
|
80
|
+
yield analysis.analyzeSnapshotsInDirectory(results.getSnapshotFileDir());
|
|
81
|
+
expect(analysis.isMonotonicIncreasing).toBe(true);
|
|
82
|
+
}), E2ETestSettings_1.testTimeout);
|