@memlab/api 1.0.0 → 1.0.3

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 (36) hide show
  1. package/README.md +5 -9
  2. package/dist/API.d.ts +139 -18
  3. package/dist/API.js +146 -17
  4. package/dist/__tests__/API/E2EDetachedDOMAnalysis.test.js +5 -6
  5. package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.js +5 -6
  6. package/dist/__tests__/API/E2EFindLeaks.example.d.ts +11 -0
  7. package/dist/__tests__/API/E2EFindLeaks.example.js +50 -0
  8. package/dist/__tests__/API/E2EFindMemoryLeaks.test.d.ts +11 -0
  9. package/dist/__tests__/API/E2EFindMemoryLeaks.test.js +72 -0
  10. package/dist/__tests__/API/E2EResultReader.test.d.ts +11 -0
  11. package/dist/__tests__/API/E2EResultReader.test.js +72 -0
  12. package/dist/__tests__/API/E2ERunSingleSnapshot.example.js +11 -12
  13. package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.js +8 -17
  14. package/dist/__tests__/API/E2EStringAnalysis.test.js +19 -15
  15. package/dist/__tests__/packages/heap-analysis.test.d.ts +11 -0
  16. package/dist/__tests__/packages/heap-analysis.test.js +82 -0
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.js +11 -2
  19. package/dist/result-reader/BaseResultReader.d.ts +70 -0
  20. package/dist/result-reader/BaseResultReader.js +96 -0
  21. package/dist/result-reader/BrowserInteractionResultReader.d.ts +105 -0
  22. package/dist/result-reader/BrowserInteractionResultReader.js +136 -0
  23. package/package.json +15 -6
  24. package/dist/API.d.ts.map +0 -1
  25. package/dist/__tests__/API/E2EBasicAnalysis.test.d.ts.map +0 -1
  26. package/dist/__tests__/API/E2EDetachedDOMAnalysis.test.d.ts.map +0 -1
  27. package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.d.ts.map +0 -1
  28. package/dist/__tests__/API/E2ERunMultipleSnapshots.example.d.ts.map +0 -1
  29. package/dist/__tests__/API/E2ERunSingleSnapshot.example.d.ts.map +0 -1
  30. package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.d.ts.map +0 -1
  31. package/dist/__tests__/API/E2EStringAnalysis.test.d.ts.map +0 -1
  32. package/dist/__tests__/API/lib/E2ETestSettings.d.ts.map +0 -1
  33. package/dist/__tests__/heap/E2EHeapParser.test.d.ts.map +0 -1
  34. package/dist/__tests__/heap/lib/HeapParserTestUtils.d.ts.map +0 -1
  35. package/dist/index.d.ts.map +0 -1
  36. package/dist/lib/APIUtils.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,11 +1,7 @@
1
- # `@memlab/api`
1
+ ## memlab API
2
2
 
3
- > TODO: description
3
+ This is the memlab API library. Add this dependency to your project
4
+ if you want to integrate memlab with your continuous testing system.
4
5
 
5
- ## Usage
6
-
7
- ```
8
- const api = require('@memlab/api');
9
-
10
- // TODO: DEMONSTRATE API
11
- ```
6
+ ## Full documentation
7
+ https://facebookincubator.github.io/memlab
package/dist/API.d.ts CHANGED
@@ -7,34 +7,155 @@
7
7
  * @emails oncall+ws_labs
8
8
  * @format
9
9
  */
10
- import type { Page } from 'puppeteer';
11
10
  import type { ParsedArgs } from 'minimist';
12
- import type { AnyFunction, E2EStepInfo, IScenario, RunMetaInfo } from '@memlab/core';
11
+ import type { AnyFunction, ISerializedInfo, IScenario } from '@memlab/core';
13
12
  import { MemLabConfig } from '@memlab/core';
14
13
  import { TestPlanner } from '@memlab/e2e';
15
14
  import { BaseAnalysis } from '@memlab/heap-analysis';
16
- declare type APIOptions = {
17
- testPlanner?: TestPlanner;
18
- cache?: boolean;
19
- config?: MemLabConfig;
20
- evalInBrowserAfterInitLoad?: AnyFunction;
21
- };
22
- declare type RunOptions = {
15
+ import BrowserInteractionResultReader from './result-reader/BrowserInteractionResultReader';
16
+ /**
17
+ * Options for configuring browser interaction run, all fields are optional
18
+ */
19
+ export declare type RunOptions = {
20
+ /** test scenario definition */
23
21
  scenario?: IScenario;
22
+ /** the absolute path of cookies file */
24
23
  cookiesFile?: string;
24
+ /** function to be evaluated in browser context after the web page initial load */
25
25
  evalInBrowserAfterInitLoad?: AnyFunction;
26
+ /**
27
+ * if true, take heap snapshot for each interaction step,
28
+ * by default this is false, which means memlab will decide
29
+ * which steps it will take heap snapshots
30
+ */
26
31
  snapshotForEachStep?: boolean;
27
32
  };
28
- declare type RunResult = {
29
- config: MemLabConfig;
30
- tabsOrder: E2EStepInfo[];
31
- metaInfo: RunMetaInfo;
33
+ /**
34
+ * Options for memlab inter-package API calls
35
+ * @internal
36
+ */
37
+ export declare type APIOptions = {
38
+ testPlanner?: TestPlanner;
39
+ cache?: boolean;
40
+ config?: MemLabConfig;
41
+ evalInBrowserAfterInitLoad?: AnyFunction;
32
42
  };
33
- export declare function run(options?: RunOptions): Promise<RunResult>;
34
- export declare function takeSnapshots(options?: RunOptions): Promise<RunResult>;
35
- export declare function analyze(runResult: RunResult, heapAnalyzer: BaseAnalysis, args?: ParsedArgs): Promise<void>;
43
+ /**
44
+ * This API warms up web server, runs E2E interaction, and takes heap snapshots.
45
+ * This is equivalent to run `memlab warmup-and-snapshot` in CLI.
46
+ * This is also equivalent to warm up and call {@link takeSnapshots}.
47
+ *
48
+ * @param options configure browser interaction run
49
+ * @returns browser interaction results
50
+ * * **Examples**:
51
+ * ```javascript
52
+ * const {warmupAndTakeSnapshots} = require('@memlab/api');
53
+ *
54
+ * (async function () {
55
+ * const scenario = {
56
+ * url: () => 'https://www.facebook.com',
57
+ * };
58
+ * const result = await warmupAndTakeSnapshots({scenario});
59
+ * })();
60
+ * ```
61
+ */
62
+ export declare function warmupAndTakeSnapshots(options?: RunOptions): Promise<BrowserInteractionResultReader>;
63
+ /**
64
+ * This API runs browser interaction and find memory leaks triggered in browser
65
+ * This is equivalent to run `memlab run` in CLI.
66
+ * This is also equivalent to warm up, and call {@link takeSnapshots}
67
+ * and {@link findLeaks}.
68
+ *
69
+ * @param runOptions configure browser interaction run
70
+ * @returns leak traces detected and clustered from the browser interaction
71
+ * * **Examples**:
72
+ * ```javascript
73
+ * const {run} = require('@memlab/api');
74
+ *
75
+ * (async function () {
76
+ * const scenario = {
77
+ * url: () => 'https://www.facebook.com',
78
+ * };
79
+ * const leaks = await run({scenario});
80
+ * })();
81
+ * ```
82
+ */
83
+ export declare function run(runOptions?: RunOptions): Promise<ISerializedInfo[]>;
84
+ /**
85
+ * This API runs E2E interaction and takes heap snapshots.
86
+ * This is equivalent to run `memlab snapshot` in CLI.
87
+ *
88
+ * @param options configure browser interaction run
89
+ * @returns browser interaction results
90
+ * * **Examples**:
91
+ * ```javascript
92
+ * const {takeSnapshots} = require('@memlab/api');
93
+ *
94
+ * (async function () {
95
+ * const scenario = {
96
+ * url: () => 'https://www.facebook.com',
97
+ * };
98
+ * const result = await takeSnapshots({scenario});
99
+ * })();
100
+ * ```
101
+ */
102
+ export declare function takeSnapshots(options?: RunOptions): Promise<BrowserInteractionResultReader>;
103
+ /**
104
+ * This API finds memory leaks by analyzing heap snapshot(s)
105
+ * This is equivalent to `memlab find-leaks` in CLI.
106
+ *
107
+ * @param runResult return value of a browser interaction run
108
+ * @returns leak traces detected and clustered from the browser interaction
109
+ * * **Examples**:
110
+ * ```javascript
111
+ * const {findLeaks, takeSnapshots} = require('@memlab/api');
112
+ *
113
+ * (async function () {
114
+ * const scenario = {
115
+ * url: () => 'https://www.facebook.com',
116
+ * };
117
+ * const result = await takeSnapshots({scenario});
118
+ * const leaks = findLeaks(result);
119
+ * })();
120
+ * ```
121
+ */
122
+ export declare function findLeaks(runResult: BrowserInteractionResultReader): Promise<ISerializedInfo[]>;
123
+ /**
124
+ * This API analyzes heap snapshot(s) with a specified heap analysis.
125
+ * This is equivalent to `memlab analyze` in CLI.
126
+ *
127
+ * @param runResult return value of a browser interaction run
128
+ * @param heapAnalyzer instance of a heap analysis
129
+ * @param args other CLI arguments that needs to be passed to the heap analysis
130
+ * @returns each analysis may have a different return type, please check out
131
+ * the type definition or the documentation for the `process` method of the
132
+ * analysis class you are using for `heapAnalyzer`.
133
+ * * **Examples**:
134
+ * ```javascript
135
+ * const {takeSnapshots, StringAnalysis} = require('@memlab/api');
136
+ *
137
+ * (async function () {
138
+ * const scenario = {
139
+ * url: () => 'https://www.facebook.com',
140
+ * };
141
+ * const result = await takeSnapshots({scenario});
142
+ * const analysis = new StringAnalysis();
143
+ * await analyze(result, analysis);
144
+ * })();
145
+ * ```
146
+ */
147
+ export declare function analyze(runResult: BrowserInteractionResultReader, heapAnalyzer: BaseAnalysis, args?: ParsedArgs): Promise<void>;
148
+ /**
149
+ * This warms up web server by sending web requests to the web sever.
150
+ * This is equivalent to run `memlab warmup` in CLI.
151
+ * @internal
152
+ *
153
+ * @param options configure browser interaction run
154
+ */
36
155
  export declare function warmup(options?: APIOptions): Promise<void>;
37
- export declare function setupPage(page: Page, options?: APIOptions): Promise<void>;
156
+ /**
157
+ * Browser interaction API used by MemLab API and MemLab CLI
158
+ * @internal
159
+ */
38
160
  export declare function testInBrowser(options?: APIOptions): Promise<void>;
39
- export {};
40
161
  //# sourceMappingURL=API.d.ts.map
package/dist/API.js CHANGED
@@ -21,14 +21,31 @@ 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.setupPage = exports.warmup = exports.analyze = exports.takeSnapshots = exports.run = void 0;
24
+ exports.testInBrowser = exports.warmup = exports.analyze = 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"));
28
- function setConfigByRunOptions(config, options) {
29
- config.isFullRun = !!options.snapshotForEachStep;
30
- }
31
- function run(options = {}) {
28
+ const BrowserInteractionResultReader_1 = __importDefault(require("./result-reader/BrowserInteractionResultReader"));
29
+ /**
30
+ * This API warms up web server, runs E2E interaction, and takes heap snapshots.
31
+ * This is equivalent to run `memlab warmup-and-snapshot` in CLI.
32
+ * This is also equivalent to warm up and call {@link takeSnapshots}.
33
+ *
34
+ * @param options configure browser interaction run
35
+ * @returns browser interaction results
36
+ * * **Examples**:
37
+ * ```javascript
38
+ * const {warmupAndTakeSnapshots} = require('@memlab/api');
39
+ *
40
+ * (async function () {
41
+ * const scenario = {
42
+ * url: () => 'https://www.facebook.com',
43
+ * };
44
+ * const result = await warmupAndTakeSnapshots({scenario});
45
+ * })();
46
+ * ```
47
+ */
48
+ function warmupAndTakeSnapshots(options = {}) {
32
49
  return __awaiter(this, void 0, void 0, function* () {
33
50
  const config = core_1.MemLabConfig.resetConfigWithTranscientDir();
34
51
  setConfigByRunOptions(config, options);
@@ -38,14 +55,63 @@ function run(options = {}) {
38
55
  const { evalInBrowserAfterInitLoad } = options;
39
56
  yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
40
57
  yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
41
- return {
42
- config,
43
- tabsOrder: core_1.utils.loadTabsOrder(),
44
- metaInfo: core_1.utils.loadRunMetaInfo(),
45
- };
58
+ return BrowserInteractionResultReader_1.default.from(config.workDir);
59
+ });
60
+ }
61
+ exports.warmupAndTakeSnapshots = warmupAndTakeSnapshots;
62
+ /**
63
+ * This API runs browser interaction and find memory leaks triggered in browser
64
+ * This is equivalent to run `memlab run` in CLI.
65
+ * This is also equivalent to warm up, and call {@link takeSnapshots}
66
+ * and {@link findLeaks}.
67
+ *
68
+ * @param runOptions configure browser interaction run
69
+ * @returns leak traces detected and clustered from the browser interaction
70
+ * * **Examples**:
71
+ * ```javascript
72
+ * const {run} = require('@memlab/api');
73
+ *
74
+ * (async function () {
75
+ * const scenario = {
76
+ * url: () => 'https://www.facebook.com',
77
+ * };
78
+ * const leaks = await run({scenario});
79
+ * })();
80
+ * ```
81
+ */
82
+ function run(runOptions = {}) {
83
+ return __awaiter(this, void 0, void 0, function* () {
84
+ const config = core_1.MemLabConfig.resetConfigWithTranscientDir();
85
+ setConfigByRunOptions(config, runOptions);
86
+ config.externalCookiesFile = runOptions.cookiesFile;
87
+ config.scenario = runOptions.scenario;
88
+ const testPlanner = new e2e_1.TestPlanner({ config });
89
+ const { evalInBrowserAfterInitLoad } = runOptions;
90
+ yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
91
+ yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
92
+ const runResult = BrowserInteractionResultReader_1.default.from(config.workDir);
93
+ return yield findLeaks(runResult);
46
94
  });
47
95
  }
48
96
  exports.run = run;
97
+ /**
98
+ * This API runs E2E interaction and takes heap snapshots.
99
+ * This is equivalent to run `memlab snapshot` in CLI.
100
+ *
101
+ * @param options configure browser interaction run
102
+ * @returns browser interaction results
103
+ * * **Examples**:
104
+ * ```javascript
105
+ * const {takeSnapshots} = require('@memlab/api');
106
+ *
107
+ * (async function () {
108
+ * const scenario = {
109
+ * url: () => 'https://www.facebook.com',
110
+ * };
111
+ * const result = await takeSnapshots({scenario});
112
+ * })();
113
+ * ```
114
+ */
49
115
  function takeSnapshots(options = {}) {
50
116
  return __awaiter(this, void 0, void 0, function* () {
51
117
  const config = core_1.MemLabConfig.resetConfigWithTranscientDir();
@@ -55,20 +121,77 @@ function takeSnapshots(options = {}) {
55
121
  const testPlanner = new e2e_1.TestPlanner();
56
122
  const { evalInBrowserAfterInitLoad } = options;
57
123
  yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
58
- return {
59
- config,
60
- tabsOrder: core_1.utils.loadTabsOrder(),
61
- metaInfo: core_1.utils.loadRunMetaInfo(),
62
- };
124
+ return BrowserInteractionResultReader_1.default.from(config.workDir);
63
125
  });
64
126
  }
65
127
  exports.takeSnapshots = takeSnapshots;
128
+ /**
129
+ * This API finds memory leaks by analyzing heap snapshot(s)
130
+ * This is equivalent to `memlab find-leaks` in CLI.
131
+ *
132
+ * @param runResult return value of a browser interaction run
133
+ * @returns leak traces detected and clustered from the browser interaction
134
+ * * **Examples**:
135
+ * ```javascript
136
+ * const {findLeaks, takeSnapshots} = require('@memlab/api');
137
+ *
138
+ * (async function () {
139
+ * const scenario = {
140
+ * url: () => 'https://www.facebook.com',
141
+ * };
142
+ * const result = await takeSnapshots({scenario});
143
+ * const leaks = findLeaks(result);
144
+ * })();
145
+ * ```
146
+ */
147
+ function findLeaks(runResult) {
148
+ return __awaiter(this, void 0, void 0, function* () {
149
+ const workDir = runResult.getRootDirectory();
150
+ core_1.fileManager.initDirs(core_1.config, { workDir });
151
+ core_1.config.chaseWeakMapEdge = false;
152
+ return yield core_1.analysis.checkLeak();
153
+ });
154
+ }
155
+ exports.findLeaks = findLeaks;
156
+ /**
157
+ * This API analyzes heap snapshot(s) with a specified heap analysis.
158
+ * This is equivalent to `memlab analyze` in CLI.
159
+ *
160
+ * @param runResult return value of a browser interaction run
161
+ * @param heapAnalyzer instance of a heap analysis
162
+ * @param args other CLI arguments that needs to be passed to the heap analysis
163
+ * @returns each analysis may have a different return type, please check out
164
+ * the type definition or the documentation for the `process` method of the
165
+ * analysis class you are using for `heapAnalyzer`.
166
+ * * **Examples**:
167
+ * ```javascript
168
+ * const {takeSnapshots, StringAnalysis} = require('@memlab/api');
169
+ *
170
+ * (async function () {
171
+ * const scenario = {
172
+ * url: () => 'https://www.facebook.com',
173
+ * };
174
+ * const result = await takeSnapshots({scenario});
175
+ * const analysis = new StringAnalysis();
176
+ * await analyze(result, analysis);
177
+ * })();
178
+ * ```
179
+ */
66
180
  function analyze(runResult, heapAnalyzer, args = { _: [] }) {
67
181
  return __awaiter(this, void 0, void 0, function* () {
68
- yield heapAnalyzer.run({ args });
182
+ const workDir = runResult.getRootDirectory();
183
+ core_1.fileManager.initDirs(core_1.config, { workDir });
184
+ return yield heapAnalyzer.run({ args });
69
185
  });
70
186
  }
71
187
  exports.analyze = analyze;
188
+ /**
189
+ * This warms up web server by sending web requests to the web sever.
190
+ * This is equivalent to run `memlab warmup` in CLI.
191
+ * @internal
192
+ *
193
+ * @param options configure browser interaction run
194
+ */
72
195
  function warmup(options = {}) {
73
196
  var _a, _b;
74
197
  return __awaiter(this, void 0, void 0, function* () {
@@ -109,6 +232,9 @@ function warmup(options = {}) {
109
232
  });
110
233
  }
111
234
  exports.warmup = warmup;
235
+ function setConfigByRunOptions(config, options) {
236
+ config.isFullRun = !!options.snapshotForEachStep;
237
+ }
112
238
  function setupPage(page, options = {}) {
113
239
  var _a, _b, _c;
114
240
  return __awaiter(this, void 0, void 0, function* () {
@@ -130,7 +256,6 @@ function setupPage(page, options = {}) {
130
256
  }));
131
257
  });
132
258
  }
133
- exports.setupPage = setupPage;
134
259
  function autoDismissDialog(page, options = {}) {
135
260
  var _a;
136
261
  const config = (_a = options.config) !== null && _a !== void 0 ? _a : core_1.config;
@@ -153,6 +278,10 @@ function initBrowserInfoInConfig(browser, options = {}) {
153
278
  }
154
279
  });
155
280
  }
281
+ /**
282
+ * Browser interaction API used by MemLab API and MemLab CLI
283
+ * @internal
284
+ */
156
285
  function testInBrowser(options = {}) {
157
286
  var _a, _b;
158
287
  return __awaiter(this, void 0, void 0, function* () {
@@ -17,12 +17,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
17
17
  step((generator = generator.apply(thisArg, _arguments || [])).next());
18
18
  });
19
19
  };
20
- var __importDefault = (this && this.__importDefault) || function (mod) {
21
- return (mod && mod.__esModule) ? mod : { "default": mod };
22
- };
23
20
  Object.defineProperty(exports, "__esModule", { value: true });
24
21
  /* eslint-disable @typescript-eslint/ban-ts-comment */
25
- const path_1 = __importDefault(require("path"));
26
22
  const index_1 = require("../../index");
27
23
  const E2ETestSettings_1 = require("./lib/E2ETestSettings");
28
24
  beforeEach(E2ETestSettings_1.testSetup);
@@ -34,14 +30,17 @@ function inject() {
34
30
  };
35
31
  }
36
32
  test('Detached DOM analysis works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
37
- const result = yield (0, index_1.run)({ scenario: E2ETestSettings_1.scenario, evalInBrowserAfterInitLoad: inject });
33
+ const result = yield (0, index_1.warmupAndTakeSnapshots)({
34
+ scenario: E2ETestSettings_1.scenario,
35
+ evalInBrowserAfterInitLoad: inject,
36
+ });
38
37
  // test analysis from auto loading
39
38
  let analysis = new index_1.DetachedDOMElementAnalysis();
40
39
  yield analysis.run();
41
40
  let domElems = analysis.getDetachedElements();
42
41
  expect(domElems.some(node => node.name === 'Detached HTMLTableElement')).toBe(true);
43
42
  // test analysis from file
44
- const snapshotFile = path_1.default.join(result.config.curDataDir, 's3.heapsnapshot');
43
+ const snapshotFile = result.getSnapshotFiles().pop();
45
44
  analysis = new index_1.DetachedDOMElementAnalysis();
46
45
  yield analysis.analyzeSnapshotFromFile(snapshotFile);
47
46
  domElems = analysis.getDetachedElements();
@@ -17,11 +17,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
17
17
  step((generator = generator.apply(thisArg, _arguments || [])).next());
18
18
  });
19
19
  };
20
- var __importDefault = (this && this.__importDefault) || function (mod) {
21
- return (mod && mod.__esModule) ? mod : { "default": mod };
22
- };
23
20
  Object.defineProperty(exports, "__esModule", { value: true });
24
- const path_1 = __importDefault(require("path"));
25
21
  const index_1 = require("../../index");
26
22
  const E2ETestSettings_1 = require("./lib/E2ETestSettings");
27
23
  beforeEach(E2ETestSettings_1.testSetup);
@@ -39,14 +35,17 @@ function inject() {
39
35
  };
40
36
  }
41
37
  test('Duplicate object analysis works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
42
- const result = yield (0, index_1.run)({ scenario: E2ETestSettings_1.scenario, evalInBrowserAfterInitLoad: inject });
38
+ const result = yield (0, index_1.warmupAndTakeSnapshots)({
39
+ scenario: E2ETestSettings_1.scenario,
40
+ evalInBrowserAfterInitLoad: inject,
41
+ });
43
42
  // test analysis from auto loading
44
43
  let analysis = new index_1.ObjectShallowAnalysis();
45
44
  yield analysis.run();
46
45
  let dupcatedObjectInfo = analysis.getTopDuplicatedObjectInCount();
47
46
  expect(dupcatedObjectInfo[0].n).toBe(12345);
48
47
  // test analysis from file
49
- const snapshotFile = path_1.default.join(result.config.curDataDir, 's3.heapsnapshot');
48
+ const snapshotFile = result.getSnapshotFiles().pop();
50
49
  analysis = new index_1.ObjectShallowAnalysis();
51
50
  yield analysis.analyzeSnapshotFromFile(snapshotFile);
52
51
  dupcatedObjectInfo = analysis.getTopDuplicatedObjectInCount();
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @emails oncall+ws_labs
8
+ * @format
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=E2EFindLeaks.example.d.ts.map
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @emails oncall+ws_labs
9
+ * @format
10
+ */
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
22
+ const core_1 = require("@memlab/core");
23
+ const index_1 = require("../../index");
24
+ const scenario = {
25
+ app: () => 'test-spa',
26
+ url: () => '',
27
+ action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
28
+ };
29
+ function inject() {
30
+ // @ts-ignore
31
+ window.injectHookForLink4 = () => {
32
+ const arr = [];
33
+ for (let i = 0; i < 23; ++i) {
34
+ arr.push(document.createElement('div'));
35
+ }
36
+ // @ts-ignore
37
+ window.__injectedValue = arr;
38
+ // @ts-ignore
39
+ window._path_1 = { x: { y: document.createElement('div') } };
40
+ // @ts-ignore
41
+ window._path_2 = new Set([document.createElement('div')]);
42
+ };
43
+ }
44
+ function test() {
45
+ return __awaiter(this, void 0, void 0, function* () {
46
+ const leaks = yield (0, index_1.run)({ scenario, evalInBrowserAfterInitLoad: inject });
47
+ core_1.info.lowLevel(`${leaks.length}`);
48
+ });
49
+ }
50
+ test();
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @emails oncall+ws_labs
8
+ * @format
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=E2EFindMemoryLeaks.test.d.ts.map
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @emails oncall+ws_labs
9
+ * @format
10
+ */
11
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
12
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
13
+ return new (P || (P = Promise))(function (resolve, reject) {
14
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
15
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
16
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
17
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
18
+ });
19
+ };
20
+ 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('leak detector can find detached DOM elements', () => __awaiter(void 0, void 0, void 0, function* () {
44
+ const leaks = yield (0, index_1.run)({
45
+ scenario: E2ETestSettings_1.scenario,
46
+ evalInBrowserAfterInitLoad: injectDetachedDOMElements,
47
+ });
48
+ // detected all different leak trace cluster
49
+ expect(leaks.length).toBe(3);
50
+ // expect all traces are found
51
+ expect(leaks.some(leak => JSON.stringify(leak).includes('__injectedValue')));
52
+ expect(leaks.some(leak => JSON.stringify(leak).includes('_path_1')));
53
+ expect(leaks.some(leak => JSON.stringify(leak).includes('_path_2')));
54
+ }), E2ETestSettings_1.testTimeout);
55
+ test('self-defined leak detector can find TestObject', () => __awaiter(void 0, void 0, void 0, function* () {
56
+ const selfDefinedScenario = {
57
+ app: () => 'test-spa',
58
+ url: () => '',
59
+ action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
60
+ leakFilter: (node) => {
61
+ return node.name === 'TestObject' && node.type === 'object';
62
+ },
63
+ };
64
+ const leaks = yield (0, index_1.run)({
65
+ scenario: selfDefinedScenario,
66
+ evalInBrowserAfterInitLoad: injectDetachedDOMElements,
67
+ });
68
+ // detected all different leak trace cluster
69
+ expect(leaks.length).toBe(1);
70
+ // expect all traces are found
71
+ expect(leaks.some(leak => JSON.stringify(leak).includes('_randomObject')));
72
+ }), E2ETestSettings_1.testTimeout);
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @emails oncall+ws_labs
8
+ * @format
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=E2EResultReader.test.d.ts.map