@memlab/api 1.0.1 → 1.0.2

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 (27) hide show
  1. package/dist/API.d.ts +80 -18
  2. package/dist/API.d.ts.map +1 -1
  3. package/dist/API.js +85 -15
  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.d.ts.map +1 -0
  8. package/dist/__tests__/API/E2EFindLeaks.example.js +50 -0
  9. package/dist/__tests__/API/E2EFindMemoryLeaks.test.d.ts +11 -0
  10. package/dist/__tests__/API/E2EFindMemoryLeaks.test.d.ts.map +1 -0
  11. package/dist/__tests__/API/E2EFindMemoryLeaks.test.js +51 -0
  12. package/dist/__tests__/API/E2EResultReader.test.d.ts +11 -0
  13. package/dist/__tests__/API/E2EResultReader.test.d.ts.map +1 -0
  14. package/dist/__tests__/API/E2EResultReader.test.js +72 -0
  15. package/dist/__tests__/API/E2ERunSingleSnapshot.example.js +11 -12
  16. package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.js +4 -15
  17. package/dist/__tests__/API/E2EStringAnalysis.test.js +19 -15
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +6 -1
  21. package/dist/result-reader/BaseResultReader.d.ts +49 -0
  22. package/dist/result-reader/BaseResultReader.d.ts.map +1 -0
  23. package/dist/result-reader/BaseResultReader.js +72 -0
  24. package/dist/result-reader/BrowserInteractionResultReader.d.ts +46 -0
  25. package/dist/result-reader/BrowserInteractionResultReader.d.ts.map +1 -0
  26. package/dist/result-reader/BrowserInteractionResultReader.js +77 -0
  27. package/package.json +1 -1
package/dist/API.d.ts CHANGED
@@ -7,34 +7,96 @@
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, AnyValue, 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
18
+ */
19
+ export declare type RunOptions = {
20
+ /** test scenario definition */
23
21
  scenario?: IScenario;
22
+ /** 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
+ * @ignore
35
+ * Options for memlab inter-package API calls
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 call {@link warmup} and {@link takeSnapshots}.
47
+ *
48
+ * @param options configure browser interaction run
49
+ * @returns browser interaction results
50
+ */
51
+ export declare function warmupAndTakeSnapshots(options?: RunOptions): Promise<BrowserInteractionResultReader>;
52
+ /**
53
+ * This API runs browser interaction and find memory leaks triggered in browser
54
+ * This is equivalent to run `memlab run` in CLI.
55
+ * This is also equivalent to call {@link warmup}, {@link takeSnapshots},
56
+ * and {@link findLeaks}.
57
+ *
58
+ * @param options configure browser interaction run
59
+ * @returns an array of leak traces detected and clustered from the
60
+ * browser interaction
61
+ */
62
+ export declare function run(options?: RunOptions): Promise<ISerializedInfo[]>;
63
+ /**
64
+ * This API runs E2E interaction and takes heap snapshots.
65
+ * This is equivalent to run `memlab snapshot` in CLI.
66
+ *
67
+ * @param options configure browser interaction run
68
+ * @returns browser interaction results
69
+ */
70
+ export declare function takeSnapshots(options?: RunOptions): Promise<BrowserInteractionResultReader>;
71
+ /**
72
+ * This API finds memory leaks by analyzing heap snapshot(s)
73
+ * This is equivalent to `memlab find-leaks` in CLI.
74
+ *
75
+ * @param runResult return value of a browser interaction run
76
+ * @returns an array of leak traces detected and clustered from the
77
+ * browser interaction
78
+ */
79
+ export declare function findLeaks(runResult: BrowserInteractionResultReader): Promise<ISerializedInfo[]>;
80
+ /**
81
+ * This API analyzes heap snapshot(s) with a specified heap analysis.
82
+ * This is equivalent to `memlab analyze` in CLI.
83
+ *
84
+ * @param runResult return value of a browser interaction run
85
+ * @param heapAnalyzer instance of a heap analysis
86
+ * @param args other CLI arguments that needs to be passed to the heap analysis
87
+ * @returns
88
+ */
89
+ export declare function analyze(runResult: BrowserInteractionResultReader, heapAnalyzer: BaseAnalysis, args?: ParsedArgs): Promise<AnyValue>;
90
+ /**
91
+ * @ignore
92
+ * This warms up web server by sending web requests to the web sever.
93
+ * This is equivalent to run `memlab warmup` in CLI.
94
+ *
95
+ * @param options configure browser interaction run
96
+ */
36
97
  export declare function warmup(options?: APIOptions): Promise<void>;
37
- export declare function setupPage(page: Page, options?: APIOptions): Promise<void>;
98
+ /**
99
+ * @ignore
100
+ */
38
101
  export declare function testInBrowser(options?: APIOptions): Promise<void>;
39
- export {};
40
102
  //# sourceMappingURL=API.d.ts.map
package/dist/API.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"API.d.ts","sourceRoot":"","sources":["../src/API.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,IAAI,EAAU,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,SAAS,EACT,WAAW,EAGZ,MAAM,cAAc,CAAC;AAEtB,OAAO,EAKL,YAAY,EACb,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,WAAW,EAGZ,MAAM,aAAa,CAAC;AACrB,OAAO,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAGnD,aAAK,UAAU,GAAG;IAGhB,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,aAAK,UAAU,GAAG;IAChB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B,CAAC,EAAE,WAAW,CAAC;IACzC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF,aAAK,SAAS,GAAG;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,QAAQ,EAAE,WAAW,CAAC;CACvB,CAAC;AASF,wBAAsB,GAAG,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CActE;AAED,wBAAsB,aAAa,CACjC,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,SAAS,CAAC,CAapB;AAED,wBAAsB,OAAO,CAC3B,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,YAAY,EAC1B,IAAI,GAAE,UAAoB,GACzB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,MAAM,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuCpE;AAED,wBAAsB,SAAS,CAC7B,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,IAAI,CAAC,CAoBf;AAyBD,wBAAsB,aAAa,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD3E"}
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,QAAQ,EACR,eAAe,EACf,SAAS,EAGV,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;AAE5F;;GAEG;AACH,oBAAY,UAAU,GAAG;IACvB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,mBAAmB;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,0BAA0B,CAAC,EAAE,WAAW,CAAC;IACzC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF;;;GAGG;AACH,oBAAY,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;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,8BAA8B,CAAC,CAUzC;AAED;;;;;;;;;GASG;AACH,wBAAsB,GAAG,CACvB,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,eAAe,EAAE,CAAC,CAW5B;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,OAAO,GAAE,UAAe,GACvB,OAAO,CAAC,8BAA8B,CAAC,CASzC;AAED;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,8BAA8B,GACxC,OAAO,CAAC,eAAe,EAAE,CAAC,CAK5B;AAED;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAC3B,SAAS,EAAE,8BAA8B,EACzC,YAAY,EAAE,YAAY,EAC1B,IAAI,GAAE,UAAoB,GACzB,OAAO,CAAC,QAAQ,CAAC,CAInB;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuCpE;AAsDD;;GAEG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAkD3E"}
package/dist/API.js CHANGED
@@ -21,13 +21,43 @@ 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;
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 call {@link warmup} and {@link takeSnapshots}.
33
+ *
34
+ * @param options configure browser interaction run
35
+ * @returns browser interaction results
36
+ */
37
+ function warmupAndTakeSnapshots(options = {}) {
38
+ return __awaiter(this, void 0, void 0, function* () {
39
+ const config = core_1.MemLabConfig.resetConfigWithTranscientDir();
40
+ setConfigByRunOptions(config, options);
41
+ config.externalCookiesFile = options.cookiesFile;
42
+ config.scenario = options.scenario;
43
+ const testPlanner = new e2e_1.TestPlanner({ config });
44
+ const { evalInBrowserAfterInitLoad } = options;
45
+ yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
46
+ yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
47
+ return BrowserInteractionResultReader_1.default.from(config.workDir);
48
+ });
30
49
  }
50
+ exports.warmupAndTakeSnapshots = warmupAndTakeSnapshots;
51
+ /**
52
+ * This API runs browser interaction and find memory leaks triggered in browser
53
+ * This is equivalent to run `memlab run` in CLI.
54
+ * This is also equivalent to call {@link warmup}, {@link takeSnapshots},
55
+ * and {@link findLeaks}.
56
+ *
57
+ * @param options configure browser interaction run
58
+ * @returns an array of leak traces detected and clustered from the
59
+ * browser interaction
60
+ */
31
61
  function run(options = {}) {
32
62
  return __awaiter(this, void 0, void 0, function* () {
33
63
  const config = core_1.MemLabConfig.resetConfigWithTranscientDir();
@@ -38,14 +68,18 @@ function run(options = {}) {
38
68
  const { evalInBrowserAfterInitLoad } = options;
39
69
  yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
40
70
  yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
41
- return {
42
- config,
43
- tabsOrder: core_1.utils.loadTabsOrder(),
44
- metaInfo: core_1.utils.loadRunMetaInfo(),
45
- };
71
+ const runResult = BrowserInteractionResultReader_1.default.from(config.workDir);
72
+ return yield findLeaks(runResult);
46
73
  });
47
74
  }
48
75
  exports.run = run;
76
+ /**
77
+ * This API runs E2E interaction and takes heap snapshots.
78
+ * This is equivalent to run `memlab snapshot` in CLI.
79
+ *
80
+ * @param options configure browser interaction run
81
+ * @returns browser interaction results
82
+ */
49
83
  function takeSnapshots(options = {}) {
50
84
  return __awaiter(this, void 0, void 0, function* () {
51
85
  const config = core_1.MemLabConfig.resetConfigWithTranscientDir();
@@ -55,20 +89,51 @@ function takeSnapshots(options = {}) {
55
89
  const testPlanner = new e2e_1.TestPlanner();
56
90
  const { evalInBrowserAfterInitLoad } = options;
57
91
  yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
58
- return {
59
- config,
60
- tabsOrder: core_1.utils.loadTabsOrder(),
61
- metaInfo: core_1.utils.loadRunMetaInfo(),
62
- };
92
+ return BrowserInteractionResultReader_1.default.from(config.workDir);
63
93
  });
64
94
  }
65
95
  exports.takeSnapshots = takeSnapshots;
96
+ /**
97
+ * This API finds memory leaks by analyzing heap snapshot(s)
98
+ * This is equivalent to `memlab find-leaks` in CLI.
99
+ *
100
+ * @param runResult return value of a browser interaction run
101
+ * @returns an array of leak traces detected and clustered from the
102
+ * browser interaction
103
+ */
104
+ function findLeaks(runResult) {
105
+ return __awaiter(this, void 0, void 0, function* () {
106
+ const workDir = runResult.getRootDirectory();
107
+ core_1.fileManager.initDirs(core_1.config, { workDir });
108
+ core_1.config.chaseWeakMapEdge = false;
109
+ return yield core_1.analysis.checkLeak();
110
+ });
111
+ }
112
+ exports.findLeaks = findLeaks;
113
+ /**
114
+ * This API analyzes heap snapshot(s) with a specified heap analysis.
115
+ * This is equivalent to `memlab analyze` in CLI.
116
+ *
117
+ * @param runResult return value of a browser interaction run
118
+ * @param heapAnalyzer instance of a heap analysis
119
+ * @param args other CLI arguments that needs to be passed to the heap analysis
120
+ * @returns
121
+ */
66
122
  function analyze(runResult, heapAnalyzer, args = { _: [] }) {
67
123
  return __awaiter(this, void 0, void 0, function* () {
68
- yield heapAnalyzer.run({ args });
124
+ const workDir = runResult.getRootDirectory();
125
+ core_1.fileManager.initDirs(core_1.config, { workDir });
126
+ return yield heapAnalyzer.run({ args });
69
127
  });
70
128
  }
71
129
  exports.analyze = analyze;
130
+ /**
131
+ * @ignore
132
+ * This warms up web server by sending web requests to the web sever.
133
+ * This is equivalent to run `memlab warmup` in CLI.
134
+ *
135
+ * @param options configure browser interaction run
136
+ */
72
137
  function warmup(options = {}) {
73
138
  var _a, _b;
74
139
  return __awaiter(this, void 0, void 0, function* () {
@@ -109,6 +174,9 @@ function warmup(options = {}) {
109
174
  });
110
175
  }
111
176
  exports.warmup = warmup;
177
+ function setConfigByRunOptions(config, options) {
178
+ config.isFullRun = !!options.snapshotForEachStep;
179
+ }
112
180
  function setupPage(page, options = {}) {
113
181
  var _a, _b, _c;
114
182
  return __awaiter(this, void 0, void 0, function* () {
@@ -130,7 +198,6 @@ function setupPage(page, options = {}) {
130
198
  }));
131
199
  });
132
200
  }
133
- exports.setupPage = setupPage;
134
201
  function autoDismissDialog(page, options = {}) {
135
202
  var _a;
136
203
  const config = (_a = options.config) !== null && _a !== void 0 ? _a : core_1.config;
@@ -153,6 +220,9 @@ function initBrowserInfoInConfig(browser, options = {}) {
153
220
  }
154
221
  });
155
222
  }
223
+ /**
224
+ * @ignore
225
+ */
156
226
  function testInBrowser(options = {}) {
157
227
  var _a, _b;
158
228
  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 @@
1
+ {"version":3,"file":"E2EFindLeaks.example.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EFindLeaks.example.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -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 @@
1
+ {"version":3,"file":"E2EFindMemoryLeaks.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EFindMemoryLeaks.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,51 @@
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 index_1 = require("../../index");
23
+ const E2ETestSettings_1 = require("./lib/E2ETestSettings");
24
+ beforeEach(E2ETestSettings_1.testSetup);
25
+ function injectDetachedDOMElements() {
26
+ // @ts-ignore
27
+ window.injectHookForLink4 = () => {
28
+ const arr = [];
29
+ for (let i = 0; i < 23; ++i) {
30
+ arr.push(document.createElement('div'));
31
+ }
32
+ // @ts-ignore
33
+ window.__injectedValue = arr;
34
+ // @ts-ignore
35
+ window._path_1 = { x: { y: document.createElement('div') } };
36
+ // @ts-ignore
37
+ window._path_2 = new Set([document.createElement('div')]);
38
+ };
39
+ }
40
+ test('leak detector can find detached DOM elements', () => __awaiter(void 0, void 0, void 0, function* () {
41
+ const leaks = yield (0, index_1.run)({
42
+ scenario: E2ETestSettings_1.scenario,
43
+ evalInBrowserAfterInitLoad: injectDetachedDOMElements,
44
+ });
45
+ // detected all different leak trace cluster
46
+ expect(leaks.length).toBe(3);
47
+ // expect all traces are found
48
+ expect(leaks.some(leak => JSON.stringify(leak).includes('__injectedValue')));
49
+ expect(leaks.some(leak => JSON.stringify(leak).includes('_path_1')));
50
+ expect(leaks.some(leak => JSON.stringify(leak).includes('_path_2')));
51
+ }), 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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"E2EResultReader.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EResultReader.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -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,7 +40,7 @@ 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,
@@ -54,19 +50,12 @@ test('Shape unbound analysis works as expected', () => __awaiter(void 0, void 0,
54
50
  let shapeSummary = yield analysis.run();
55
51
  expect(shapeSummary.reduce((acc, summary) => acc || summary.shape.includes('LeakObject'), false)).toBe(true);
56
52
  // test analysis from file
57
- const snapshotDir = path_1.default.join(result.config.curDataDir);
53
+ const snapshotDir = result.getSnapshotFileDir();
58
54
  analysis = new index_1.ShapeUnboundGrowthAnalysis();
59
55
  shapeSummary = yield analysis.analyzeSnapshotsInDirectory(snapshotDir);
60
56
  expect(shapeSummary.some((summary) => summary.shape.includes('LeakObject'))).toBe(true);
61
57
  // expect incorrect use of heap analysis to throw
62
- const snapshotFile = path_1.default.join(result.config.curDataDir, 's3.heapsnapshot');
58
+ const snapshotFile = result.getSnapshotFiles().pop();
63
59
  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);
60
+ expect(() => __awaiter(void 0, void 0, void 0, function* () { return yield analysis.analyzeSnapshotFromFile(snapshotFile); })).rejects.toThrowError();
72
61
  }), 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);
package/dist/index.d.ts CHANGED
@@ -10,4 +10,5 @@
10
10
  export * from './API';
11
11
  export * from '@memlab/heap-analysis';
12
12
  export { config } from '@memlab/core';
13
+ export { default as BrowserInteractionResultReader } from './result-reader/BrowserInteractionResultReader';
13
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,OAAO,CAAC;AACtB,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,cAAc,OAAO,CAAC;AACtB,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC;AACpC,OAAO,EAAC,OAAO,IAAI,8BAA8B,EAAC,MAAM,gDAAgD,CAAC"}
package/dist/index.js CHANGED
@@ -22,9 +22,14 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
22
22
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
23
23
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
24
24
  };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.config = void 0;
29
+ exports.BrowserInteractionResultReader = exports.config = void 0;
27
30
  __exportStar(require("./API"), exports);
28
31
  __exportStar(require("@memlab/heap-analysis"), exports);
29
32
  var core_1 = require("@memlab/core");
30
33
  Object.defineProperty(exports, "config", { enumerable: true, get: function () { return core_1.config; } });
34
+ var BrowserInteractionResultReader_1 = require("./result-reader/BrowserInteractionResultReader");
35
+ Object.defineProperty(exports, "BrowserInteractionResultReader", { enumerable: true, get: function () { return __importDefault(BrowserInteractionResultReader_1).default; } });
@@ -0,0 +1,49 @@
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
+ import { FileManager } from '@memlab/core';
11
+ /**
12
+ * A utility entity to read all generated files from
13
+ * the directory holding the data and results from
14
+ * a memlab run
15
+ */
16
+ export default class BaseResultReader {
17
+ /** @ignore */
18
+ protected workDir: string;
19
+ /** @ignore */
20
+ protected fileManager: FileManager;
21
+ /** @ignore */
22
+ private isValid;
23
+ /**
24
+ * build a result reader
25
+ * @param workDir absolute path of the directory where the data
26
+ * and generated files of the memlab run were stored
27
+ */
28
+ protected constructor(workDir?: string);
29
+ /** @ignore */
30
+ protected check(): void;
31
+ /**
32
+ * build a result reader
33
+ * @param workDir absolute path of the directory where the data
34
+ * and generated files of the memlab run were stored
35
+ * @returns the ResultReader instance
36
+ */
37
+ static from(workDir?: string): BaseResultReader;
38
+ /**
39
+ * get the directory where the data and generated files of
40
+ * the memlab run were stored
41
+ * @returns absolute path of the directory
42
+ */
43
+ getRootDirectory(): string;
44
+ /**
45
+ * clean up data/files generated from the memlab run
46
+ */
47
+ cleanup(): void;
48
+ }
49
+ //# sourceMappingURL=BaseResultReader.d.ts.map
@@ -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,cAAc;IACd,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,cAAc;IACd,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;IACnC,cAAc;IACd,OAAO,CAAC,OAAO,CAAU;IAEzB;;;;OAIG;IACH,SAAS,aAAa,OAAO,SAAK;IASlC,cAAc;IACd,SAAS,CAAC,KAAK,IAAI,IAAI;IAOvB;;;;;OAKG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,SAAK,GAAG,gBAAgB;IAI3C;;;;OAIG;IACI,gBAAgB,IAAI,MAAM;IAKjC;;OAEG;IACI,OAAO,IAAI,IAAI;CAOvB"}
@@ -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 __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
+ /**
18
+ * A utility entity to read all generated files from
19
+ * the directory holding the data and results from
20
+ * a memlab run
21
+ */
22
+ class BaseResultReader {
23
+ /**
24
+ * build a result reader
25
+ * @param workDir absolute path of the directory where the data
26
+ * and generated files of the memlab run were stored
27
+ */
28
+ constructor(workDir = '') {
29
+ this.fileManager = new core_1.FileManager();
30
+ if (workDir === '') {
31
+ workDir = this.fileManager.getWorkDir();
32
+ }
33
+ this.workDir = workDir;
34
+ this.check();
35
+ }
36
+ /** @ignore */
37
+ check() {
38
+ this.isValid = fs_extra_1.default.existsSync(this.workDir);
39
+ if (!this.isValid) {
40
+ core_1.utils.haltOrThrow(`invalid/removed data directory: ${this.workDir}`);
41
+ }
42
+ }
43
+ /**
44
+ * build a result reader
45
+ * @param workDir absolute path of the directory where the data
46
+ * and generated files of the memlab run were stored
47
+ * @returns the ResultReader instance
48
+ */
49
+ static from(workDir = '') {
50
+ return new BaseResultReader(workDir);
51
+ }
52
+ /**
53
+ * get the directory where the data and generated files of
54
+ * the memlab run were stored
55
+ * @returns absolute path of the directory
56
+ */
57
+ getRootDirectory() {
58
+ this.check();
59
+ return this.workDir;
60
+ }
61
+ /**
62
+ * clean up data/files generated from the memlab run
63
+ */
64
+ cleanup() {
65
+ if (!this.isValid) {
66
+ return;
67
+ }
68
+ fs_extra_1.default.removeSync(this.workDir);
69
+ this.isValid = false;
70
+ }
71
+ }
72
+ exports.default = BaseResultReader;
@@ -0,0 +1,46 @@
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
+ import type { E2EStepInfo, RunMetaInfo } from '@memlab/core';
11
+ import BaseResultReader from './BaseResultReader';
12
+ /**
13
+ * A utility entity to read all generated files from
14
+ * the directory holding the data and results from the
15
+ * last browser interaction run
16
+ */
17
+ export default class BrowserInteractionResultReader extends BaseResultReader {
18
+ /**
19
+ * build a result reader
20
+ * @param workDir absolute path of the directory where the data
21
+ * and generated files of the browser interaction run were stored
22
+ * @returns the ResultReader instance
23
+ */
24
+ static from(workDir?: string): BrowserInteractionResultReader;
25
+ /**
26
+ * get all snapshot files
27
+ * @returns an array of snapshot file's absolute path
28
+ */
29
+ getSnapshotFiles(): string[];
30
+ /**
31
+ * get the directory holding all snapshot files
32
+ * @returns the absolute path of the directory
33
+ */
34
+ getSnapshotFileDir(): string;
35
+ /**
36
+ * browser interaction step sequence
37
+ * @returns an array of browser interaction step info
38
+ */
39
+ getInteractionSteps(): E2EStepInfo[];
40
+ /**
41
+ * general meta data of the browser interaction run
42
+ * @returns meta data about the entire browser interaction
43
+ */
44
+ getRunMetaInfo(): RunMetaInfo;
45
+ }
46
+ //# sourceMappingURL=BrowserInteractionResultReader.d.ts.map
@@ -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;;;;;OAKG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,SAAK,GAAG,8BAA8B;IAIzD;;;OAGG;IACI,gBAAgB,IAAI,MAAM,EAAE;IASnC;;;OAGG;IACI,kBAAkB,IAAI,MAAM;IAKnC;;;OAGG;IACI,mBAAmB,IAAI,WAAW,EAAE;IAQ3C;;;OAGG;IACI,cAAc,IAAI,WAAW;CAOrC"}
@@ -0,0 +1,77 @@
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 __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 path_1 = __importDefault(require("path"));
18
+ const BaseResultReader_1 = __importDefault(require("./BaseResultReader"));
19
+ /**
20
+ * A utility entity to read all generated files from
21
+ * the directory holding the data and results from the
22
+ * last browser interaction run
23
+ */
24
+ class BrowserInteractionResultReader extends BaseResultReader_1.default {
25
+ /**
26
+ * build a result reader
27
+ * @param workDir absolute path of the directory where the data
28
+ * and generated files of the browser interaction run were stored
29
+ * @returns the ResultReader instance
30
+ */
31
+ static from(workDir = '') {
32
+ return new BrowserInteractionResultReader(workDir);
33
+ }
34
+ /**
35
+ * get all snapshot files
36
+ * @returns an array of snapshot file's absolute path
37
+ */
38
+ getSnapshotFiles() {
39
+ this.check();
40
+ const dataDir = this.fileManager.getCurDataDir({ workDir: this.workDir });
41
+ return fs_extra_1.default
42
+ .readdirSync(dataDir)
43
+ .filter(file => file.endsWith('heapsnapshot'))
44
+ .map(file => path_1.default.join(dataDir, file));
45
+ }
46
+ /**
47
+ * get the directory holding all snapshot files
48
+ * @returns the absolute path of the directory
49
+ */
50
+ getSnapshotFileDir() {
51
+ this.check();
52
+ return this.fileManager.getCurDataDir({ workDir: this.workDir });
53
+ }
54
+ /**
55
+ * browser interaction step sequence
56
+ * @returns an array of browser interaction step info
57
+ */
58
+ getInteractionSteps() {
59
+ this.check();
60
+ const metaFile = this.fileManager.getSnapshotSequenceMetaFile({
61
+ workDir: this.workDir,
62
+ });
63
+ return core_1.utils.loadTabsOrder(metaFile);
64
+ }
65
+ /**
66
+ * general meta data of the browser interaction run
67
+ * @returns meta data about the entire browser interaction
68
+ */
69
+ getRunMetaInfo() {
70
+ this.check();
71
+ const metaFile = this.fileManager.getRunMetaFile({
72
+ workDir: this.workDir,
73
+ });
74
+ return core_1.utils.loadRunMetaInfo(metaFile);
75
+ }
76
+ }
77
+ exports.default = BrowserInteractionResultReader;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memlab/api",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "license": "MIT",
5
5
  "description": "memlab API",
6
6
  "author": "Liang Gong <lgong@fb.com>",