@memlab/api 1.0.1 → 1.0.4

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