@memlab/api 1.0.26 → 1.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/API.d.ts +34 -8
- package/dist/API.d.ts.map +1 -1
- package/dist/API.js +34 -19
- package/dist/__tests__/API/E2EFindMemoryLeaks.test.js +1 -24
- package/dist/__tests__/API/E2EMemoryLeakFilter.test.d.ts +11 -0
- package/dist/__tests__/API/E2EMemoryLeakFilter.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EMemoryLeakFilter.test.js +121 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/result-reader/BaseResultReader.d.ts +26 -0
- package/dist/result-reader/BaseResultReader.d.ts.map +1 -1
- package/dist/result-reader/BaseResultReader.js +28 -0
- package/dist/state/APIStateManager.d.ts +26 -0
- package/dist/state/APIStateManager.d.ts.map +1 -0
- package/dist/state/APIStateManager.js +40 -0
- package/dist/state/ConsoleModeManager.d.ts +48 -0
- package/dist/state/ConsoleModeManager.d.ts.map +1 -0
- package/dist/state/ConsoleModeManager.js +106 -0
- package/dist/state/PuppeteerConfigManager.d.ts +21 -0
- package/dist/state/PuppeteerConfigManager.d.ts.map +1 -0
- package/dist/state/PuppeteerConfigManager.js +31 -0
- package/package.json +6 -6
package/dist/API.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { ParsedArgs } from 'minimist';
|
|
11
11
|
import type { AnyFunction, ISerializedInfo, IScenario, Optional } from '@memlab/core';
|
|
12
|
+
import { ConsoleMode } from './state/ConsoleModeManager';
|
|
12
13
|
import { MemLabConfig } from '@memlab/core';
|
|
13
14
|
import { TestPlanner } from '@memlab/e2e';
|
|
14
15
|
import { BaseAnalysis } from '@memlab/heap-analysis';
|
|
@@ -27,7 +28,10 @@ export type RunOptions = {
|
|
|
27
28
|
cookiesFile?: string;
|
|
28
29
|
/**
|
|
29
30
|
* function to be evaluated in browser context after
|
|
30
|
-
* the web page initial load
|
|
31
|
+
* the web page initial load.
|
|
32
|
+
* Note that this function is defined in node.js context but it will be
|
|
33
|
+
* evaluated in browser context so the function should not use any closure
|
|
34
|
+
* variables outside of the browser context.
|
|
31
35
|
*/
|
|
32
36
|
evalInBrowserAfterInitLoad?: AnyFunction;
|
|
33
37
|
/**
|
|
@@ -54,9 +58,22 @@ export type RunOptions = {
|
|
|
54
58
|
*/
|
|
55
59
|
webWorker?: Optional<string>;
|
|
56
60
|
/**
|
|
57
|
-
* skip
|
|
61
|
+
* skip the initial page loading warmup for the web application being tested
|
|
58
62
|
*/
|
|
59
63
|
skipWarmup?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* specifying the terminal output mode, default is `default`.
|
|
66
|
+
* For more details. please check out {@link ConsoleMode}
|
|
67
|
+
*/
|
|
68
|
+
consoleMode?: ConsoleMode;
|
|
69
|
+
/**
|
|
70
|
+
* if not specified, memlab will use the Chromium binary installed
|
|
71
|
+
* by Puppeteer. Use this option to specify a different binary if
|
|
72
|
+
* Puppeteer does not install the Chromium binary correctly (e.g., in a
|
|
73
|
+
* environtment Docker) or when you may want to use a different version of
|
|
74
|
+
* Chromium binary.
|
|
75
|
+
*/
|
|
76
|
+
chromiumBinary?: string;
|
|
60
77
|
};
|
|
61
78
|
/**
|
|
62
79
|
* A data structure holding the result of the {@link run} API call.
|
|
@@ -122,7 +139,7 @@ export declare function warmupAndTakeSnapshots(options?: RunOptions): Promise<Br
|
|
|
122
139
|
* })();
|
|
123
140
|
* ```
|
|
124
141
|
*/
|
|
125
|
-
export declare function run(
|
|
142
|
+
export declare function run(options?: RunOptions): Promise<RunResult>;
|
|
126
143
|
/**
|
|
127
144
|
* This API runs E2E interaction and takes heap snapshots.
|
|
128
145
|
* This is equivalent to running `memlab snapshot` in CLI.
|
|
@@ -147,6 +164,9 @@ export declare function takeSnapshots(options?: RunOptions): Promise<BrowserInte
|
|
|
147
164
|
* This is equivalent to `memlab find-leaks` in CLI.
|
|
148
165
|
*
|
|
149
166
|
* @param runResult return value of a browser interaction run
|
|
167
|
+
* @param options configure memory leak detection run
|
|
168
|
+
* @param options.consoleMode specify the terminal output
|
|
169
|
+
* mode (see {@link ConsoleMode})
|
|
150
170
|
* @returns leak traces detected and clustered from the browser interaction
|
|
151
171
|
* * **Examples**:
|
|
152
172
|
* ```javascript
|
|
@@ -156,12 +176,14 @@ export declare function takeSnapshots(options?: RunOptions): Promise<BrowserInte
|
|
|
156
176
|
* const scenario = {
|
|
157
177
|
* url: () => 'https://www.facebook.com',
|
|
158
178
|
* };
|
|
159
|
-
* const result = await takeSnapshots({scenario});
|
|
160
|
-
* const leaks = findLeaks(result);
|
|
179
|
+
* const result = await takeSnapshots({scenario, consoleMode: 'SILENT'});
|
|
180
|
+
* const leaks = findLeaks(result, {consoleMode: 'CONTINUOUS_TEST'});
|
|
161
181
|
* })();
|
|
162
182
|
* ```
|
|
163
183
|
*/
|
|
164
|
-
export declare function findLeaks(runResult: BaseResultReader
|
|
184
|
+
export declare function findLeaks(runResult: BaseResultReader, options?: {
|
|
185
|
+
consoleMode?: ConsoleMode;
|
|
186
|
+
}): Promise<ISerializedInfo[]>;
|
|
165
187
|
/**
|
|
166
188
|
* This API finds memory leaks by analyzing specified heap snapshots.
|
|
167
189
|
* This is equivalent to `memlab find-leaks` with
|
|
@@ -170,12 +192,16 @@ export declare function findLeaks(runResult: BaseResultReader): Promise<ISeriali
|
|
|
170
192
|
* @param baselineSnapshot the file path of the baseline heap snapshot
|
|
171
193
|
* @param targetSnapshot the file path of the target heap snapshot
|
|
172
194
|
* @param finalSnapshot the file path of the final heap snapshot
|
|
173
|
-
* @param options optionally, you can specify a
|
|
174
|
-
*
|
|
195
|
+
* @param options optionally, you can specify a mode for heap analysis
|
|
196
|
+
* @param options.workDir specify a working directory (other than
|
|
197
|
+
* the default one)
|
|
198
|
+
* @param options.consoleMode specify the terminal output
|
|
199
|
+
* mode (see {@link ConsoleMode})
|
|
175
200
|
* @returns leak traces detected and clustered from the browser interaction
|
|
176
201
|
*/
|
|
177
202
|
export declare function findLeaksBySnapshotFilePaths(baselineSnapshot: string, targetSnapshot: string, finalSnapshot: string, options?: {
|
|
178
203
|
workDir?: string;
|
|
204
|
+
consoleMode?: ConsoleMode;
|
|
179
205
|
}): Promise<ISerializedInfo[]>;
|
|
180
206
|
/**
|
|
181
207
|
* This API analyzes heap snapshot(s) with a specified heap analysis.
|
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;AAGH,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,SAAS,EAGT,QAAQ,EACT,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"API.d.ts","sourceRoot":"","sources":["../src/API.ts"],"names":[],"mappings":"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"}
|
package/dist/API.js
CHANGED
|
@@ -26,6 +26,7 @@ const core_1 = require("@memlab/core");
|
|
|
26
26
|
const e2e_1 = require("@memlab/e2e");
|
|
27
27
|
const APIUtils_1 = __importDefault(require("./lib/APIUtils"));
|
|
28
28
|
const BrowserInteractionResultReader_1 = __importDefault(require("./result-reader/BrowserInteractionResultReader"));
|
|
29
|
+
const APIStateManager_1 = __importDefault(require("./state/APIStateManager"));
|
|
29
30
|
/**
|
|
30
31
|
* This API warms up web server, runs E2E interaction, and takes heap snapshots.
|
|
31
32
|
* This is equivalent to running `memlab warmup-and-snapshot` in CLI.
|
|
@@ -48,15 +49,16 @@ const BrowserInteractionResultReader_1 = __importDefault(require("./result-reade
|
|
|
48
49
|
function warmupAndTakeSnapshots(options = {}) {
|
|
49
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50
51
|
const config = getConfigFromRunOptions(options);
|
|
51
|
-
|
|
52
|
-
config.scenario = options.scenario;
|
|
52
|
+
const state = APIStateManager_1.default.getAndUpdateState(config, options);
|
|
53
53
|
const testPlanner = new e2e_1.TestPlanner({ config });
|
|
54
54
|
const { evalInBrowserAfterInitLoad } = options;
|
|
55
55
|
if (!options.skipWarmup) {
|
|
56
56
|
yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
57
57
|
}
|
|
58
58
|
yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
59
|
-
|
|
59
|
+
const ret = BrowserInteractionResultReader_1.default.from(config.workDir);
|
|
60
|
+
APIStateManager_1.default.restoreState(config, state);
|
|
61
|
+
return ret;
|
|
60
62
|
});
|
|
61
63
|
}
|
|
62
64
|
exports.warmupAndTakeSnapshots = warmupAndTakeSnapshots;
|
|
@@ -81,19 +83,19 @@ exports.warmupAndTakeSnapshots = warmupAndTakeSnapshots;
|
|
|
81
83
|
* })();
|
|
82
84
|
* ```
|
|
83
85
|
*/
|
|
84
|
-
function run(
|
|
86
|
+
function run(options = {}) {
|
|
85
87
|
return __awaiter(this, void 0, void 0, function* () {
|
|
86
|
-
const config = getConfigFromRunOptions(
|
|
87
|
-
|
|
88
|
-
config.scenario = runOptions.scenario;
|
|
88
|
+
const config = getConfigFromRunOptions(options);
|
|
89
|
+
const state = APIStateManager_1.default.getAndUpdateState(config, options);
|
|
89
90
|
const testPlanner = new e2e_1.TestPlanner({ config });
|
|
90
|
-
const { evalInBrowserAfterInitLoad } =
|
|
91
|
-
if (!
|
|
91
|
+
const { evalInBrowserAfterInitLoad } = options;
|
|
92
|
+
if (!options.skipWarmup) {
|
|
92
93
|
yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
93
94
|
}
|
|
94
95
|
yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
95
96
|
const runResult = BrowserInteractionResultReader_1.default.from(config.workDir);
|
|
96
97
|
const leaks = yield findLeaks(runResult);
|
|
98
|
+
APIStateManager_1.default.restoreState(config, state);
|
|
97
99
|
return { leaks, runResult };
|
|
98
100
|
});
|
|
99
101
|
}
|
|
@@ -119,12 +121,13 @@ exports.run = run;
|
|
|
119
121
|
function takeSnapshots(options = {}) {
|
|
120
122
|
return __awaiter(this, void 0, void 0, function* () {
|
|
121
123
|
const config = getConfigFromRunOptions(options);
|
|
122
|
-
|
|
123
|
-
config.scenario = options.scenario;
|
|
124
|
+
const state = APIStateManager_1.default.getAndUpdateState(config, options);
|
|
124
125
|
const testPlanner = new e2e_1.TestPlanner();
|
|
125
126
|
const { evalInBrowserAfterInitLoad } = options;
|
|
126
127
|
yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
127
|
-
|
|
128
|
+
const ret = BrowserInteractionResultReader_1.default.from(config.workDir);
|
|
129
|
+
APIStateManager_1.default.restoreState(config, state);
|
|
130
|
+
return ret;
|
|
128
131
|
});
|
|
129
132
|
}
|
|
130
133
|
exports.takeSnapshots = takeSnapshots;
|
|
@@ -133,6 +136,9 @@ exports.takeSnapshots = takeSnapshots;
|
|
|
133
136
|
* This is equivalent to `memlab find-leaks` in CLI.
|
|
134
137
|
*
|
|
135
138
|
* @param runResult return value of a browser interaction run
|
|
139
|
+
* @param options configure memory leak detection run
|
|
140
|
+
* @param options.consoleMode specify the terminal output
|
|
141
|
+
* mode (see {@link ConsoleMode})
|
|
136
142
|
* @returns leak traces detected and clustered from the browser interaction
|
|
137
143
|
* * **Examples**:
|
|
138
144
|
* ```javascript
|
|
@@ -142,17 +148,20 @@ exports.takeSnapshots = takeSnapshots;
|
|
|
142
148
|
* const scenario = {
|
|
143
149
|
* url: () => 'https://www.facebook.com',
|
|
144
150
|
* };
|
|
145
|
-
* const result = await takeSnapshots({scenario});
|
|
146
|
-
* const leaks = findLeaks(result);
|
|
151
|
+
* const result = await takeSnapshots({scenario, consoleMode: 'SILENT'});
|
|
152
|
+
* const leaks = findLeaks(result, {consoleMode: 'CONTINUOUS_TEST'});
|
|
147
153
|
* })();
|
|
148
154
|
* ```
|
|
149
155
|
*/
|
|
150
|
-
function findLeaks(runResult) {
|
|
156
|
+
function findLeaks(runResult, options = {}) {
|
|
151
157
|
return __awaiter(this, void 0, void 0, function* () {
|
|
158
|
+
const state = APIStateManager_1.default.getAndUpdateState(core_1.config, options);
|
|
152
159
|
const workDir = runResult.getRootDirectory();
|
|
153
160
|
core_1.fileManager.initDirs(core_1.config, { workDir });
|
|
154
161
|
core_1.config.chaseWeakMapEdge = false;
|
|
155
|
-
|
|
162
|
+
const ret = yield core_1.analysis.checkLeak();
|
|
163
|
+
APIStateManager_1.default.restoreState(core_1.config, state);
|
|
164
|
+
return ret;
|
|
156
165
|
});
|
|
157
166
|
}
|
|
158
167
|
exports.findLeaks = findLeaks;
|
|
@@ -164,12 +173,16 @@ exports.findLeaks = findLeaks;
|
|
|
164
173
|
* @param baselineSnapshot the file path of the baseline heap snapshot
|
|
165
174
|
* @param targetSnapshot the file path of the target heap snapshot
|
|
166
175
|
* @param finalSnapshot the file path of the final heap snapshot
|
|
167
|
-
* @param options optionally, you can specify a
|
|
168
|
-
*
|
|
176
|
+
* @param options optionally, you can specify a mode for heap analysis
|
|
177
|
+
* @param options.workDir specify a working directory (other than
|
|
178
|
+
* the default one)
|
|
179
|
+
* @param options.consoleMode specify the terminal output
|
|
180
|
+
* mode (see {@link ConsoleMode})
|
|
169
181
|
* @returns leak traces detected and clustered from the browser interaction
|
|
170
182
|
*/
|
|
171
183
|
function findLeaksBySnapshotFilePaths(baselineSnapshot, targetSnapshot, finalSnapshot, options = {}) {
|
|
172
184
|
return __awaiter(this, void 0, void 0, function* () {
|
|
185
|
+
const state = APIStateManager_1.default.getAndUpdateState(core_1.config, options);
|
|
173
186
|
core_1.config.useExternalSnapshot = true;
|
|
174
187
|
core_1.config.externalSnapshotFilePaths = [
|
|
175
188
|
baselineSnapshot,
|
|
@@ -178,7 +191,9 @@ function findLeaksBySnapshotFilePaths(baselineSnapshot, targetSnapshot, finalSna
|
|
|
178
191
|
];
|
|
179
192
|
core_1.fileManager.initDirs(core_1.config, { workDir: options.workDir });
|
|
180
193
|
core_1.config.chaseWeakMapEdge = false;
|
|
181
|
-
|
|
194
|
+
const ret = yield core_1.analysis.checkLeak();
|
|
195
|
+
APIStateManager_1.default.restoreState(core_1.config, state);
|
|
196
|
+
return ret;
|
|
182
197
|
});
|
|
183
198
|
}
|
|
184
199
|
exports.findLeaksBySnapshotFilePaths = findLeaksBySnapshotFilePaths;
|
|
@@ -58,29 +58,6 @@ test('leak detector can find detached DOM elements', () => __awaiter(void 0, voi
|
|
|
58
58
|
expect(leaks.some(leak => JSON.stringify(leak).includes('_path_1')));
|
|
59
59
|
expect(leaks.some(leak => JSON.stringify(leak).includes('_path_2')));
|
|
60
60
|
}), E2ETestSettings_1.testTimeout);
|
|
61
|
-
test('self-defined leak detector can find TestObject', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
62
|
-
const selfDefinedScenario = {
|
|
63
|
-
app: () => 'test-spa',
|
|
64
|
-
url: () => '',
|
|
65
|
-
action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
|
|
66
|
-
leakFilter: (node) => {
|
|
67
|
-
return node.name === 'TestObject' && node.type === 'object';
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
const workDir = path_1.default.join(os_1.default.tmpdir(), 'memlab-api-test', `${process.pid}`);
|
|
71
|
-
fs_extra_1.default.mkdirsSync(workDir);
|
|
72
|
-
const result = yield (0, index_1.run)({
|
|
73
|
-
scenario: selfDefinedScenario,
|
|
74
|
-
evalInBrowserAfterInitLoad: injectDetachedDOMElements,
|
|
75
|
-
workDir,
|
|
76
|
-
});
|
|
77
|
-
// detected all different leak trace cluster
|
|
78
|
-
expect(result.leaks.length).toBe(1);
|
|
79
|
-
// expect all traces are found
|
|
80
|
-
expect(result.leaks.some(leak => JSON.stringify(leak).includes('_randomObject')));
|
|
81
|
-
const reader = result.runResult;
|
|
82
|
-
expect(path_1.default.resolve(reader.getRootDirectory())).toBe(path_1.default.resolve(workDir));
|
|
83
|
-
}), E2ETestSettings_1.testTimeout);
|
|
84
61
|
function injectDetachedDOMElementsWithPrompt() {
|
|
85
62
|
// @ts-ignore
|
|
86
63
|
window.injectHookForLink4 = () => {
|
|
@@ -121,7 +98,7 @@ test('test runner should work with pages having pop up dialog', () => __awaiter(
|
|
|
121
98
|
return node.name === 'TestObject' && node.type === 'object';
|
|
122
99
|
},
|
|
123
100
|
};
|
|
124
|
-
const workDir = path_1.default.join(os_1.default.tmpdir(), 'memlab-api-test',
|
|
101
|
+
const workDir = path_1.default.join(os_1.default.tmpdir(), 'memlab-api-test', (0, E2ETestSettings_1.getUniqueID)());
|
|
125
102
|
fs_extra_1.default.mkdirsSync(workDir);
|
|
126
103
|
const result = yield (0, index_1.run)({
|
|
127
104
|
scenario: selfDefinedScenario,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall web_perf_infra
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=E2EMemoryLeakFilter.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EMemoryLeakFilter.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EMemoryLeakFilter.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
* @oncall web_perf_infra
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
21
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
const os_1 = __importDefault(require("os"));
|
|
25
|
+
const path_1 = __importDefault(require("path"));
|
|
26
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
27
|
+
const index_1 = require("../../index");
|
|
28
|
+
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
29
|
+
beforeEach(E2ETestSettings_1.testSetup);
|
|
30
|
+
function injectDetachedDOMElements() {
|
|
31
|
+
// @ts-ignore
|
|
32
|
+
window.injectHookForLink4 = () => {
|
|
33
|
+
class TestObject {
|
|
34
|
+
}
|
|
35
|
+
const arr = [];
|
|
36
|
+
for (let i = 0; i < 23; ++i) {
|
|
37
|
+
arr.push(document.createElement('div'));
|
|
38
|
+
}
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
window.__injectedValue = arr;
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
window._path_1 = { x: { y: document.createElement('div') } };
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
window._path_2 = new Set([document.createElement('div')]);
|
|
45
|
+
// @ts-ignore
|
|
46
|
+
window._randomObject = [new TestObject()];
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
test('self-defined leak detector can find TestObject', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
50
|
+
const selfDefinedScenario = {
|
|
51
|
+
app: () => 'test-spa',
|
|
52
|
+
url: () => '',
|
|
53
|
+
action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
|
|
54
|
+
leakFilter: (node) => {
|
|
55
|
+
return node.name === 'TestObject' && node.type === 'object';
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
const workDir = path_1.default.join(os_1.default.tmpdir(), 'memlab-api-test', (0, E2ETestSettings_1.getUniqueID)());
|
|
59
|
+
fs_extra_1.default.mkdirsSync(workDir);
|
|
60
|
+
const result = yield (0, index_1.run)({
|
|
61
|
+
scenario: selfDefinedScenario,
|
|
62
|
+
evalInBrowserAfterInitLoad: injectDetachedDOMElements,
|
|
63
|
+
workDir,
|
|
64
|
+
});
|
|
65
|
+
// detected all different leak trace cluster
|
|
66
|
+
expect(result.leaks.length).toBe(1);
|
|
67
|
+
// expect all traces are found
|
|
68
|
+
expect(result.leaks.some(leak => JSON.stringify(leak).includes('_randomObject')));
|
|
69
|
+
const reader = result.runResult;
|
|
70
|
+
expect(path_1.default.resolve(reader.getRootDirectory())).toBe(path_1.default.resolve(workDir));
|
|
71
|
+
}), E2ETestSettings_1.testTimeout);
|
|
72
|
+
test('self-defined retainer trace filter work as expected (part 1)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
+
const selfDefinedScenario = {
|
|
74
|
+
app: () => 'test-spa',
|
|
75
|
+
url: () => '',
|
|
76
|
+
action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
|
|
77
|
+
retainerReferenceFilter: (edge) => {
|
|
78
|
+
return edge.name_or_index !== '_path_1';
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
const workDir = path_1.default.join(os_1.default.tmpdir(), 'memlab-api-test', (0, E2ETestSettings_1.getUniqueID)());
|
|
82
|
+
fs_extra_1.default.mkdirsSync(workDir);
|
|
83
|
+
const result = yield (0, index_1.run)({
|
|
84
|
+
scenario: selfDefinedScenario,
|
|
85
|
+
evalInBrowserAfterInitLoad: injectDetachedDOMElements,
|
|
86
|
+
workDir,
|
|
87
|
+
});
|
|
88
|
+
// detected all different leak trace cluster
|
|
89
|
+
expect(result.leaks.length).toBe(1);
|
|
90
|
+
// expect the none of the traces to include _path_1
|
|
91
|
+
expect(result.leaks.every(leak => !JSON.stringify(leak).includes('_path_1')));
|
|
92
|
+
// expect some of the traces to include _path_2
|
|
93
|
+
expect(result.leaks.some(leak => JSON.stringify(leak).includes('_path_2')));
|
|
94
|
+
const reader = result.runResult;
|
|
95
|
+
expect(path_1.default.resolve(reader.getRootDirectory())).toBe(path_1.default.resolve(workDir));
|
|
96
|
+
}), E2ETestSettings_1.testTimeout);
|
|
97
|
+
test('self-defined retainer trace filter work as expected (part 2)', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
98
|
+
const selfDefinedScenario = {
|
|
99
|
+
app: () => 'test-spa',
|
|
100
|
+
url: () => '',
|
|
101
|
+
action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
|
|
102
|
+
retainerReferenceFilter: (edge) => {
|
|
103
|
+
return edge.name_or_index !== '_path_2';
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
const workDir = path_1.default.join(os_1.default.tmpdir(), 'memlab-api-test', (0, E2ETestSettings_1.getUniqueID)());
|
|
107
|
+
fs_extra_1.default.mkdirsSync(workDir);
|
|
108
|
+
const result = yield (0, index_1.run)({
|
|
109
|
+
scenario: selfDefinedScenario,
|
|
110
|
+
evalInBrowserAfterInitLoad: injectDetachedDOMElements,
|
|
111
|
+
workDir,
|
|
112
|
+
});
|
|
113
|
+
// detected all different leak trace cluster
|
|
114
|
+
expect(result.leaks.length).toBe(1);
|
|
115
|
+
// expect the none of the traces to include _path_2
|
|
116
|
+
expect(result.leaks.every(leak => !JSON.stringify(leak).includes('_path_2')));
|
|
117
|
+
// expect some of the traces to include _path_1
|
|
118
|
+
expect(result.leaks.some(leak => JSON.stringify(leak).includes('_path_1')));
|
|
119
|
+
const reader = result.runResult;
|
|
120
|
+
expect(path_1.default.resolve(reader.getRootDirectory())).toBe(path_1.default.resolve(workDir));
|
|
121
|
+
}), E2ETestSettings_1.testTimeout);
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
export declare function registerPackage(): Promise<void>;
|
|
12
12
|
export * from './API';
|
|
13
13
|
export * from '@memlab/heap-analysis';
|
|
14
|
+
export * from './state/ConsoleModeManager';
|
|
14
15
|
export { default as BrowserInteractionResultReader } from './result-reader/BrowserInteractionResultReader';
|
|
15
16
|
export { default as SnapshotResultReader } from './result-reader/SnapshotResultReader';
|
|
16
17
|
export { dumpNodeHeapSnapshot, getNodeInnocentHeap, takeNodeMinimalHeap, } from '@memlab/core';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,gBAAgB;AAChB,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAErD;AAED,cAAc,OAAO,CAAC;AACtB,cAAc,uBAAuB,CAAC;AACtC,OAAO,EAAC,OAAO,IAAI,8BAA8B,EAAC,MAAM,gDAAgD,CAAC;AACzG,OAAO,EAAC,OAAO,IAAI,oBAAoB,EAAC,MAAM,sCAAsC,CAAC;AACrF,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,gBAAgB;AAChB,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,gBAAgB;AAChB,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAErD;AAED,cAAc,OAAO,CAAC;AACtB,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAC,OAAO,IAAI,8BAA8B,EAAC,MAAM,gDAAgD,CAAC;AACzG,OAAO,EAAC,OAAO,IAAI,oBAAoB,EAAC,MAAM,sCAAsC,CAAC;AACrF,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,gBAAgB;AAChB,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -47,6 +47,7 @@ function registerPackage() {
|
|
|
47
47
|
exports.registerPackage = registerPackage;
|
|
48
48
|
__exportStar(require("./API"), exports);
|
|
49
49
|
__exportStar(require("@memlab/heap-analysis"), exports);
|
|
50
|
+
__exportStar(require("./state/ConsoleModeManager"), exports);
|
|
50
51
|
var BrowserInteractionResultReader_1 = require("./result-reader/BrowserInteractionResultReader");
|
|
51
52
|
Object.defineProperty(exports, "BrowserInteractionResultReader", { enumerable: true, get: function () { return __importDefault(BrowserInteractionResultReader_1).default; } });
|
|
52
53
|
var SnapshotResultReader_1 = require("./result-reader/SnapshotResultReader");
|
|
@@ -49,6 +49,32 @@ export default class BaseResultReader {
|
|
|
49
49
|
* ```
|
|
50
50
|
*/
|
|
51
51
|
getRootDirectory(): string;
|
|
52
|
+
/**
|
|
53
|
+
* This method gets the backup file of the console output.
|
|
54
|
+
*
|
|
55
|
+
* The memlab CLI commands (e.g., `memlab find-leaks`) outputs a
|
|
56
|
+
* non-structured string representation for easy reading, while the
|
|
57
|
+
* APIs (e.g., <code>{@link findLeaks}</code>) return structured leaks
|
|
58
|
+
* representation that is handy for post-processing. If you need to
|
|
59
|
+
* obtain all the string output from the CLI in the current working directory,
|
|
60
|
+
* you can read them from the CLI output backup file returned by this method.
|
|
61
|
+
*
|
|
62
|
+
* @returns the absolute path of the backup file
|
|
63
|
+
* * **Examples**:
|
|
64
|
+
* ```javascript
|
|
65
|
+
* const {takeSnapshots, findLeaks} = require('@memlab/api');
|
|
66
|
+
*
|
|
67
|
+
* (async function () {
|
|
68
|
+
* const scenario = { url: () => 'https://www.npmjs.com'};
|
|
69
|
+
* const result = await takeSnapshots({scenario});
|
|
70
|
+
* const leaks = await findLeaks(result);
|
|
71
|
+
*
|
|
72
|
+
* // get the console output backup file
|
|
73
|
+
* const consoleBackupFile = result.getConsoleBackupFile();
|
|
74
|
+
* })();
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
getConsoleBackupFile(): string;
|
|
52
78
|
/**
|
|
53
79
|
* clean up data/files generated from the memlab browser interaction run
|
|
54
80
|
* @returns no return value
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseResultReader.d.ts","sourceRoot":"","sources":["../../src/result-reader/BaseResultReader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAQ,WAAW,EAAC,MAAM,cAAc,CAAC;AAGhD;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;IACnC,OAAO,CAAC,OAAO,CAAU;IAEzB;;;;OAIG;IACH,SAAS,aAAa,OAAO,SAAK;IASlC,SAAS,CAAC,KAAK,IAAI,IAAI;IAOvB;;;;OAIG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,SAAK,GAAG,gBAAgB;IAI3C;;;;;;;;;;;;;;;;;OAiBG;IACI,gBAAgB,IAAI,MAAM;IAKjC;;;;;;;;;;;;;;;OAeG;IACI,OAAO,IAAI,IAAI;CAOvB"}
|
|
1
|
+
{"version":3,"file":"BaseResultReader.d.ts","sourceRoot":"","sources":["../../src/result-reader/BaseResultReader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAQ,WAAW,EAAC,MAAM,cAAc,CAAC;AAGhD;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;IACnC,OAAO,CAAC,OAAO,CAAU;IAEzB;;;;OAIG;IACH,SAAS,aAAa,OAAO,SAAK;IASlC,SAAS,CAAC,KAAK,IAAI,IAAI;IAOvB;;;;OAIG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,SAAK,GAAG,gBAAgB;IAI3C;;;;;;;;;;;;;;;;;OAiBG;IACI,gBAAgB,IAAI,MAAM;IAKjC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACI,oBAAoB,IAAI,MAAM;IAIrC;;;;;;;;;;;;;;;OAeG;IACI,OAAO,IAAI,IAAI;CAOvB"}
|
|
@@ -69,6 +69,34 @@ class BaseResultReader {
|
|
|
69
69
|
this.check();
|
|
70
70
|
return this.workDir;
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* This method gets the backup file of the console output.
|
|
74
|
+
*
|
|
75
|
+
* The memlab CLI commands (e.g., `memlab find-leaks`) outputs a
|
|
76
|
+
* non-structured string representation for easy reading, while the
|
|
77
|
+
* APIs (e.g., <code>{@link findLeaks}</code>) return structured leaks
|
|
78
|
+
* representation that is handy for post-processing. If you need to
|
|
79
|
+
* obtain all the string output from the CLI in the current working directory,
|
|
80
|
+
* you can read them from the CLI output backup file returned by this method.
|
|
81
|
+
*
|
|
82
|
+
* @returns the absolute path of the backup file
|
|
83
|
+
* * **Examples**:
|
|
84
|
+
* ```javascript
|
|
85
|
+
* const {takeSnapshots, findLeaks} = require('@memlab/api');
|
|
86
|
+
*
|
|
87
|
+
* (async function () {
|
|
88
|
+
* const scenario = { url: () => 'https://www.npmjs.com'};
|
|
89
|
+
* const result = await takeSnapshots({scenario});
|
|
90
|
+
* const leaks = await findLeaks(result);
|
|
91
|
+
*
|
|
92
|
+
* // get the console output backup file
|
|
93
|
+
* const consoleBackupFile = result.getConsoleBackupFile();
|
|
94
|
+
* })();
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
getConsoleBackupFile() {
|
|
98
|
+
return this.fileManager.getConsoleBackupFile({ workDir: this.workDir });
|
|
99
|
+
}
|
|
72
100
|
/**
|
|
73
101
|
* clean up data/files generated from the memlab browser interaction run
|
|
74
102
|
* @returns no return value
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall web_perf_infra
|
|
9
|
+
*/
|
|
10
|
+
import type { MemLabConfig, Optional, PuppeteerConfig } from '@memlab/core';
|
|
11
|
+
import type { ConsoleMode } from './ConsoleModeManager';
|
|
12
|
+
import type { RunOptions } from '../API';
|
|
13
|
+
export declare class APIState {
|
|
14
|
+
modes: Optional<Set<ConsoleMode>>;
|
|
15
|
+
puppeteerConfig: Optional<PuppeteerConfig>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Manage, save, and restore the current state of the API.
|
|
19
|
+
*/
|
|
20
|
+
declare class APIStateManager {
|
|
21
|
+
getAndUpdateState(config: MemLabConfig, options?: RunOptions): APIState;
|
|
22
|
+
restoreState(config: MemLabConfig, state: APIState): void;
|
|
23
|
+
}
|
|
24
|
+
declare const _default: APIStateManager;
|
|
25
|
+
export default _default;
|
|
26
|
+
//# sourceMappingURL=APIStateManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"APIStateManager.d.ts","sourceRoot":"","sources":["../../src/state/APIStateManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAC,MAAM,cAAc,CAAC;AAC1E,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,QAAQ,CAAC;AAKvC,qBAAa,QAAQ;IACnB,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;IAClC,eAAe,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;CAC5C;AAED;;GAEG;AACH,cAAM,eAAe;IACnB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,UAAe;IAUhE,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ;CAQnD;;AAED,wBAAqC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
* @oncall web_perf_infra
|
|
10
|
+
*/
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.APIState = void 0;
|
|
16
|
+
const ConsoleModeManager_1 = __importDefault(require("./ConsoleModeManager"));
|
|
17
|
+
const PuppeteerConfigManager_1 = __importDefault(require("./PuppeteerConfigManager"));
|
|
18
|
+
class APIState {
|
|
19
|
+
}
|
|
20
|
+
exports.APIState = APIState;
|
|
21
|
+
/**
|
|
22
|
+
* Manage, save, and restore the current state of the API.
|
|
23
|
+
*/
|
|
24
|
+
class APIStateManager {
|
|
25
|
+
getAndUpdateState(config, options = {}) {
|
|
26
|
+
const state = new APIState();
|
|
27
|
+
state.modes = ConsoleModeManager_1.default.getAndUpdateState(config, options);
|
|
28
|
+
state.puppeteerConfig = PuppeteerConfigManager_1.default.getAndUpdateState(config, options);
|
|
29
|
+
return state;
|
|
30
|
+
}
|
|
31
|
+
restoreState(config, state) {
|
|
32
|
+
if (state.modes) {
|
|
33
|
+
ConsoleModeManager_1.default.restoreState(config, state.modes);
|
|
34
|
+
}
|
|
35
|
+
if (state.puppeteerConfig) {
|
|
36
|
+
PuppeteerConfigManager_1.default.restoreState(config, state.puppeteerConfig);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.default = new APIStateManager();
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall web_perf_infra
|
|
9
|
+
*/
|
|
10
|
+
import { MemLabConfig, Nullable } from '@memlab/core';
|
|
11
|
+
import type { RunOptions } from '../API';
|
|
12
|
+
/**
|
|
13
|
+
* enum of all console mode options
|
|
14
|
+
*/
|
|
15
|
+
export declare enum ConsoleMode {
|
|
16
|
+
/**
|
|
17
|
+
* mute all terminal output, equivalent to using `--silent`
|
|
18
|
+
*/
|
|
19
|
+
SILENT = "SILENT",
|
|
20
|
+
/**
|
|
21
|
+
* continuous test mode, no terminal output overwrite or animation,
|
|
22
|
+
* equivalent to using `--sc`
|
|
23
|
+
*/
|
|
24
|
+
CONTINUOUS_TEST = "CONTINUOUS_TEST",
|
|
25
|
+
/**
|
|
26
|
+
* the default mode, there could be terminal output overwrite and animation,
|
|
27
|
+
*/
|
|
28
|
+
DEFAULT = "DEFAULT",
|
|
29
|
+
/**
|
|
30
|
+
* verbose mode, there could be terminal output overwrite and animation
|
|
31
|
+
*/
|
|
32
|
+
VERBOSE = "VERBOSE"
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Manage, save, and restore the current state of the Console modes.
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
declare class ConsoleModeManager {
|
|
39
|
+
getAndUpdateState(config: MemLabConfig, options?: RunOptions): Nullable<Set<ConsoleMode>>;
|
|
40
|
+
restoreState(config: MemLabConfig, modes: Nullable<Set<ConsoleMode>>): void;
|
|
41
|
+
private resetConsoleMode;
|
|
42
|
+
private setConsoleMode;
|
|
43
|
+
private getExistingConsoleModes;
|
|
44
|
+
}
|
|
45
|
+
/** @internal */
|
|
46
|
+
declare const _default: ConsoleModeManager;
|
|
47
|
+
export default _default;
|
|
48
|
+
//# sourceMappingURL=ConsoleModeManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConsoleModeManager.d.ts","sourceRoot":"","sources":["../../src/state/ConsoleModeManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,YAAY,EAAE,QAAQ,EAAkB,MAAM,cAAc,CAAC;AACrE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,QAAQ,CAAC;AAEvC;;GAEG;AACH,oBAAY,WAAW;IACrB;;OAEG;IACH,MAAM,WAAW;IACjB;;;OAGG;IACH,eAAe,oBAAoB;IACnC;;OAEG;IACH,OAAO,YAAY;IACnB;;OAEG;IACH,OAAO,YAAY;CACpB;AAED;;;GAGG;AACH,cAAM,kBAAkB;IACtB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,UAAe;IAIhE,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAUpE,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,cAAc;IAmCtB,OAAO,CAAC,uBAAuB;CAehC;AAED,gBAAgB;;AAChB,wBAAwC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
* @oncall web_perf_infra
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ConsoleMode = void 0;
|
|
13
|
+
const core_1 = require("@memlab/core");
|
|
14
|
+
/**
|
|
15
|
+
* enum of all console mode options
|
|
16
|
+
*/
|
|
17
|
+
var ConsoleMode;
|
|
18
|
+
(function (ConsoleMode) {
|
|
19
|
+
/**
|
|
20
|
+
* mute all terminal output, equivalent to using `--silent`
|
|
21
|
+
*/
|
|
22
|
+
ConsoleMode["SILENT"] = "SILENT";
|
|
23
|
+
/**
|
|
24
|
+
* continuous test mode, no terminal output overwrite or animation,
|
|
25
|
+
* equivalent to using `--sc`
|
|
26
|
+
*/
|
|
27
|
+
ConsoleMode["CONTINUOUS_TEST"] = "CONTINUOUS_TEST";
|
|
28
|
+
/**
|
|
29
|
+
* the default mode, there could be terminal output overwrite and animation,
|
|
30
|
+
*/
|
|
31
|
+
ConsoleMode["DEFAULT"] = "DEFAULT";
|
|
32
|
+
/**
|
|
33
|
+
* verbose mode, there could be terminal output overwrite and animation
|
|
34
|
+
*/
|
|
35
|
+
ConsoleMode["VERBOSE"] = "VERBOSE";
|
|
36
|
+
})(ConsoleMode = exports.ConsoleMode || (exports.ConsoleMode = {}));
|
|
37
|
+
/**
|
|
38
|
+
* Manage, save, and restore the current state of the Console modes.
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
class ConsoleModeManager {
|
|
42
|
+
getAndUpdateState(config, options = {}) {
|
|
43
|
+
return this.setConsoleMode(config, options.consoleMode, true);
|
|
44
|
+
}
|
|
45
|
+
restoreState(config, modes) {
|
|
46
|
+
if (modes == null) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.resetConsoleMode(config);
|
|
50
|
+
for (const mode of modes) {
|
|
51
|
+
this.setConsoleMode(config, mode, false);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
resetConsoleMode(config) {
|
|
55
|
+
config.muteConsole = false;
|
|
56
|
+
config.isContinuousTest = false;
|
|
57
|
+
config.verbose = false;
|
|
58
|
+
}
|
|
59
|
+
setConsoleMode(config, mode, reset) {
|
|
60
|
+
let existingModes = this.getExistingConsoleModes(config);
|
|
61
|
+
switch (mode) {
|
|
62
|
+
case ConsoleMode.SILENT:
|
|
63
|
+
reset && this.resetConsoleMode(config);
|
|
64
|
+
config.muteConsole = true;
|
|
65
|
+
break;
|
|
66
|
+
case ConsoleMode.CONTINUOUS_TEST:
|
|
67
|
+
reset && this.resetConsoleMode(config);
|
|
68
|
+
config.isContinuousTest = true;
|
|
69
|
+
break;
|
|
70
|
+
case ConsoleMode.DEFAULT:
|
|
71
|
+
reset && this.resetConsoleMode(config);
|
|
72
|
+
config.muteConsole = false;
|
|
73
|
+
config.isContinuousTest = false;
|
|
74
|
+
break;
|
|
75
|
+
case ConsoleMode.VERBOSE:
|
|
76
|
+
reset && this.resetConsoleMode(config);
|
|
77
|
+
config.verbose = true;
|
|
78
|
+
break;
|
|
79
|
+
default:
|
|
80
|
+
if (mode == null) {
|
|
81
|
+
existingModes = null;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
throw core_1.utils.haltOrThrow(`Unknown console mode: ${mode}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return existingModes;
|
|
88
|
+
}
|
|
89
|
+
getExistingConsoleModes(config) {
|
|
90
|
+
const modes = new Set([ConsoleMode.DEFAULT]);
|
|
91
|
+
if (config.muteConsole) {
|
|
92
|
+
modes.add(ConsoleMode.SILENT);
|
|
93
|
+
modes.delete(ConsoleMode.DEFAULT);
|
|
94
|
+
}
|
|
95
|
+
if (config.isContinuousTest) {
|
|
96
|
+
modes.add(ConsoleMode.CONTINUOUS_TEST);
|
|
97
|
+
modes.delete(ConsoleMode.DEFAULT);
|
|
98
|
+
}
|
|
99
|
+
if (config.verbose) {
|
|
100
|
+
modes.add(ConsoleMode.VERBOSE);
|
|
101
|
+
}
|
|
102
|
+
return modes;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** @internal */
|
|
106
|
+
exports.default = new ConsoleModeManager();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall web_perf_infra
|
|
9
|
+
*/
|
|
10
|
+
import type { MemLabConfig, PuppeteerConfig } from '@memlab/core';
|
|
11
|
+
import type { RunOptions } from '../API';
|
|
12
|
+
/**
|
|
13
|
+
* Manage, save, and restore the current state of the PuppeteerConfig.
|
|
14
|
+
*/
|
|
15
|
+
declare class PuppeteerStateManager {
|
|
16
|
+
getAndUpdateState(config: MemLabConfig, options?: RunOptions): PuppeteerConfig;
|
|
17
|
+
restoreState(config: MemLabConfig, puppeteerConfig: PuppeteerConfig): void;
|
|
18
|
+
}
|
|
19
|
+
declare const _default: PuppeteerStateManager;
|
|
20
|
+
export default _default;
|
|
21
|
+
//# sourceMappingURL=PuppeteerConfigManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PuppeteerConfigManager.d.ts","sourceRoot":"","sources":["../../src/state/PuppeteerConfigManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,YAAY,EAAE,eAAe,EAAC,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,QAAQ,CAAC;AAIvC;;GAEG;AACH,cAAM,qBAAqB;IACzB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,UAAe;IAWhE,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe;CAGpE;;AAED,wBAA2C"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
* @oncall web_perf_infra
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const core_1 = require("@memlab/core");
|
|
13
|
+
/**
|
|
14
|
+
* Manage, save, and restore the current state of the PuppeteerConfig.
|
|
15
|
+
*/
|
|
16
|
+
class PuppeteerStateManager {
|
|
17
|
+
getAndUpdateState(config, options = {}) {
|
|
18
|
+
const existing = config.puppeteerConfig;
|
|
19
|
+
config.puppeteerConfig = Object.assign({}, config.puppeteerConfig);
|
|
20
|
+
config.externalCookiesFile = options.cookiesFile;
|
|
21
|
+
config.scenario = options.scenario;
|
|
22
|
+
if (options.chromiumBinary != null) {
|
|
23
|
+
core_1.utils.setChromiumBinary(config, options.chromiumBinary);
|
|
24
|
+
}
|
|
25
|
+
return existing;
|
|
26
|
+
}
|
|
27
|
+
restoreState(config, puppeteerConfig) {
|
|
28
|
+
config.puppeteerConfig = puppeteerConfig;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.default = new PuppeteerStateManager();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memlab/api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.28",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "memlab API",
|
|
6
6
|
"author": "Liang Gong <lgong@fb.com>",
|
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@memlab/core": "^1.1.
|
|
31
|
-
"@memlab/e2e": "^1.0.
|
|
32
|
-
"@memlab/heap-analysis": "^1.0.
|
|
30
|
+
"@memlab/core": "^1.1.29",
|
|
31
|
+
"@memlab/e2e": "^1.0.29",
|
|
32
|
+
"@memlab/heap-analysis": "^1.0.26",
|
|
33
33
|
"ansi": "^0.3.1",
|
|
34
34
|
"babar": "^0.2.0",
|
|
35
35
|
"chalk": "^4.0.0",
|
|
36
36
|
"fs-extra": "^4.0.2",
|
|
37
|
-
"minimist": "^1.2.
|
|
37
|
+
"minimist": "^1.2.8",
|
|
38
38
|
"puppeteer": "^21.0.3",
|
|
39
39
|
"puppeteer-core": "^21.0.3",
|
|
40
40
|
"string-width": "^4.2.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/fs-extra": "^9.0.3",
|
|
46
46
|
"@types/jest": "^27.4.1",
|
|
47
|
-
"@types/minimist": "^1.2.
|
|
47
|
+
"@types/minimist": "^1.2.5",
|
|
48
48
|
"@types/node": "^12.16.3",
|
|
49
49
|
"@types/puppeteer": "^5.4.4",
|
|
50
50
|
"jest": "^29.6.2",
|