@memlab/api 1.0.16 → 1.0.18
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 +4 -4
- package/dist/API.js +4 -4
- package/dist/__tests__/API/E2EDetachedDOMAnalysis.test.js +12 -1
- package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.d.ts +0 -9
- package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.js +51 -24
- package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.js +74 -23
- package/dist/__tests__/API/lib/E2ETestSettings.d.ts +1 -0
- package/dist/__tests__/API/lib/E2ETestSettings.js +6 -1
- package/package.json +2 -2
package/dist/API.d.ts
CHANGED
|
@@ -71,7 +71,7 @@ export declare type APIOptions = {
|
|
|
71
71
|
};
|
|
72
72
|
/**
|
|
73
73
|
* This API warms up web server, runs E2E interaction, and takes heap snapshots.
|
|
74
|
-
* This is equivalent to
|
|
74
|
+
* This is equivalent to running `memlab warmup-and-snapshot` in CLI.
|
|
75
75
|
* This is also equivalent to warm up and call {@link takeSnapshots}.
|
|
76
76
|
*
|
|
77
77
|
* @param options configure browser interaction run
|
|
@@ -91,7 +91,7 @@ export declare type APIOptions = {
|
|
|
91
91
|
export declare function warmupAndTakeSnapshots(options?: RunOptions): Promise<BrowserInteractionResultReader>;
|
|
92
92
|
/**
|
|
93
93
|
* This API runs browser interaction and find memory leaks triggered in browser
|
|
94
|
-
* This is equivalent to
|
|
94
|
+
* This is equivalent to running `memlab run` in CLI.
|
|
95
95
|
* This is also equivalent to warm up, and call {@link takeSnapshots}
|
|
96
96
|
* and {@link findLeaks}.
|
|
97
97
|
*
|
|
@@ -113,7 +113,7 @@ export declare function warmupAndTakeSnapshots(options?: RunOptions): Promise<Br
|
|
|
113
113
|
export declare function run(runOptions?: RunOptions): Promise<RunResult>;
|
|
114
114
|
/**
|
|
115
115
|
* This API runs E2E interaction and takes heap snapshots.
|
|
116
|
-
* This is equivalent to
|
|
116
|
+
* This is equivalent to running `memlab snapshot` in CLI.
|
|
117
117
|
*
|
|
118
118
|
* @param options configure browser interaction run
|
|
119
119
|
* @returns a utility reading browser interaction results from disk
|
|
@@ -177,7 +177,7 @@ export declare function findLeaks(runResult: BrowserInteractionResultReader): Pr
|
|
|
177
177
|
export declare function analyze(runResult: BrowserInteractionResultReader, heapAnalyzer: BaseAnalysis, args?: ParsedArgs): Promise<void>;
|
|
178
178
|
/**
|
|
179
179
|
* This warms up web server by sending web requests to the web sever.
|
|
180
|
-
* This is equivalent to
|
|
180
|
+
* This is equivalent to running `memlab warmup` in CLI.
|
|
181
181
|
* @internal
|
|
182
182
|
*
|
|
183
183
|
* @param options configure browser interaction run
|
package/dist/API.js
CHANGED
|
@@ -28,7 +28,7 @@ const APIUtils_1 = __importDefault(require("./lib/APIUtils"));
|
|
|
28
28
|
const BrowserInteractionResultReader_1 = __importDefault(require("./result-reader/BrowserInteractionResultReader"));
|
|
29
29
|
/**
|
|
30
30
|
* This API warms up web server, runs E2E interaction, and takes heap snapshots.
|
|
31
|
-
* This is equivalent to
|
|
31
|
+
* This is equivalent to running `memlab warmup-and-snapshot` in CLI.
|
|
32
32
|
* This is also equivalent to warm up and call {@link takeSnapshots}.
|
|
33
33
|
*
|
|
34
34
|
* @param options configure browser interaction run
|
|
@@ -60,7 +60,7 @@ function warmupAndTakeSnapshots(options = {}) {
|
|
|
60
60
|
exports.warmupAndTakeSnapshots = warmupAndTakeSnapshots;
|
|
61
61
|
/**
|
|
62
62
|
* This API runs browser interaction and find memory leaks triggered in browser
|
|
63
|
-
* This is equivalent to
|
|
63
|
+
* This is equivalent to running `memlab run` in CLI.
|
|
64
64
|
* This is also equivalent to warm up, and call {@link takeSnapshots}
|
|
65
65
|
* and {@link findLeaks}.
|
|
66
66
|
*
|
|
@@ -96,7 +96,7 @@ function run(runOptions = {}) {
|
|
|
96
96
|
exports.run = run;
|
|
97
97
|
/**
|
|
98
98
|
* This API runs E2E interaction and takes heap snapshots.
|
|
99
|
-
* This is equivalent to
|
|
99
|
+
* This is equivalent to running `memlab snapshot` in CLI.
|
|
100
100
|
*
|
|
101
101
|
* @param options configure browser interaction run
|
|
102
102
|
* @returns a utility reading browser interaction results from disk
|
|
@@ -186,7 +186,7 @@ function analyze(runResult, heapAnalyzer, args = { _: [] }) {
|
|
|
186
186
|
exports.analyze = analyze;
|
|
187
187
|
/**
|
|
188
188
|
* This warms up web server by sending web requests to the web sever.
|
|
189
|
-
* This is equivalent to
|
|
189
|
+
* This is equivalent to running `memlab warmup` in CLI.
|
|
190
190
|
* @internal
|
|
191
191
|
*
|
|
192
192
|
* @param options configure browser interaction run
|
|
@@ -17,8 +17,12 @@ 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
|
+
};
|
|
20
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
24
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
25
|
+
const fs_1 = __importDefault(require("fs"));
|
|
22
26
|
const index_1 = require("../../index");
|
|
23
27
|
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
24
28
|
beforeEach(E2ETestSettings_1.testSetup);
|
|
@@ -42,7 +46,14 @@ test('Detached DOM analysis works as expected', () => __awaiter(void 0, void 0,
|
|
|
42
46
|
// test analysis from file
|
|
43
47
|
const snapshotFile = result.getSnapshotFiles().pop();
|
|
44
48
|
analysis = new index_1.DetachedDOMElementAnalysis();
|
|
45
|
-
yield analysis.analyzeSnapshotFromFile(snapshotFile);
|
|
49
|
+
const ret = yield analysis.analyzeSnapshotFromFile(snapshotFile);
|
|
50
|
+
// expect the heap analysis output log file to exist and
|
|
51
|
+
// to contain the expected results
|
|
52
|
+
expect(fs_1.default.existsSync(ret.analysisOutputFile)).toBe(true);
|
|
53
|
+
expect(fs_1.default
|
|
54
|
+
.readFileSync(ret.analysisOutputFile, 'UTF-8')
|
|
55
|
+
.includes('Detached HTMLTableElement')).toBe(true);
|
|
56
|
+
// check if the query result API works as expected
|
|
46
57
|
domElems = analysis.getDetachedElements();
|
|
47
58
|
expect(domElems.some(node => node.name === 'Detached HTMLTableElement')).toBe(true);
|
|
48
59
|
}), E2ETestSettings_1.testTimeout);
|
|
@@ -1,11 +1,2 @@
|
|
|
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
|
-
* @format
|
|
8
|
-
* @oncall web_perf_infra
|
|
9
|
-
*/
|
|
10
1
|
export {};
|
|
11
2
|
//# sourceMappingURL=E2EDuplicateObjectAnalysis.test.d.ts.map
|
|
@@ -1,13 +1,4 @@
|
|
|
1
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
|
-
* @format
|
|
9
|
-
* @oncall web_perf_infra
|
|
10
|
-
*/
|
|
11
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -17,7 +8,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
17
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
9
|
});
|
|
19
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
20
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const fs_1 = __importDefault(require("fs"));
|
|
16
|
+
const path_1 = __importDefault(require("path"));
|
|
21
17
|
const index_1 = require("../../index");
|
|
22
18
|
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
23
19
|
beforeEach(E2ETestSettings_1.testSetup);
|
|
@@ -34,20 +30,51 @@ function inject() {
|
|
|
34
30
|
window.__injectedValue = arr;
|
|
35
31
|
};
|
|
36
32
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
function gatherSnapshots() {
|
|
34
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
const result = yield (0, index_1.warmupAndTakeSnapshots)({
|
|
36
|
+
scenario: E2ETestSettings_1.scenario,
|
|
37
|
+
evalInBrowserAfterInitLoad: inject,
|
|
38
|
+
});
|
|
39
|
+
return result;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function testAnalysisFromAutoLoading() {
|
|
43
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
// test analysis from auto loading
|
|
45
|
+
const analysis = new index_1.ObjectShallowAnalysis();
|
|
46
|
+
yield analysis.run();
|
|
47
|
+
const dupcatedObjectInfo = analysis.getTopDuplicatedObjectInCount();
|
|
48
|
+
expect(dupcatedObjectInfo[0].n).toBe(12345);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function testAnalysisFromFileDir(result) {
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
// test analysis from file
|
|
54
|
+
const snapshotFile = result.getSnapshotFiles().pop();
|
|
55
|
+
const analysis = new index_1.ObjectShallowAnalysis();
|
|
56
|
+
yield analysis.analyzeSnapshotFromFile(snapshotFile);
|
|
57
|
+
const dupcatedObjectInfo = analysis.getTopDuplicatedObjectInCount();
|
|
58
|
+
expect(dupcatedObjectInfo[0].n).toBe(12345);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function testAnalysisWithSpecifiedWorkDir(result) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
const snapshotFile = result.getSnapshotFiles().pop();
|
|
64
|
+
const analysis = new index_1.ObjectShallowAnalysis();
|
|
65
|
+
const workDir = `/tmp/memlab-test/${(0, E2ETestSettings_1.getUniqueID)()}`;
|
|
66
|
+
const ret = yield analysis.analyzeSnapshotFromFile(snapshotFile, { workDir });
|
|
67
|
+
// expect the heap analysis output log file to exist and
|
|
68
|
+
expect(fs_1.default.existsSync(ret.analysisOutputFile)).toBe(true);
|
|
69
|
+
// output file is inside the working directory
|
|
70
|
+
expect(path_1.default.resolve(ret.analysisOutputFile).includes(path_1.default.resolve(workDir))).toBe(true);
|
|
71
|
+
const dupcatedObjectInfo = analysis.getTopDuplicatedObjectInCount();
|
|
72
|
+
expect(dupcatedObjectInfo[0].n).toBe(12345);
|
|
41
73
|
});
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
yield
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const snapshotFile = result.getSnapshotFiles().pop();
|
|
49
|
-
analysis = new index_1.ObjectShallowAnalysis();
|
|
50
|
-
yield analysis.analyzeSnapshotFromFile(snapshotFile);
|
|
51
|
-
dupcatedObjectInfo = analysis.getTopDuplicatedObjectInCount();
|
|
52
|
-
expect(dupcatedObjectInfo[0].n).toBe(12345);
|
|
74
|
+
}
|
|
75
|
+
test('Duplicate object analysis works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
76
|
+
const result = yield gatherSnapshots();
|
|
77
|
+
yield testAnalysisFromAutoLoading();
|
|
78
|
+
yield testAnalysisFromFileDir(result);
|
|
79
|
+
yield testAnalysisWithSpecifiedWorkDir(result);
|
|
53
80
|
}), E2ETestSettings_1.testTimeout);
|
|
@@ -17,8 +17,12 @@ 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
|
+
};
|
|
20
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
|
|
24
|
+
const fs_1 = __importDefault(require("fs"));
|
|
25
|
+
const path_1 = __importDefault(require("path"));
|
|
22
26
|
const index_1 = require("../../index");
|
|
23
27
|
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
24
28
|
beforeEach(E2ETestSettings_1.testSetup);
|
|
@@ -37,27 +41,74 @@ function inject() {
|
|
|
37
41
|
}
|
|
38
42
|
};
|
|
39
43
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
function gatherSnapshots() {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
const repeatScenario = Object.assign({ repeat: () => 2 }, E2ETestSettings_1.scenario);
|
|
47
|
+
// test analysis from auto loading
|
|
48
|
+
const result = yield (0, index_1.warmupAndTakeSnapshots)({
|
|
49
|
+
scenario: repeatScenario,
|
|
50
|
+
evalInBrowserAfterInitLoad: inject,
|
|
51
|
+
snapshotForEachStep: true,
|
|
52
|
+
});
|
|
53
|
+
return result;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function testAnalysisFromAutoLoading() {
|
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
// test analysis from auto loading
|
|
59
|
+
const analysis = new index_1.ShapeUnboundGrowthAnalysis();
|
|
60
|
+
yield analysis.run();
|
|
61
|
+
const shapeSummary = analysis.getShapesWithUnboundGrowth();
|
|
62
|
+
expect(shapeSummary.reduce((acc, summary) => acc || summary.shape.includes('LeakObject'), false)).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function testAnalysisFromFileDir(result) {
|
|
66
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
67
|
+
// test analysis from file
|
|
68
|
+
const snapshotDir = result.getSnapshotFileDir();
|
|
69
|
+
const analysis = new index_1.ShapeUnboundGrowthAnalysis();
|
|
70
|
+
const ret = yield analysis.analyzeSnapshotsInDirectory(snapshotDir);
|
|
71
|
+
// expect the heap analysis output log file to exist and
|
|
72
|
+
// to contain the expected results
|
|
73
|
+
expect(fs_1.default.existsSync(ret.analysisOutputFile)).toBe(true);
|
|
74
|
+
expect(fs_1.default.readFileSync(ret.analysisOutputFile, 'UTF-8').includes('LeakObject')).toBe(true);
|
|
75
|
+
// expect the query API works
|
|
76
|
+
const shapeSummary = analysis.getShapesWithUnboundGrowth();
|
|
77
|
+
expect(shapeSummary.some((summary) => summary.shape.includes('LeakObject'))).toBe(true);
|
|
47
78
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
}
|
|
80
|
+
function testIncorrectUseage(result) {
|
|
81
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
// expect incorrect use of heap analysis to throw
|
|
83
|
+
const snapshotFile = result.getSnapshotFiles().pop();
|
|
84
|
+
const analysis = new index_1.ShapeUnboundGrowthAnalysis();
|
|
85
|
+
expect(() => __awaiter(this, void 0, void 0, function* () { return yield analysis.analyzeSnapshotFromFile(snapshotFile); })).rejects.toThrowError();
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function testAnalysisWithSpecifiedWorkDir(result) {
|
|
89
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
90
|
+
// test analysis from file
|
|
91
|
+
const snapshotDir = result.getSnapshotFileDir();
|
|
92
|
+
const analysis = new index_1.ShapeUnboundGrowthAnalysis();
|
|
93
|
+
const workDir = `/tmp/memlab-test/${(0, E2ETestSettings_1.getUniqueID)()}`;
|
|
94
|
+
const ret = yield analysis.analyzeSnapshotsInDirectory(snapshotDir, {
|
|
95
|
+
workDir,
|
|
96
|
+
});
|
|
97
|
+
// expect the heap analysis output log file to exist and
|
|
98
|
+
expect(fs_1.default.existsSync(ret.analysisOutputFile)).toBe(true);
|
|
99
|
+
// output file is inside the working directory
|
|
100
|
+
expect(path_1.default.resolve(ret.analysisOutputFile).includes(path_1.default.resolve(workDir))).toBe(true);
|
|
101
|
+
// output file contains the expected result
|
|
102
|
+
expect(fs_1.default.readFileSync(ret.analysisOutputFile, 'UTF-8').includes('LeakObject')).toBe(true);
|
|
103
|
+
// expect the query API works
|
|
104
|
+
const shapeSummary = analysis.getShapesWithUnboundGrowth();
|
|
105
|
+
expect(shapeSummary.some((summary) => summary.shape.includes('LeakObject'))).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
test('Shape unbound analysis works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
109
|
+
const result = yield gatherSnapshots();
|
|
110
|
+
yield testAnalysisFromAutoLoading();
|
|
111
|
+
yield testAnalysisFromFileDir(result);
|
|
112
|
+
yield testIncorrectUseage(result);
|
|
113
|
+
yield testAnalysisWithSpecifiedWorkDir(result);
|
|
63
114
|
}), E2ETestSettings_1.testTimeout);
|
|
@@ -18,7 +18,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
18
18
|
});
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.testSetup = exports.scenario = exports.defaultAnalysisArgs = exports.testTimeout = void 0;
|
|
21
|
+
exports.getUniqueID = exports.testSetup = exports.scenario = exports.defaultAnalysisArgs = exports.testTimeout = void 0;
|
|
22
22
|
const core_1 = require("@memlab/core");
|
|
23
23
|
exports.testTimeout = 5 * 60 * 1000;
|
|
24
24
|
exports.defaultAnalysisArgs = { args: { _: [] } };
|
|
@@ -34,3 +34,8 @@ const testSetup = () => {
|
|
|
34
34
|
core_1.config.errorHandling = core_1.ErrorHandling.Throw;
|
|
35
35
|
};
|
|
36
36
|
exports.testSetup = testSetup;
|
|
37
|
+
let uindex = 1;
|
|
38
|
+
function getUniqueID() {
|
|
39
|
+
return `${process.pid}-${Date.now()}-${uindex++}`;
|
|
40
|
+
}
|
|
41
|
+
exports.getUniqueID = getUniqueID;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memlab/api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "memlab API",
|
|
6
6
|
"author": "Liang Gong <lgong@fb.com>",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build-pkg": "tsc",
|
|
60
60
|
"test-pkg": "jest .",
|
|
61
|
-
"publish-patch": "npm
|
|
61
|
+
"publish-patch": "npm publish",
|
|
62
62
|
"clean-pkg": "rm -rf ./dist && rm -rf ./node_modules && rm -f ./tsconfig.tsbuildinfo"
|
|
63
63
|
},
|
|
64
64
|
"bugs": {
|