@memlab/api 1.0.22 → 1.0.24
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 +26 -6
- package/dist/API.d.ts.map +1 -0
- package/dist/API.js +50 -10
- package/dist/__tests__/API/E2EBasicAnalysis.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EDetachedDOMAnalysis.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EFindLeaks.example.d.ts.map +1 -0
- package/dist/__tests__/API/E2EFindMemoryLeaks.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EFindMemoryLeaksWithSnapshotFiles.test.d.ts +11 -0
- package/dist/__tests__/API/E2EFindMemoryLeaksWithSnapshotFiles.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EFindMemoryLeaksWithSnapshotFiles.test.js +100 -0
- package/dist/__tests__/API/E2EInjectLeaksWithSetup.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EReloadInSetup.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EResultReader.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EResultReader.test.js +36 -0
- package/dist/__tests__/API/E2ERunMultipleSnapshots.example.d.ts.map +1 -0
- package/dist/__tests__/API/E2ERunSingleSnapshot.example.d.ts.map +1 -0
- package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EStringAnalysis.test.d.ts.map +1 -0
- package/dist/__tests__/API/{E2EFindWebWorkerLeaks.test.d.ts → E2ETestScenarioCallback.test.d.ts} +1 -1
- package/dist/__tests__/API/E2ETestScenarioCallback.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2ETestScenarioCallback.test.js +135 -0
- package/dist/__tests__/API/lib/E2ETestSettings.d.ts.map +1 -0
- package/dist/__tests__/heap/E2EHeapParser.test.d.ts.map +1 -0
- package/dist/__tests__/heap/examples/example-1.d.ts.map +1 -0
- package/dist/__tests__/heap/examples/example-2.d.ts.map +1 -0
- package/dist/__tests__/heap/examples/example-3.d.ts.map +1 -0
- package/dist/__tests__/heap/examples/example-4.d.ts.map +1 -0
- package/dist/__tests__/heap/examples/example-5.test.d.ts.map +1 -0
- package/dist/__tests__/heap/examples/example-6.d.ts.map +1 -0
- package/dist/__tests__/heap/examples/example-7.test.d.ts.map +1 -0
- package/dist/__tests__/heap/lib/HeapParserTestUtils.d.ts.map +1 -0
- package/dist/__tests__/heap/lib/HeapParserTestUtils.js +1 -0
- package/dist/__tests__/packages/heap-analysis.test.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -1
- package/dist/lib/APIUtils.d.ts.map +1 -0
- package/dist/lib/APIUtils.js +1 -0
- package/dist/result-reader/BaseResultReader.d.ts.map +1 -0
- package/dist/result-reader/BrowserInteractionResultReader.d.ts +1 -1
- package/dist/result-reader/BrowserInteractionResultReader.d.ts.map +1 -0
- package/dist/result-reader/BrowserInteractionResultReader.js +1 -1
- package/dist/result-reader/SnapshotResultReader.d.ts +115 -0
- package/dist/result-reader/SnapshotResultReader.d.ts.map +1 -0
- package/dist/result-reader/SnapshotResultReader.js +156 -0
- package/package.json +5 -4
- package/dist/__tests__/API/E2EFindWebWorkerLeaks.test.js +0 -69
package/dist/API.d.ts
CHANGED
|
@@ -13,10 +13,11 @@ import { MemLabConfig } from '@memlab/core';
|
|
|
13
13
|
import { TestPlanner } from '@memlab/e2e';
|
|
14
14
|
import { BaseAnalysis } from '@memlab/heap-analysis';
|
|
15
15
|
import BrowserInteractionResultReader from './result-reader/BrowserInteractionResultReader';
|
|
16
|
+
import BaseResultReader from './result-reader/BaseResultReader';
|
|
16
17
|
/**
|
|
17
18
|
* Options for configuring browser interaction run, all fields are optional
|
|
18
19
|
*/
|
|
19
|
-
export
|
|
20
|
+
export type RunOptions = {
|
|
20
21
|
/**
|
|
21
22
|
* test scenario specifying how to interact with browser
|
|
22
23
|
* (for more details view {@link IScenario})
|
|
@@ -52,11 +53,15 @@ export declare type RunOptions = {
|
|
|
52
53
|
* means analyzing the heap of the web worker with name: `'workerTitle'`.
|
|
53
54
|
*/
|
|
54
55
|
webWorker?: Optional<string>;
|
|
56
|
+
/**
|
|
57
|
+
* skip warmup page load for the target web app
|
|
58
|
+
*/
|
|
59
|
+
skipWarmup?: boolean;
|
|
55
60
|
};
|
|
56
61
|
/**
|
|
57
62
|
* A data structure holding the result of the {@link run} API call.
|
|
58
63
|
*/
|
|
59
|
-
export
|
|
64
|
+
export type RunResult = {
|
|
60
65
|
/**
|
|
61
66
|
* leak traces detected and clustered from the browser interaction
|
|
62
67
|
*/
|
|
@@ -70,7 +75,7 @@ export declare type RunResult = {
|
|
|
70
75
|
* Options for memlab inter-package API calls
|
|
71
76
|
* @internal
|
|
72
77
|
*/
|
|
73
|
-
export
|
|
78
|
+
export type APIOptions = {
|
|
74
79
|
testPlanner?: TestPlanner;
|
|
75
80
|
cache?: boolean;
|
|
76
81
|
config?: MemLabConfig;
|
|
@@ -138,7 +143,7 @@ export declare function run(runOptions?: RunOptions): Promise<RunResult>;
|
|
|
138
143
|
*/
|
|
139
144
|
export declare function takeSnapshots(options?: RunOptions): Promise<BrowserInteractionResultReader>;
|
|
140
145
|
/**
|
|
141
|
-
* This API finds memory leaks by analyzing heap snapshot(s)
|
|
146
|
+
* This API finds memory leaks by analyzing heap snapshot(s).
|
|
142
147
|
* This is equivalent to `memlab find-leaks` in CLI.
|
|
143
148
|
*
|
|
144
149
|
* @param runResult return value of a browser interaction run
|
|
@@ -156,7 +161,22 @@ export declare function takeSnapshots(options?: RunOptions): Promise<BrowserInte
|
|
|
156
161
|
* })();
|
|
157
162
|
* ```
|
|
158
163
|
*/
|
|
159
|
-
export declare function findLeaks(runResult:
|
|
164
|
+
export declare function findLeaks(runResult: BaseResultReader): Promise<ISerializedInfo[]>;
|
|
165
|
+
/**
|
|
166
|
+
* This API finds memory leaks by analyzing specified heap snapshots.
|
|
167
|
+
* This is equivalent to `memlab find-leaks` with
|
|
168
|
+
* the `--baseline`, `--target`, and `--final` flags in CLI.
|
|
169
|
+
*
|
|
170
|
+
* @param baselineSnapshot the file path of the baseline heap snapshot
|
|
171
|
+
* @param targetSnapshot the file path of the target heap snapshot
|
|
172
|
+
* @param finalSnapshot the file path of the final heap snapshot
|
|
173
|
+
* @param options optionally, you can specify a working
|
|
174
|
+
* directory (other than the default one) for heap analysis
|
|
175
|
+
* @returns leak traces detected and clustered from the browser interaction
|
|
176
|
+
*/
|
|
177
|
+
export declare function findLeaksBySnapshotFilePaths(baselineSnapshot: string, targetSnapshot: string, finalSnapshot: string, options?: {
|
|
178
|
+
workDir?: string;
|
|
179
|
+
}): Promise<ISerializedInfo[]>;
|
|
160
180
|
/**
|
|
161
181
|
* This API analyzes heap snapshot(s) with a specified heap analysis.
|
|
162
182
|
* This is equivalent to `memlab analyze` in CLI.
|
|
@@ -181,7 +201,7 @@ export declare function findLeaks(runResult: BrowserInteractionResultReader): Pr
|
|
|
181
201
|
* })();
|
|
182
202
|
* ```
|
|
183
203
|
*/
|
|
184
|
-
export declare function analyze(runResult:
|
|
204
|
+
export declare function analyze(runResult: BaseResultReader, heapAnalyzer: BaseAnalysis, args?: ParsedArgs): Promise<void>;
|
|
185
205
|
/**
|
|
186
206
|
* This warms up web server by sending web requests to the web sever.
|
|
187
207
|
* This is equivalent to running `memlab warmup` in CLI.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"API.d.ts","sourceRoot":"","sources":["../src/API.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,SAAS,EAGT,QAAQ,EACT,MAAM,cAAc,CAAC;AAEtB,OAAO,EAML,YAAY,EAEb,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,WAAW,EAGZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAEnD,OAAO,8BAA8B,MAAM,gDAAgD,CAAC;AAC5F,OAAO,gBAAgB,MAAM,kCAAkC,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,0BAA0B,CAAC,EAAE,WAAW,CAAC;IACzC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB;;OAEG;IACH,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB;;OAEG;IACH,SAAS,EAAE,8BAA8B,CAAC;CAC3C,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IAGvB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,0BAA0B,CAAC,EAAE,WAAW,CAAC;CAC1C,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,8BAA8B,CAAC,CAWzC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,GAAG,CAAC,UAAU,GAAE,UAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAazE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,8BAA8B,CAAC,CAQzC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,gBAAgB,GAC1B,OAAO,CAAC,eAAe,EAAE,CAAC,CAK5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,4BAA4B,CAChD,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAM,GAC/B,OAAO,CAAC,eAAe,EAAE,CAAC,CAU5B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,OAAO,CAC3B,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EAAE,YAAY,EAC1B,IAAI,GAAE,UAAoB,GACzB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuCpE;AAmED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAsD3E"}
|
package/dist/API.js
CHANGED
|
@@ -21,7 +21,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
21
21
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
22
|
};
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.testInBrowser = exports.warmup = exports.analyze = exports.findLeaks = exports.takeSnapshots = exports.run = exports.warmupAndTakeSnapshots = void 0;
|
|
24
|
+
exports.testInBrowser = exports.warmup = exports.analyze = exports.findLeaksBySnapshotFilePaths = exports.findLeaks = exports.takeSnapshots = exports.run = exports.warmupAndTakeSnapshots = void 0;
|
|
25
25
|
const core_1 = require("@memlab/core");
|
|
26
26
|
const e2e_1 = require("@memlab/e2e");
|
|
27
27
|
const APIUtils_1 = __importDefault(require("./lib/APIUtils"));
|
|
@@ -52,7 +52,9 @@ function warmupAndTakeSnapshots(options = {}) {
|
|
|
52
52
|
config.scenario = options.scenario;
|
|
53
53
|
const testPlanner = new e2e_1.TestPlanner({ config });
|
|
54
54
|
const { evalInBrowserAfterInitLoad } = options;
|
|
55
|
-
|
|
55
|
+
if (!options.skipWarmup) {
|
|
56
|
+
yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
57
|
+
}
|
|
56
58
|
yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
57
59
|
return BrowserInteractionResultReader_1.default.from(config.workDir);
|
|
58
60
|
});
|
|
@@ -86,7 +88,9 @@ function run(runOptions = {}) {
|
|
|
86
88
|
config.scenario = runOptions.scenario;
|
|
87
89
|
const testPlanner = new e2e_1.TestPlanner({ config });
|
|
88
90
|
const { evalInBrowserAfterInitLoad } = runOptions;
|
|
89
|
-
|
|
91
|
+
if (!runOptions.skipWarmup) {
|
|
92
|
+
yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
93
|
+
}
|
|
90
94
|
yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
91
95
|
const runResult = BrowserInteractionResultReader_1.default.from(config.workDir);
|
|
92
96
|
const leaks = yield findLeaks(runResult);
|
|
@@ -125,7 +129,7 @@ function takeSnapshots(options = {}) {
|
|
|
125
129
|
}
|
|
126
130
|
exports.takeSnapshots = takeSnapshots;
|
|
127
131
|
/**
|
|
128
|
-
* This API finds memory leaks by analyzing heap snapshot(s)
|
|
132
|
+
* This API finds memory leaks by analyzing heap snapshot(s).
|
|
129
133
|
* This is equivalent to `memlab find-leaks` in CLI.
|
|
130
134
|
*
|
|
131
135
|
* @param runResult return value of a browser interaction run
|
|
@@ -152,6 +156,32 @@ function findLeaks(runResult) {
|
|
|
152
156
|
});
|
|
153
157
|
}
|
|
154
158
|
exports.findLeaks = findLeaks;
|
|
159
|
+
/**
|
|
160
|
+
* This API finds memory leaks by analyzing specified heap snapshots.
|
|
161
|
+
* This is equivalent to `memlab find-leaks` with
|
|
162
|
+
* the `--baseline`, `--target`, and `--final` flags in CLI.
|
|
163
|
+
*
|
|
164
|
+
* @param baselineSnapshot the file path of the baseline heap snapshot
|
|
165
|
+
* @param targetSnapshot the file path of the target heap snapshot
|
|
166
|
+
* @param finalSnapshot the file path of the final heap snapshot
|
|
167
|
+
* @param options optionally, you can specify a working
|
|
168
|
+
* directory (other than the default one) for heap analysis
|
|
169
|
+
* @returns leak traces detected and clustered from the browser interaction
|
|
170
|
+
*/
|
|
171
|
+
function findLeaksBySnapshotFilePaths(baselineSnapshot, targetSnapshot, finalSnapshot, options = {}) {
|
|
172
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
173
|
+
core_1.config.useExternalSnapshot = true;
|
|
174
|
+
core_1.config.externalSnapshotFilePaths = [
|
|
175
|
+
baselineSnapshot,
|
|
176
|
+
targetSnapshot,
|
|
177
|
+
finalSnapshot,
|
|
178
|
+
];
|
|
179
|
+
core_1.fileManager.initDirs(core_1.config, { workDir: options.workDir });
|
|
180
|
+
core_1.config.chaseWeakMapEdge = false;
|
|
181
|
+
return yield core_1.analysis.checkLeak();
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
exports.findLeaksBySnapshotFilePaths = findLeaksBySnapshotFilePaths;
|
|
155
185
|
/**
|
|
156
186
|
* This API analyzes heap snapshot(s) with a specified heap analysis.
|
|
157
187
|
* This is equivalent to `memlab analyze` in CLI.
|
|
@@ -309,30 +339,37 @@ function testInBrowser(options = {}) {
|
|
|
309
339
|
const testPlanner = (_b = options.testPlanner) !== null && _b !== void 0 ? _b : e2e_1.defaultTestPlanner;
|
|
310
340
|
let interactionManager = null;
|
|
311
341
|
let xvfb = null;
|
|
342
|
+
let browser = null;
|
|
343
|
+
let page = null;
|
|
344
|
+
let maybeError = null;
|
|
312
345
|
try {
|
|
313
346
|
xvfb = e2e_1.Xvfb.startIfEnabled();
|
|
314
|
-
|
|
347
|
+
browser = yield APIUtils_1.default.getBrowser();
|
|
315
348
|
const pages = yield browser.pages();
|
|
316
|
-
|
|
349
|
+
page = pages.length > 0 ? pages[0] : yield browser.newPage();
|
|
350
|
+
// create and configure web page interaction manager
|
|
317
351
|
interactionManager = new e2e_1.E2EInteractionManager(page, browser);
|
|
318
352
|
if (options.evalInBrowserAfterInitLoad) {
|
|
319
353
|
interactionManager.setEvalFuncAfterInitLoad(options.evalInBrowserAfterInitLoad);
|
|
320
354
|
}
|
|
321
355
|
const visitPlan = testPlanner.getVisitPlan();
|
|
356
|
+
// setup page configuration
|
|
322
357
|
config.setDevice(visitPlan.device);
|
|
323
358
|
autoDismissDialog(page);
|
|
324
359
|
yield initBrowserInfoInConfig(browser);
|
|
325
360
|
core_1.browserInfo.monitorWebConsole(page);
|
|
326
361
|
yield setupPage(page, options);
|
|
362
|
+
// interact with the web page and take heap snapshots
|
|
327
363
|
yield interactionManager.visitAndGetSnapshots(options);
|
|
328
|
-
yield core_1.utils.closePuppeteer(browser, [page]);
|
|
329
364
|
}
|
|
330
365
|
catch (ex) {
|
|
331
|
-
|
|
332
|
-
core_1.utils.checkUninstalledLibrary(
|
|
333
|
-
core_1.info.error(error.message);
|
|
366
|
+
maybeError = core_1.utils.getError(ex);
|
|
367
|
+
core_1.utils.checkUninstalledLibrary(maybeError);
|
|
334
368
|
}
|
|
335
369
|
finally {
|
|
370
|
+
if (browser && page) {
|
|
371
|
+
yield core_1.utils.closePuppeteer(browser, [page]);
|
|
372
|
+
}
|
|
336
373
|
if (interactionManager) {
|
|
337
374
|
interactionManager.clearCDPSession();
|
|
338
375
|
}
|
|
@@ -343,6 +380,9 @@ function testInBrowser(options = {}) {
|
|
|
343
380
|
}
|
|
344
381
|
});
|
|
345
382
|
}
|
|
383
|
+
if (maybeError != null) {
|
|
384
|
+
core_1.utils.haltOrThrow(maybeError);
|
|
385
|
+
}
|
|
346
386
|
}
|
|
347
387
|
});
|
|
348
388
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EBasicAnalysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EBasicAnalysis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EDetachedDOMAnalysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EDetachedDOMAnalysis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EDuplicateObjectAnalysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EDuplicateObjectAnalysis.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EFindLeaks.example.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EFindLeaks.example.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EFindMemoryLeaks.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EFindMemoryLeaks.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -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
|
+
* @format
|
|
8
|
+
* @oncall web_perf_infra
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=E2EFindMemoryLeaksWithSnapshotFiles.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EFindMemoryLeaksWithSnapshotFiles.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EFindMemoryLeaksWithSnapshotFiles.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,100 @@
|
|
|
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
|
+
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
|
+
const core_1 = require("@memlab/core");
|
|
25
|
+
const path_1 = __importDefault(require("path"));
|
|
26
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
27
|
+
const index_1 = require("../../index");
|
|
28
|
+
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
29
|
+
beforeEach(E2ETestSettings_1.testSetup);
|
|
30
|
+
function injectDetachedDOMElements() {
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
window.injectHookForLink4 = () => {
|
|
33
|
+
class TestObject {
|
|
34
|
+
}
|
|
35
|
+
const arr = [];
|
|
36
|
+
for (let i = 0; i < 23; ++i) {
|
|
37
|
+
arr.push(document.createElement('div'));
|
|
38
|
+
}
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
window.__injectedValue = arr;
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
window._path_1 = { x: { y: document.createElement('div') } };
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
window._path_2 = new Set([document.createElement('div')]);
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
window._randomObject = [new TestObject()];
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
test('leak detector can find detached DOM elements', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
|
+
const result = yield (0, index_1.takeSnapshots)({
|
|
51
|
+
scenario: E2ETestSettings_1.scenario,
|
|
52
|
+
evalInBrowserAfterInitLoad: injectDetachedDOMElements,
|
|
53
|
+
});
|
|
54
|
+
// copy heap snapshots to a different location
|
|
55
|
+
const snapshotFiles = result.getSnapshotFiles();
|
|
56
|
+
const tmpDir = core_1.fileManager.generateTmpHeapDir();
|
|
57
|
+
const newSnapshotFiles = [];
|
|
58
|
+
snapshotFiles.forEach(file => {
|
|
59
|
+
const newFile = path_1.default.join(tmpDir, path_1.default.basename(file));
|
|
60
|
+
newSnapshotFiles.push(newFile);
|
|
61
|
+
fs_extra_1.default.moveSync(file, newFile);
|
|
62
|
+
});
|
|
63
|
+
fs_extra_1.default.rmdirSync(result.getRootDirectory(), { recursive: true });
|
|
64
|
+
// find memory leaks with the new snapshot files
|
|
65
|
+
const leaks = yield (0, index_1.findLeaksBySnapshotFilePaths)(newSnapshotFiles[0], newSnapshotFiles[1], newSnapshotFiles[2]);
|
|
66
|
+
// detected all different leak trace cluster
|
|
67
|
+
expect(leaks.length >= 1).toBe(true);
|
|
68
|
+
// expect all traces are found
|
|
69
|
+
expect(leaks.some(leak => JSON.stringify(leak).includes('__injectedValue')));
|
|
70
|
+
expect(leaks.some(leak => JSON.stringify(leak).includes('_path_1')));
|
|
71
|
+
expect(leaks.some(leak => JSON.stringify(leak).includes('_path_2')));
|
|
72
|
+
// finally clean up the temporary directory
|
|
73
|
+
fs_extra_1.default.rmdirSync(tmpDir, { recursive: true });
|
|
74
|
+
}), E2ETestSettings_1.testTimeout);
|
|
75
|
+
test('takeSnapshot API allows to throw and catch exceptions from scenario', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
76
|
+
const scenarioThatThrows = Object.assign({}, E2ETestSettings_1.scenario);
|
|
77
|
+
const errorMessage = 'throw from scenario.action';
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
79
|
+
scenarioThatThrows.action = (_page) => __awaiter(void 0, void 0, void 0, function* () {
|
|
80
|
+
throw new Error(errorMessage);
|
|
81
|
+
});
|
|
82
|
+
expect.assertions(1);
|
|
83
|
+
yield expect((0, index_1.takeSnapshots)({
|
|
84
|
+
scenario: scenarioThatThrows,
|
|
85
|
+
evalInBrowserAfterInitLoad: injectDetachedDOMElements,
|
|
86
|
+
})).rejects.toThrow(errorMessage);
|
|
87
|
+
}), E2ETestSettings_1.testTimeout);
|
|
88
|
+
test('run API allows to throw and catch exceptions from scenario', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
89
|
+
const scenarioThatThrows = Object.assign({}, E2ETestSettings_1.scenario);
|
|
90
|
+
const errorMessage = 'throw from scenario.action';
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
92
|
+
scenarioThatThrows.action = (_page) => __awaiter(void 0, void 0, void 0, function* () {
|
|
93
|
+
throw new Error(errorMessage);
|
|
94
|
+
});
|
|
95
|
+
expect.assertions(1);
|
|
96
|
+
yield expect((0, index_1.run)({
|
|
97
|
+
scenario: scenarioThatThrows,
|
|
98
|
+
evalInBrowserAfterInitLoad: injectDetachedDOMElements,
|
|
99
|
+
})).rejects.toThrow(errorMessage);
|
|
100
|
+
}), E2ETestSettings_1.testTimeout);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EInjectLeaksWithSetup.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EInjectLeaksWithSetup.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EReloadInSetup.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EReloadInSetup.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EResultReader.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EResultReader.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -26,6 +26,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
26
26
|
const BrowserInteractionResultReader_1 = __importDefault(require("../../result-reader/BrowserInteractionResultReader"));
|
|
27
27
|
const index_1 = require("../../index");
|
|
28
28
|
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
29
|
+
const SnapshotResultReader_1 = __importDefault(require("../../result-reader/SnapshotResultReader"));
|
|
29
30
|
beforeEach(E2ETestSettings_1.testSetup);
|
|
30
31
|
function inject() {
|
|
31
32
|
// @ts-ignore
|
|
@@ -70,3 +71,38 @@ test('ResultReader.from is working as expected', () => __awaiter(void 0, void 0,
|
|
|
70
71
|
});
|
|
71
72
|
checkResultReader(BrowserInteractionResultReader_1.default.from(result.getRootDirectory()));
|
|
72
73
|
}), E2ETestSettings_1.testTimeout);
|
|
74
|
+
function injectDetachedDOMElements() {
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
window.injectHookForLink4 = () => {
|
|
77
|
+
class TestObject {
|
|
78
|
+
}
|
|
79
|
+
const arr = [];
|
|
80
|
+
for (let i = 0; i < 23; ++i) {
|
|
81
|
+
arr.push(document.createElement('div'));
|
|
82
|
+
}
|
|
83
|
+
// @ts-ignore
|
|
84
|
+
window.__injectedValue = arr;
|
|
85
|
+
// @ts-ignore
|
|
86
|
+
window._path_1 = { x: { y: document.createElement('div') } };
|
|
87
|
+
// @ts-ignore
|
|
88
|
+
window._path_2 = new Set([document.createElement('div')]);
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
window._randomObject = [new TestObject()];
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
test('SnapshotResultReader is working as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
94
|
+
const result = yield (0, index_1.warmupAndTakeSnapshots)({
|
|
95
|
+
scenario: E2ETestSettings_1.scenario,
|
|
96
|
+
evalInBrowserAfterInitLoad: injectDetachedDOMElements,
|
|
97
|
+
});
|
|
98
|
+
const snapshotFiles = result.getSnapshotFiles();
|
|
99
|
+
expect(snapshotFiles.length).toBe(3);
|
|
100
|
+
const reader = SnapshotResultReader_1.default.fromSnapshots(snapshotFiles[0], snapshotFiles[1], snapshotFiles[2]);
|
|
101
|
+
const leaks = yield (0, index_1.findLeaks)(reader);
|
|
102
|
+
// detected all different leak trace cluster
|
|
103
|
+
expect(leaks.length >= 1).toBe(true);
|
|
104
|
+
// expect all traces are found
|
|
105
|
+
expect(leaks.some(leak => JSON.stringify(leak).includes('__injectedValue')));
|
|
106
|
+
expect(leaks.some(leak => JSON.stringify(leak).includes('_path_1')));
|
|
107
|
+
expect(leaks.some(leak => JSON.stringify(leak).includes('_path_2')));
|
|
108
|
+
}), E2ETestSettings_1.testTimeout);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2ERunMultipleSnapshots.example.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2ERunMultipleSnapshots.example.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2ERunSingleSnapshot.example.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2ERunSingleSnapshot.example.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EShapeUnboundGrowthAnalysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EStringAnalysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EStringAnalysis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2ETestScenarioCallback.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2ETestScenarioCallback.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,135 @@
|
|
|
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
|
+
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 index_1 = require("../../index");
|
|
22
|
+
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
23
|
+
beforeEach(E2ETestSettings_1.testSetup);
|
|
24
|
+
function injectDetachedDOMElements() {
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
window.injectHookForLink4 = () => {
|
|
27
|
+
class TestObject {
|
|
28
|
+
}
|
|
29
|
+
const arr = [];
|
|
30
|
+
for (let i = 0; i < 23; ++i) {
|
|
31
|
+
arr.push(document.createElement('div'));
|
|
32
|
+
}
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
window.__injectedValue = arr;
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
window._path_1 = { x: { y: document.createElement('div') } };
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
window._path_2 = new Set([document.createElement('div')]);
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
window._randomObject = [new TestObject()];
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
test('callbacks in test scenarios are called in the right order', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
44
|
+
const actualCalls = [];
|
|
45
|
+
// define a test scenario with all callbacks offered by memlab
|
|
46
|
+
const selfDefinedScenario = {
|
|
47
|
+
app: () => {
|
|
48
|
+
actualCalls.push('app');
|
|
49
|
+
return 'test-spa';
|
|
50
|
+
},
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
52
|
+
beforeInitialPageLoad: (_page) => __awaiter(void 0, void 0, void 0, function* () {
|
|
53
|
+
actualCalls.push('beforeInitialPageLoad');
|
|
54
|
+
}),
|
|
55
|
+
cookies: () => {
|
|
56
|
+
actualCalls.push('cookies');
|
|
57
|
+
return [];
|
|
58
|
+
},
|
|
59
|
+
repeat: () => {
|
|
60
|
+
actualCalls.push('repeat');
|
|
61
|
+
return 0;
|
|
62
|
+
},
|
|
63
|
+
isPageLoaded: (page) => __awaiter(void 0, void 0, void 0, function* () {
|
|
64
|
+
actualCalls.push('isPageLoaded');
|
|
65
|
+
yield page.waitForNavigation({
|
|
66
|
+
// consider navigation to be finished when there are
|
|
67
|
+
// no more than 2 network connections for at least 500 ms.
|
|
68
|
+
waitUntil: 'networkidle2',
|
|
69
|
+
// Maximum navigation time in milliseconds
|
|
70
|
+
timeout: 5000,
|
|
71
|
+
});
|
|
72
|
+
return true;
|
|
73
|
+
}),
|
|
74
|
+
url: () => {
|
|
75
|
+
actualCalls.push('url');
|
|
76
|
+
return '';
|
|
77
|
+
},
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
79
|
+
setup: (_page) => __awaiter(void 0, void 0, void 0, function* () {
|
|
80
|
+
actualCalls.push('setup');
|
|
81
|
+
}),
|
|
82
|
+
action: (page) => __awaiter(void 0, void 0, void 0, function* () {
|
|
83
|
+
actualCalls.push('action');
|
|
84
|
+
yield page.click('[data-testid="link-4"]');
|
|
85
|
+
}),
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
87
|
+
back: (_page) => __awaiter(void 0, void 0, void 0, function* () {
|
|
88
|
+
actualCalls.push('back');
|
|
89
|
+
}),
|
|
90
|
+
beforeLeakFilter: (
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
92
|
+
_snapshot,
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
94
|
+
_leakedNodeIds) => {
|
|
95
|
+
actualCalls.push('beforeLeakFilter');
|
|
96
|
+
},
|
|
97
|
+
leakFilter: (node) => {
|
|
98
|
+
actualCalls.push('leakFilter');
|
|
99
|
+
return node.name === 'TestObject' && node.type === 'object';
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
// run test scenario
|
|
103
|
+
yield (0, index_1.run)({
|
|
104
|
+
scenario: selfDefinedScenario,
|
|
105
|
+
evalInBrowserAfterInitLoad: injectDetachedDOMElements,
|
|
106
|
+
skipWarmup: true,
|
|
107
|
+
});
|
|
108
|
+
// squash all leakFilter call into a single identifier
|
|
109
|
+
let normalizedCalls = squash(actualCalls, ['leakFilter', 'isPageLoaded']);
|
|
110
|
+
normalizedCalls = normalizedCalls.slice(normalizedCalls.lastIndexOf('url'));
|
|
111
|
+
// expect all callbacks are called in the right order
|
|
112
|
+
expect(normalizedCalls).toEqual([
|
|
113
|
+
// the first 4 calls (app, cookies, repeat, url) can be in any order
|
|
114
|
+
'url',
|
|
115
|
+
'repeat',
|
|
116
|
+
'app',
|
|
117
|
+
'cookies',
|
|
118
|
+
// the following calls must be in the exact order listed
|
|
119
|
+
'beforeInitialPageLoad',
|
|
120
|
+
'isPageLoaded',
|
|
121
|
+
'setup',
|
|
122
|
+
'action',
|
|
123
|
+
'isPageLoaded',
|
|
124
|
+
'back',
|
|
125
|
+
'isPageLoaded',
|
|
126
|
+
'beforeLeakFilter',
|
|
127
|
+
'leakFilter',
|
|
128
|
+
]);
|
|
129
|
+
}), E2ETestSettings_1.testTimeout);
|
|
130
|
+
// Squashes consecutive occurrences of a specified element in
|
|
131
|
+
// an array into a single occurrence of that element
|
|
132
|
+
function squash(arr, elementsToSquash) {
|
|
133
|
+
const squashSet = new Set(elementsToSquash);
|
|
134
|
+
return arr.filter((value, index) => !squashSet.has(value) || value !== arr[index - 1]);
|
|
135
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2ETestSettings.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/API/lib/E2ETestSettings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAGpC,eAAO,MAAM,WAAW,QAAgB,CAAC;AAEzC,eAAO,MAAM,mBAAmB;;;;CAAkB,CAAC;AAEnD,eAAO,MAAM,QAAQ;eACV,MAAM;eACN,MAAM;mBACM,IAAI,KAAG,QAAQ,IAAI,CAAC;CAE1C,CAAC;AAEF,eAAO,MAAM,SAAS,QAAO,IAK5B,CAAC;AAGF,wBAAgB,WAAW,IAAI,MAAM,CAEpC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EHeapParser.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/heap/E2EHeapParser.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAA2B,MAAM,cAAc,CAAC;AAKrE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,QAAQ,EAAE,QAAQ,CAAC;KACpB;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example-1.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/heap/examples/example-1.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example-2.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/heap/examples/example-2.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example-3.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/heap/examples/example-3.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example-4.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/heap/examples/example-4.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example-5.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/heap/examples/example-5.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example-6.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/heap/examples/example-6.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example-7.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/heap/examples/example-7.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeapParserTestUtils.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/heap/lib/HeapParserTestUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,cAAc,CAAC;AAUhD,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,IAAI,EACxB,eAAe,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,OAAO,GACpD,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
|
@@ -69,6 +69,7 @@ function saveSnapshotToFile(page, file) {
|
|
|
69
69
|
const TEST_URL = 'about:blank';
|
|
70
70
|
function dumpHeap(snapshotFile, leakInjector) {
|
|
71
71
|
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
core_1.utils.tryToMutePuppeteerWarning();
|
|
72
73
|
const browser = yield puppeteer.launch(core_1.config.puppeteerConfig);
|
|
73
74
|
const page = yield browser.newPage();
|
|
74
75
|
// set page size
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heap-analysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/packages/heap-analysis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare function registerPackage(): Promise<void>;
|
|
|
12
12
|
export * from './API';
|
|
13
13
|
export * from '@memlab/heap-analysis';
|
|
14
14
|
export { default as BrowserInteractionResultReader } from './result-reader/BrowserInteractionResultReader';
|
|
15
|
+
export { default as SnapshotResultReader } from './result-reader/SnapshotResultReader';
|
|
15
16
|
export { dumpNodeHeapSnapshot, getNodeInnocentHeap, takeNodeMinimalHeap, } from '@memlab/core';
|
|
16
17
|
/** @internal */
|
|
17
18
|
export { config } from '@memlab/core';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,gBAAgB;AAChB,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAErD;AAED,cAAc,OAAO,CAAC;AACtB,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAC,OAAO,IAAI,8BAA8B,EAAC,MAAM,gDAAgD,CAAC;AACzG,OAAO,EAAC,OAAO,IAAI,oBAAoB,EAAC,MAAM,sCAAsC,CAAC;AACrF,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,gBAAgB;AAChB,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -35,7 +35,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
35
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
36
|
};
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
exports.config = exports.takeNodeMinimalHeap = exports.getNodeInnocentHeap = exports.dumpNodeHeapSnapshot = exports.BrowserInteractionResultReader = exports.registerPackage = void 0;
|
|
38
|
+
exports.config = exports.takeNodeMinimalHeap = exports.getNodeInnocentHeap = exports.dumpNodeHeapSnapshot = exports.SnapshotResultReader = exports.BrowserInteractionResultReader = exports.registerPackage = void 0;
|
|
39
39
|
const path_1 = __importDefault(require("path"));
|
|
40
40
|
const core_1 = require("@memlab/core");
|
|
41
41
|
/** @internal */
|
|
@@ -49,6 +49,8 @@ __exportStar(require("./API"), exports);
|
|
|
49
49
|
__exportStar(require("@memlab/heap-analysis"), exports);
|
|
50
50
|
var BrowserInteractionResultReader_1 = require("./result-reader/BrowserInteractionResultReader");
|
|
51
51
|
Object.defineProperty(exports, "BrowserInteractionResultReader", { enumerable: true, get: function () { return __importDefault(BrowserInteractionResultReader_1).default; } });
|
|
52
|
+
var SnapshotResultReader_1 = require("./result-reader/SnapshotResultReader");
|
|
53
|
+
Object.defineProperty(exports, "SnapshotResultReader", { enumerable: true, get: function () { return __importDefault(SnapshotResultReader_1).default; } });
|
|
52
54
|
var core_2 = require("@memlab/core");
|
|
53
55
|
Object.defineProperty(exports, "dumpNodeHeapSnapshot", { enumerable: true, get: function () { return core_2.dumpNodeHeapSnapshot; } });
|
|
54
56
|
Object.defineProperty(exports, "getNodeInnocentHeap", { enumerable: true, get: function () { return core_2.getNodeInnocentHeap; } });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"APIUtils.d.ts","sourceRoot":"","sources":["../../src/lib/APIUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,cAAc,CAAC;AAU/C,iBAAe,UAAU,CACvB,OAAO,GAAE;IAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAM,GACtD,OAAO,CAAC,OAAO,CAAC,CAoBlB;;;;AAED,wBAEE"}
|
package/dist/lib/APIUtils.js
CHANGED
|
@@ -29,6 +29,7 @@ function getBrowser(options = {}) {
|
|
|
29
29
|
return __awaiter(this, void 0, void 0, function* () {
|
|
30
30
|
const runConfig = (_a = options.config) !== null && _a !== void 0 ? _a : core_1.config;
|
|
31
31
|
let browser;
|
|
32
|
+
core_1.utils.tryToMutePuppeteerWarning();
|
|
32
33
|
if (runConfig.isLocalPuppeteer && !options.warmup) {
|
|
33
34
|
try {
|
|
34
35
|
browser = yield puppeteer.connect(Object.assign({ browserURL: `http://localhost:${runConfig.localBrowserPort}` }, runConfig.puppeteerConfig));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseResultReader.d.ts","sourceRoot":"","sources":["../../src/result-reader/BaseResultReader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAQ,WAAW,EAAC,MAAM,cAAc,CAAC;AAGhD;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;IACnC,OAAO,CAAC,OAAO,CAAU;IAEzB;;;;OAIG;IACH,SAAS,aAAa,OAAO,SAAK;IASlC,SAAS,CAAC,KAAK,IAAI,IAAI;IAOvB;;;;OAIG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,SAAK,GAAG,gBAAgB;IAI3C;;;;;;;;;;;;;;;;;OAiBG;IACI,gBAAgB,IAAI,MAAM;IAKjC;;;;;;;;;;;;;;;OAeG;IACI,OAAO,IAAI,IAAI;CAOvB"}
|
|
@@ -12,7 +12,7 @@ import BaseResultReader from './BaseResultReader';
|
|
|
12
12
|
/**
|
|
13
13
|
* A utility entity to read all generated files from
|
|
14
14
|
* the directory holding the data and results from the
|
|
15
|
-
* last browser interaction run
|
|
15
|
+
* last MemLab browser interaction run
|
|
16
16
|
*/
|
|
17
17
|
export default class BrowserInteractionResultReader extends BaseResultReader {
|
|
18
18
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BrowserInteractionResultReader.d.ts","sourceRoot":"","sources":["../../src/result-reader/BrowserInteractionResultReader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAE,WAAW,EAAC,MAAM,cAAc,CAAC;AAK3D,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAElD;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,8BAA+B,SAAQ,gBAAgB;IAC1E;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,SAAK,GAAG,8BAA8B;IAIzD;;;;;;;;;;;;;;;OAeG;IACI,gBAAgB,IAAI,MAAM,EAAE;IASnC;;;;;;;;;;;;;;;OAeG;IACI,kBAAkB,IAAI,MAAM;IAKnC;;;;;;;;;;;;;;;;OAgBG;IACI,mBAAmB,IAAI,WAAW,EAAE;IAQ3C;;;;;;;;;;;;;;;;OAgBG;IACI,cAAc,IAAI,WAAW;CAMrC"}
|
|
@@ -19,7 +19,7 @@ const BaseResultReader_1 = __importDefault(require("./BaseResultReader"));
|
|
|
19
19
|
/**
|
|
20
20
|
* A utility entity to read all generated files from
|
|
21
21
|
* the directory holding the data and results from the
|
|
22
|
-
* last browser interaction run
|
|
22
|
+
* last MemLab browser interaction run
|
|
23
23
|
*/
|
|
24
24
|
class BrowserInteractionResultReader extends BaseResultReader_1.default {
|
|
25
25
|
/**
|
|
@@ -0,0 +1,115 @@
|
|
|
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
|
+
import { E2EStepInfo, RunMetaInfo } from '@memlab/core';
|
|
11
|
+
import BaseResultReader from './BaseResultReader';
|
|
12
|
+
/**
|
|
13
|
+
* A utility entity to read all MemLab files generated from
|
|
14
|
+
* baseline, target and final heap snapshots.
|
|
15
|
+
*
|
|
16
|
+
* The most useful feature of this class is when you have
|
|
17
|
+
* three separate snapshots (baseline, target, and final)
|
|
18
|
+
* that are not taken from MemLab, but you still would
|
|
19
|
+
* like to use the `findLeaks` to detect memory leaks:
|
|
20
|
+
*
|
|
21
|
+
* ```javascript
|
|
22
|
+
* const {SnapshotResultReader, findLeaks} = require('@memlab/api');
|
|
23
|
+
*
|
|
24
|
+
* // baseline, target, and final are file paths of heap snapshot files
|
|
25
|
+
* const reader = SnapshotResultReader.fromSnapshots(baseline, target, final);
|
|
26
|
+
* const leaks = await findLeaks(reader);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export default class SnapshotResultReader extends BaseResultReader {
|
|
30
|
+
private baselineSnapshot;
|
|
31
|
+
private targetSnapshot;
|
|
32
|
+
private finalSnapshot;
|
|
33
|
+
/**
|
|
34
|
+
* build a result reader
|
|
35
|
+
* @param workDir absolute path of the directory where the data
|
|
36
|
+
* and generated files of the memlab run were stored
|
|
37
|
+
*/
|
|
38
|
+
protected constructor(baselineSnapshot: string, targetSnapshot: string, finalSnapshot: string);
|
|
39
|
+
private createMetaFilesOnDisk;
|
|
40
|
+
private checkSnapshotFiles;
|
|
41
|
+
/**
|
|
42
|
+
* Build a result reader from baseline, target, and final heap snapshot files.
|
|
43
|
+
* The three snapshot files do not have to be in the same directory.
|
|
44
|
+
* @param baselineSnapshot file path of the baseline heap snapshot
|
|
45
|
+
* @param targetSnapshot file path of the target heap snapshot
|
|
46
|
+
* @param finalSnapshot file path of the final heap snapshot
|
|
47
|
+
* @returns the ResultReader instance
|
|
48
|
+
*
|
|
49
|
+
* * **Examples**:
|
|
50
|
+
* ```javascript
|
|
51
|
+
* const {SnapshotResultReader, findLeaks} = require('@memlab/api');
|
|
52
|
+
*
|
|
53
|
+
* // baseline, target, and final are file paths of heap snapshot files
|
|
54
|
+
* const reader = SnapshotResultReader.fromSnapshots(baseline, target, final);
|
|
55
|
+
* const leaks = await findLeaks(reader);
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
static fromSnapshots(baselineSnapshot: string, targetSnapshot: string, finalSnapshot: string): SnapshotResultReader;
|
|
59
|
+
/**
|
|
60
|
+
* @internal
|
|
61
|
+
*/
|
|
62
|
+
static from(workDir?: string): BaseResultReader;
|
|
63
|
+
/**
|
|
64
|
+
* get all snapshot files related to this SnapshotResultReader
|
|
65
|
+
* @returns an array of snapshot file's absolute path
|
|
66
|
+
*
|
|
67
|
+
* * **Examples**:
|
|
68
|
+
* ```javascript
|
|
69
|
+
* const {SnapshotResultReader} = require('@memlab/api');
|
|
70
|
+
*
|
|
71
|
+
* // baseline, target, and final are file paths of heap snapshot files
|
|
72
|
+
* const reader = SnapshotResultReader.fromSnapshots(baseline, target, final);
|
|
73
|
+
* const paths = reader.getSnapshotFiles();
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
getSnapshotFiles(): string[];
|
|
77
|
+
/**
|
|
78
|
+
* @internal
|
|
79
|
+
*/
|
|
80
|
+
getSnapshotFileDir(): string;
|
|
81
|
+
/**
|
|
82
|
+
* browser interaction step sequence
|
|
83
|
+
* @returns an array of browser interaction step information
|
|
84
|
+
*
|
|
85
|
+
* * **Examples**:
|
|
86
|
+
* ```javascript
|
|
87
|
+
* const {SnapshotResultReader} = require('@memlab/api');
|
|
88
|
+
*
|
|
89
|
+
* // baseline, target, and final are file paths of heap snapshot files
|
|
90
|
+
* const reader = SnapshotResultReader.fromSnapshots(baseline, target, final);
|
|
91
|
+
* const paths = reader.getInteractionSteps();
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
getInteractionSteps(): E2EStepInfo[];
|
|
95
|
+
/**
|
|
96
|
+
* @internal
|
|
97
|
+
* general meta data of the browser interaction run
|
|
98
|
+
* @returns meta data about the entire browser interaction
|
|
99
|
+
*
|
|
100
|
+
* * **Examples**:
|
|
101
|
+
* ```javascript
|
|
102
|
+
* const {SnapshotResultReader} = require('@memlab/api');
|
|
103
|
+
*
|
|
104
|
+
* // baseline, target, and final are file paths of heap snapshot files
|
|
105
|
+
* const reader = SnapshotResultReader.fromSnapshots(baseline, target, final);
|
|
106
|
+
* const metaInfo = reader.getRunMetaInfo();
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
getRunMetaInfo(): RunMetaInfo;
|
|
110
|
+
/**
|
|
111
|
+
* @internal
|
|
112
|
+
*/
|
|
113
|
+
cleanup(): void;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=SnapshotResultReader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SnapshotResultReader.d.ts","sourceRoot":"","sources":["../../src/result-reader/SnapshotResultReader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAS,WAAW,EAAE,WAAW,EAAC,MAAM,cAAc,CAAC;AAI9D,OAAO,gBAAgB,MAAM,oBAAoB,CAAC;AAElD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,gBAAgB;IAChE,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,aAAa,CAAS;IAE9B;;;;OAIG;IACH,SAAS,aACP,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM;IAavB,OAAO,CAAC,qBAAqB;IAU7B,OAAO,CAAC,kBAAkB;IAY1B;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,aAAa,CAClB,gBAAgB,EAAE,MAAM,EACxB,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,GACpB,oBAAoB;IAQvB;;OAEG;WACW,IAAI,CAAC,OAAO,SAAK,GAAG,gBAAgB;IAKlD;;;;;;;;;;;;OAYG;IACI,gBAAgB,IAAI,MAAM,EAAE;IAInC;;OAEG;IACI,kBAAkB,IAAI,MAAM;IAOnC;;;;;;;;;;;;OAYG;IACI,mBAAmB,IAAI,WAAW,EAAE;IAQ3C;;;;;;;;;;;;;OAaG;IACI,cAAc,IAAI,WAAW;IAIpC;;OAEG;IACI,OAAO,IAAI,IAAI;CAGvB"}
|
|
@@ -0,0 +1,156 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const core_1 = require("@memlab/core");
|
|
16
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
17
|
+
const core_2 = require("@memlab/core");
|
|
18
|
+
const BaseResultReader_1 = __importDefault(require("./BaseResultReader"));
|
|
19
|
+
/**
|
|
20
|
+
* A utility entity to read all MemLab files generated from
|
|
21
|
+
* baseline, target and final heap snapshots.
|
|
22
|
+
*
|
|
23
|
+
* The most useful feature of this class is when you have
|
|
24
|
+
* three separate snapshots (baseline, target, and final)
|
|
25
|
+
* that are not taken from MemLab, but you still would
|
|
26
|
+
* like to use the `findLeaks` to detect memory leaks:
|
|
27
|
+
*
|
|
28
|
+
* ```javascript
|
|
29
|
+
* const {SnapshotResultReader, findLeaks} = require('@memlab/api');
|
|
30
|
+
*
|
|
31
|
+
* // baseline, target, and final are file paths of heap snapshot files
|
|
32
|
+
* const reader = SnapshotResultReader.fromSnapshots(baseline, target, final);
|
|
33
|
+
* const leaks = await findLeaks(reader);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
class SnapshotResultReader extends BaseResultReader_1.default {
|
|
37
|
+
/**
|
|
38
|
+
* build a result reader
|
|
39
|
+
* @param workDir absolute path of the directory where the data
|
|
40
|
+
* and generated files of the memlab run were stored
|
|
41
|
+
*/
|
|
42
|
+
constructor(baselineSnapshot, targetSnapshot, finalSnapshot) {
|
|
43
|
+
const fileManager = new core_2.FileManager();
|
|
44
|
+
const workDir = fileManager.generateTmpHeapDir();
|
|
45
|
+
fs_extra_1.default.ensureDirSync(workDir);
|
|
46
|
+
super(workDir);
|
|
47
|
+
this.baselineSnapshot = baselineSnapshot;
|
|
48
|
+
this.targetSnapshot = targetSnapshot;
|
|
49
|
+
this.finalSnapshot = finalSnapshot;
|
|
50
|
+
this.checkSnapshotFiles();
|
|
51
|
+
this.createMetaFilesOnDisk(fileManager, workDir);
|
|
52
|
+
}
|
|
53
|
+
createMetaFilesOnDisk(fileManager, workDir) {
|
|
54
|
+
fileManager.initDirs(core_1.config, { workDir });
|
|
55
|
+
const visitOrder = this.getInteractionSteps();
|
|
56
|
+
const snapSeqFile = fileManager.getSnapshotSequenceMetaFile({ workDir });
|
|
57
|
+
fs_extra_1.default.writeFileSync(snapSeqFile, JSON.stringify(visitOrder, null, 2), 'UTF-8');
|
|
58
|
+
}
|
|
59
|
+
checkSnapshotFiles() {
|
|
60
|
+
if (!fs_extra_1.default.existsSync(this.baselineSnapshot) ||
|
|
61
|
+
!fs_extra_1.default.existsSync(this.targetSnapshot) ||
|
|
62
|
+
!fs_extra_1.default.existsSync(this.finalSnapshot)) {
|
|
63
|
+
throw core_2.utils.haltOrThrow('invalid file path of baseline, target, or final heap snapshots');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Build a result reader from baseline, target, and final heap snapshot files.
|
|
68
|
+
* The three snapshot files do not have to be in the same directory.
|
|
69
|
+
* @param baselineSnapshot file path of the baseline heap snapshot
|
|
70
|
+
* @param targetSnapshot file path of the target heap snapshot
|
|
71
|
+
* @param finalSnapshot file path of the final heap snapshot
|
|
72
|
+
* @returns the ResultReader instance
|
|
73
|
+
*
|
|
74
|
+
* * **Examples**:
|
|
75
|
+
* ```javascript
|
|
76
|
+
* const {SnapshotResultReader, findLeaks} = require('@memlab/api');
|
|
77
|
+
*
|
|
78
|
+
* // baseline, target, and final are file paths of heap snapshot files
|
|
79
|
+
* const reader = SnapshotResultReader.fromSnapshots(baseline, target, final);
|
|
80
|
+
* const leaks = await findLeaks(reader);
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
static fromSnapshots(baselineSnapshot, targetSnapshot, finalSnapshot) {
|
|
84
|
+
return new SnapshotResultReader(baselineSnapshot, targetSnapshot, finalSnapshot);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* @internal
|
|
88
|
+
*/
|
|
89
|
+
static from(workDir = '') {
|
|
90
|
+
throw core_2.utils.haltOrThrow('SnapshotResultReader.from is not supported');
|
|
91
|
+
return new BaseResultReader_1.default(workDir);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* get all snapshot files related to this SnapshotResultReader
|
|
95
|
+
* @returns an array of snapshot file's absolute path
|
|
96
|
+
*
|
|
97
|
+
* * **Examples**:
|
|
98
|
+
* ```javascript
|
|
99
|
+
* const {SnapshotResultReader} = require('@memlab/api');
|
|
100
|
+
*
|
|
101
|
+
* // baseline, target, and final are file paths of heap snapshot files
|
|
102
|
+
* const reader = SnapshotResultReader.fromSnapshots(baseline, target, final);
|
|
103
|
+
* const paths = reader.getSnapshotFiles();
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
getSnapshotFiles() {
|
|
107
|
+
return [this.baselineSnapshot, this.targetSnapshot, this.finalSnapshot];
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* @internal
|
|
111
|
+
*/
|
|
112
|
+
getSnapshotFileDir() {
|
|
113
|
+
throw core_2.utils.haltOrThrow('SnapshotResultReader getSnapshotFileDir() method is not supported');
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* browser interaction step sequence
|
|
118
|
+
* @returns an array of browser interaction step information
|
|
119
|
+
*
|
|
120
|
+
* * **Examples**:
|
|
121
|
+
* ```javascript
|
|
122
|
+
* const {SnapshotResultReader} = require('@memlab/api');
|
|
123
|
+
*
|
|
124
|
+
* // baseline, target, and final are file paths of heap snapshot files
|
|
125
|
+
* const reader = SnapshotResultReader.fromSnapshots(baseline, target, final);
|
|
126
|
+
* const paths = reader.getInteractionSteps();
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
getInteractionSteps() {
|
|
130
|
+
return this.fileManager.createVisitOrderWithSnapshots(this.baselineSnapshot, this.targetSnapshot, this.finalSnapshot);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* @internal
|
|
134
|
+
* general meta data of the browser interaction run
|
|
135
|
+
* @returns meta data about the entire browser interaction
|
|
136
|
+
*
|
|
137
|
+
* * **Examples**:
|
|
138
|
+
* ```javascript
|
|
139
|
+
* const {SnapshotResultReader} = require('@memlab/api');
|
|
140
|
+
*
|
|
141
|
+
* // baseline, target, and final are file paths of heap snapshot files
|
|
142
|
+
* const reader = SnapshotResultReader.fromSnapshots(baseline, target, final);
|
|
143
|
+
* const metaInfo = reader.getRunMetaInfo();
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
getRunMetaInfo() {
|
|
147
|
+
return new core_2.RunMetaInfoManager().loadRunMetaExternalTemplate();
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* @internal
|
|
151
|
+
*/
|
|
152
|
+
cleanup() {
|
|
153
|
+
// do nothing
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.default = SnapshotResultReader;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memlab/api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.24",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "memlab API",
|
|
6
6
|
"author": "Liang Gong <lgong@fb.com>",
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
"chalk": "^4.0.0",
|
|
36
36
|
"fs-extra": "^4.0.2",
|
|
37
37
|
"minimist": "^1.2.0",
|
|
38
|
-
"puppeteer": "^
|
|
38
|
+
"puppeteer": "^21.0.3",
|
|
39
|
+
"puppeteer-core": "^21.0.3",
|
|
39
40
|
"string-width": "^4.2.0",
|
|
40
41
|
"util.promisify": "^1.1.1",
|
|
41
42
|
"xvfb": "^0.4.0"
|
|
@@ -46,8 +47,8 @@
|
|
|
46
47
|
"@types/minimist": "^1.2.2",
|
|
47
48
|
"@types/node": "^12.16.3",
|
|
48
49
|
"@types/puppeteer": "^5.4.4",
|
|
49
|
-
"jest": "^
|
|
50
|
-
"ts-jest": "^
|
|
50
|
+
"jest": "^29.6.2",
|
|
51
|
+
"ts-jest": "^29.1.1",
|
|
51
52
|
"typescript": "^4.6.3"
|
|
52
53
|
},
|
|
53
54
|
"repository": {
|
|
@@ -1,69 +0,0 @@
|
|
|
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
|
-
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 index_1 = require("../../index");
|
|
22
|
-
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
23
|
-
beforeEach(E2ETestSettings_1.testSetup);
|
|
24
|
-
test('self-defined leak detector can find Web Worker TestObject (in initial load)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
-
const selfDefinedScenario = {
|
|
26
|
-
app: () => 'test-spa',
|
|
27
|
-
url: () => '',
|
|
28
|
-
leakFilter: (node) => {
|
|
29
|
-
return node.name === 'WorkerTestObject' && node.type === 'object';
|
|
30
|
-
},
|
|
31
|
-
};
|
|
32
|
-
const result = yield (0, index_1.run)({
|
|
33
|
-
scenario: selfDefinedScenario,
|
|
34
|
-
webWorker: null,
|
|
35
|
-
});
|
|
36
|
-
// detected all different leak trace cluster
|
|
37
|
-
expect(result.leaks.length).toBe(1);
|
|
38
|
-
}), E2ETestSettings_1.testTimeout);
|
|
39
|
-
test('self-defined leak detector can find Web Worker TestObject with specified worker name (in initial load)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
40
|
-
const selfDefinedScenario = {
|
|
41
|
-
app: () => 'test-spa',
|
|
42
|
-
url: () => '',
|
|
43
|
-
leakFilter: (node) => {
|
|
44
|
-
return node.name === 'WorkerTestObject' && node.type === 'object';
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
const result = yield (0, index_1.run)({
|
|
48
|
-
scenario: selfDefinedScenario,
|
|
49
|
-
webWorker: 'test-worker',
|
|
50
|
-
});
|
|
51
|
-
// detected all different leak trace cluster
|
|
52
|
-
expect(result.leaks.length).toBe(1);
|
|
53
|
-
}), E2ETestSettings_1.testTimeout);
|
|
54
|
-
test('self-defined leak detector can find Web Worker TestObject (during interaction)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
|
-
const selfDefinedScenario = {
|
|
56
|
-
app: () => 'test-spa',
|
|
57
|
-
url: () => '',
|
|
58
|
-
action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
|
|
59
|
-
leakFilter: (node) => {
|
|
60
|
-
return node.name === 'WorkerTestObject' && node.type === 'object';
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
const result = yield (0, index_1.run)({
|
|
64
|
-
scenario: selfDefinedScenario,
|
|
65
|
-
webWorker: null,
|
|
66
|
-
});
|
|
67
|
-
// detected all different leak trace cluster
|
|
68
|
-
expect(result.leaks.length).toBe(1);
|
|
69
|
-
}), E2ETestSettings_1.testTimeout);
|