@memlab/api 1.0.23 → 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.
Files changed (46) hide show
  1. package/dist/API.d.ts +10 -5
  2. package/dist/API.d.ts.map +1 -0
  3. package/dist/API.js +6 -2
  4. package/dist/__tests__/API/E2EBasicAnalysis.test.d.ts.map +1 -0
  5. package/dist/__tests__/API/E2EDetachedDOMAnalysis.test.d.ts.map +1 -0
  6. package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.d.ts.map +1 -0
  7. package/dist/__tests__/API/E2EFindLeaks.example.d.ts.map +1 -0
  8. package/dist/__tests__/API/E2EFindMemoryLeaks.test.d.ts.map +1 -0
  9. package/dist/__tests__/API/E2EFindMemoryLeaksWithSnapshotFiles.test.d.ts.map +1 -0
  10. package/dist/__tests__/API/E2EInjectLeaksWithSetup.test.d.ts.map +1 -0
  11. package/dist/__tests__/API/E2EReloadInSetup.test.d.ts.map +1 -0
  12. package/dist/__tests__/API/E2EResultReader.test.d.ts.map +1 -0
  13. package/dist/__tests__/API/E2EResultReader.test.js +36 -0
  14. package/dist/__tests__/API/E2ERunMultipleSnapshots.example.d.ts.map +1 -0
  15. package/dist/__tests__/API/E2ERunSingleSnapshot.example.d.ts.map +1 -0
  16. package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.d.ts.map +1 -0
  17. package/dist/__tests__/API/E2EStringAnalysis.test.d.ts.map +1 -0
  18. package/dist/__tests__/API/{E2EFindWebWorkerLeaks.test.d.ts → E2ETestScenarioCallback.test.d.ts} +1 -1
  19. package/dist/__tests__/API/E2ETestScenarioCallback.test.d.ts.map +1 -0
  20. package/dist/__tests__/API/E2ETestScenarioCallback.test.js +135 -0
  21. package/dist/__tests__/API/lib/E2ETestSettings.d.ts.map +1 -0
  22. package/dist/__tests__/heap/E2EHeapParser.test.d.ts.map +1 -0
  23. package/dist/__tests__/heap/examples/example-1.d.ts.map +1 -0
  24. package/dist/__tests__/heap/examples/example-2.d.ts.map +1 -0
  25. package/dist/__tests__/heap/examples/example-3.d.ts.map +1 -0
  26. package/dist/__tests__/heap/examples/example-4.d.ts.map +1 -0
  27. package/dist/__tests__/heap/examples/example-5.test.d.ts.map +1 -0
  28. package/dist/__tests__/heap/examples/example-6.d.ts.map +1 -0
  29. package/dist/__tests__/heap/examples/example-7.test.d.ts.map +1 -0
  30. package/dist/__tests__/heap/lib/HeapParserTestUtils.d.ts.map +1 -0
  31. package/dist/__tests__/heap/lib/HeapParserTestUtils.js +1 -0
  32. package/dist/__tests__/packages/heap-analysis.test.d.ts.map +1 -0
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +3 -1
  36. package/dist/lib/APIUtils.d.ts.map +1 -0
  37. package/dist/lib/APIUtils.js +1 -0
  38. package/dist/result-reader/BaseResultReader.d.ts.map +1 -0
  39. package/dist/result-reader/BrowserInteractionResultReader.d.ts +1 -1
  40. package/dist/result-reader/BrowserInteractionResultReader.d.ts.map +1 -0
  41. package/dist/result-reader/BrowserInteractionResultReader.js +1 -1
  42. package/dist/result-reader/SnapshotResultReader.d.ts +115 -0
  43. package/dist/result-reader/SnapshotResultReader.d.ts.map +1 -0
  44. package/dist/result-reader/SnapshotResultReader.js +156 -0
  45. package/package.json +5 -4
  46. 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 declare type RunOptions = {
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 declare type RunResult = {
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 declare type APIOptions = {
78
+ export type APIOptions = {
74
79
  testPlanner?: TestPlanner;
75
80
  cache?: boolean;
76
81
  config?: MemLabConfig;
@@ -156,7 +161,7 @@ export declare function takeSnapshots(options?: RunOptions): Promise<BrowserInte
156
161
  * })();
157
162
  * ```
158
163
  */
159
- export declare function findLeaks(runResult: BrowserInteractionResultReader): Promise<ISerializedInfo[]>;
164
+ export declare function findLeaks(runResult: BaseResultReader): Promise<ISerializedInfo[]>;
160
165
  /**
161
166
  * This API finds memory leaks by analyzing specified heap snapshots.
162
167
  * This is equivalent to `memlab find-leaks` with
@@ -196,7 +201,7 @@ export declare function findLeaksBySnapshotFilePaths(baselineSnapshot: string, t
196
201
  * })();
197
202
  * ```
198
203
  */
199
- export declare function analyze(runResult: BrowserInteractionResultReader, heapAnalyzer: BaseAnalysis, args?: ParsedArgs): Promise<void>;
204
+ export declare function analyze(runResult: BaseResultReader, heapAnalyzer: BaseAnalysis, args?: ParsedArgs): Promise<void>;
200
205
  /**
201
206
  * This warms up web server by sending web requests to the web sever.
202
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
@@ -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
- yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
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
- yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
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);
@@ -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 @@
1
+ {"version":3,"file":"E2EFindMemoryLeaksWithSnapshotFiles.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EFindMemoryLeaksWithSnapshotFiles.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -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"}
@@ -8,4 +8,4 @@
8
8
  * @oncall web_perf_infra
9
9
  */
10
10
  export {};
11
- //# sourceMappingURL=E2EFindWebWorkerLeaks.test.d.ts.map
11
+ //# sourceMappingURL=E2ETestScenarioCallback.test.d.ts.map
@@ -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"}
@@ -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.23",
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": "^13.5.1",
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": "^27.5.1",
50
- "ts-jest": "^27.1.4",
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);