@memlab/api 1.0.0
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/README.md +11 -0
- package/dist/API.d.ts +40 -0
- package/dist/API.d.ts.map +1 -0
- package/dist/API.js +203 -0
- package/dist/__tests__/API/E2EBasicAnalysis.test.d.ts +11 -0
- package/dist/__tests__/API/E2EBasicAnalysis.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EBasicAnalysis.test.js +65 -0
- package/dist/__tests__/API/E2EDetachedDOMAnalysis.test.d.ts +11 -0
- package/dist/__tests__/API/E2EDetachedDOMAnalysis.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EDetachedDOMAnalysis.test.js +49 -0
- package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.d.ts +11 -0
- package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EDuplicateObjectAnalysis.test.js +54 -0
- package/dist/__tests__/API/E2ERunMultipleSnapshots.example.d.ts +11 -0
- package/dist/__tests__/API/E2ERunMultipleSnapshots.example.d.ts.map +1 -0
- package/dist/__tests__/API/E2ERunMultipleSnapshots.example.js +52 -0
- package/dist/__tests__/API/E2ERunSingleSnapshot.example.d.ts +11 -0
- package/dist/__tests__/API/E2ERunSingleSnapshot.example.d.ts.map +1 -0
- package/dist/__tests__/API/E2ERunSingleSnapshot.example.js +38 -0
- package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.d.ts +11 -0
- package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.js +72 -0
- package/dist/__tests__/API/E2EStringAnalysis.test.d.ts +11 -0
- package/dist/__tests__/API/E2EStringAnalysis.test.d.ts.map +1 -0
- package/dist/__tests__/API/E2EStringAnalysis.test.js +66 -0
- package/dist/__tests__/API/lib/E2ETestSettings.d.ts +23 -0
- package/dist/__tests__/API/lib/E2ETestSettings.d.ts.map +1 -0
- package/dist/__tests__/API/lib/E2ETestSettings.js +36 -0
- package/dist/__tests__/heap/E2EHeapParser.test.d.ts +16 -0
- package/dist/__tests__/heap/E2EHeapParser.test.d.ts.map +1 -0
- package/dist/__tests__/heap/E2EHeapParser.test.js +57 -0
- package/dist/__tests__/heap/lib/HeapParserTestUtils.d.ts +12 -0
- package/dist/__tests__/heap/lib/HeapParserTestUtils.d.ts.map +1 -0
- package/dist/__tests__/heap/lib/HeapParserTestUtils.js +99 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/lib/APIUtils.d.ts +20 -0
- package/dist/lib/APIUtils.d.ts.map +1 -0
- package/dist/lib/APIUtils.js +50 -0
- package/package.json +57 -0
package/README.md
ADDED
package/dist/API.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
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 { Page } from 'puppeteer';
|
|
11
|
+
import type { ParsedArgs } from 'minimist';
|
|
12
|
+
import type { AnyFunction, E2EStepInfo, IScenario, RunMetaInfo } from '@memlab/core';
|
|
13
|
+
import { MemLabConfig } from '@memlab/core';
|
|
14
|
+
import { TestPlanner } from '@memlab/e2e';
|
|
15
|
+
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 = {
|
|
23
|
+
scenario?: IScenario;
|
|
24
|
+
cookiesFile?: string;
|
|
25
|
+
evalInBrowserAfterInitLoad?: AnyFunction;
|
|
26
|
+
snapshotForEachStep?: boolean;
|
|
27
|
+
};
|
|
28
|
+
declare type RunResult = {
|
|
29
|
+
config: MemLabConfig;
|
|
30
|
+
tabsOrder: E2EStepInfo[];
|
|
31
|
+
metaInfo: RunMetaInfo;
|
|
32
|
+
};
|
|
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>;
|
|
36
|
+
export declare function warmup(options?: APIOptions): Promise<void>;
|
|
37
|
+
export declare function setupPage(page: Page, options?: APIOptions): Promise<void>;
|
|
38
|
+
export declare function testInBrowser(options?: APIOptions): Promise<void>;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=API.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/API.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
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
|
+
exports.testInBrowser = exports.setupPage = exports.warmup = exports.analyze = exports.takeSnapshots = exports.run = void 0;
|
|
25
|
+
const core_1 = require("@memlab/core");
|
|
26
|
+
const e2e_1 = require("@memlab/e2e");
|
|
27
|
+
const APIUtils_1 = __importDefault(require("./lib/APIUtils"));
|
|
28
|
+
function setConfigByRunOptions(config, options) {
|
|
29
|
+
config.isFullRun = !!options.snapshotForEachStep;
|
|
30
|
+
}
|
|
31
|
+
function run(options = {}) {
|
|
32
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
const config = core_1.MemLabConfig.resetConfigWithTranscientDir();
|
|
34
|
+
setConfigByRunOptions(config, options);
|
|
35
|
+
config.externalCookiesFile = options.cookiesFile;
|
|
36
|
+
config.scenario = options.scenario;
|
|
37
|
+
const testPlanner = new e2e_1.TestPlanner({ config });
|
|
38
|
+
const { evalInBrowserAfterInitLoad } = options;
|
|
39
|
+
yield warmup({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
40
|
+
yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
41
|
+
return {
|
|
42
|
+
config,
|
|
43
|
+
tabsOrder: core_1.utils.loadTabsOrder(),
|
|
44
|
+
metaInfo: core_1.utils.loadRunMetaInfo(),
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
exports.run = run;
|
|
49
|
+
function takeSnapshots(options = {}) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const config = core_1.MemLabConfig.resetConfigWithTranscientDir();
|
|
52
|
+
setConfigByRunOptions(config, options);
|
|
53
|
+
config.externalCookiesFile = options.cookiesFile;
|
|
54
|
+
config.scenario = options.scenario;
|
|
55
|
+
const testPlanner = new e2e_1.TestPlanner();
|
|
56
|
+
const { evalInBrowserAfterInitLoad } = options;
|
|
57
|
+
yield testInBrowser({ testPlanner, config, evalInBrowserAfterInitLoad });
|
|
58
|
+
return {
|
|
59
|
+
config,
|
|
60
|
+
tabsOrder: core_1.utils.loadTabsOrder(),
|
|
61
|
+
metaInfo: core_1.utils.loadRunMetaInfo(),
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
exports.takeSnapshots = takeSnapshots;
|
|
66
|
+
function analyze(runResult, heapAnalyzer, args = { _: [] }) {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
yield heapAnalyzer.run({ args });
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
exports.analyze = analyze;
|
|
72
|
+
function warmup(options = {}) {
|
|
73
|
+
var _a, _b;
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
const config = (_a = options.config) !== null && _a !== void 0 ? _a : core_1.config;
|
|
76
|
+
if (config.verbose) {
|
|
77
|
+
core_1.info.lowLevel(`Xvfb: ${config.useXVFB}`);
|
|
78
|
+
}
|
|
79
|
+
const testPlanner = (_b = options.testPlanner) !== null && _b !== void 0 ? _b : e2e_1.defaultTestPlanner;
|
|
80
|
+
try {
|
|
81
|
+
if (config.skipWarmup) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const browser = yield APIUtils_1.default.getBrowser({ warmup: true });
|
|
85
|
+
const visitPlan = testPlanner.getVisitPlan();
|
|
86
|
+
config.setDevice(visitPlan.device);
|
|
87
|
+
const numOfWarmup = visitPlan.numOfWarmup || 3;
|
|
88
|
+
const promises = [];
|
|
89
|
+
for (let i = 0; i < numOfWarmup; ++i) {
|
|
90
|
+
promises.push(browser.newPage());
|
|
91
|
+
}
|
|
92
|
+
const pages = yield Promise.all(promises);
|
|
93
|
+
core_1.info.beginSection('warmup');
|
|
94
|
+
yield Promise.all(pages.map((page) => __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
yield setupPage(page, { cache: false });
|
|
96
|
+
const interactionManager = new e2e_1.E2EInteractionManager(page);
|
|
97
|
+
yield interactionManager.warmupInPage();
|
|
98
|
+
}))).catch(err => {
|
|
99
|
+
core_1.info.error(err.message);
|
|
100
|
+
});
|
|
101
|
+
core_1.info.endSection('warmup');
|
|
102
|
+
yield core_1.utils.closePuppeteer(browser, pages, { warmup: true });
|
|
103
|
+
}
|
|
104
|
+
catch (ex) {
|
|
105
|
+
const error = core_1.utils.getError(ex);
|
|
106
|
+
core_1.utils.checkUninstalledLibrary(error);
|
|
107
|
+
throw ex;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
exports.warmup = warmup;
|
|
112
|
+
function setupPage(page, options = {}) {
|
|
113
|
+
var _a, _b, _c;
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
const config = (_a = options.config) !== null && _a !== void 0 ? _a : core_1.config;
|
|
116
|
+
const testPlanner = (_b = options.testPlanner) !== null && _b !== void 0 ? _b : e2e_1.defaultTestPlanner;
|
|
117
|
+
if (config.emulateDevice) {
|
|
118
|
+
yield page.emulate(config.emulateDevice);
|
|
119
|
+
}
|
|
120
|
+
if (config.defaultUserAgent) {
|
|
121
|
+
yield page.setUserAgent(config.defaultUserAgent);
|
|
122
|
+
}
|
|
123
|
+
// set login session
|
|
124
|
+
yield page.setCookie(...testPlanner.getCookies());
|
|
125
|
+
const cache = (_c = options.cache) !== null && _c !== void 0 ? _c : true;
|
|
126
|
+
yield page.setCacheEnabled(cache);
|
|
127
|
+
// automatically accept dialog
|
|
128
|
+
page.on('dialog', (dialog) => __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
yield dialog.accept();
|
|
130
|
+
}));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
exports.setupPage = setupPage;
|
|
134
|
+
function autoDismissDialog(page, options = {}) {
|
|
135
|
+
var _a;
|
|
136
|
+
const config = (_a = options.config) !== null && _a !== void 0 ? _a : core_1.config;
|
|
137
|
+
page.on('dialog', (dialog) => __awaiter(this, void 0, void 0, function* () {
|
|
138
|
+
if (config.verbose) {
|
|
139
|
+
core_1.info.lowLevel(`Browser dialog: ${dialog.message()}`);
|
|
140
|
+
}
|
|
141
|
+
yield dialog.dismiss();
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
function initBrowserInfoInConfig(browser, options = {}) {
|
|
145
|
+
var _a;
|
|
146
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
147
|
+
const config = (_a = options.config) !== null && _a !== void 0 ? _a : core_1.config;
|
|
148
|
+
core_1.browserInfo.setPuppeteerConfig(config.puppeteerConfig);
|
|
149
|
+
const version = yield browser.version();
|
|
150
|
+
core_1.browserInfo.setBrowserVersion(version);
|
|
151
|
+
if (config.verbose) {
|
|
152
|
+
core_1.info.lowLevel(JSON.stringify(core_1.browserInfo, null, 2));
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function testInBrowser(options = {}) {
|
|
157
|
+
var _a, _b;
|
|
158
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
159
|
+
const config = (_a = options.config) !== null && _a !== void 0 ? _a : core_1.config;
|
|
160
|
+
if (config.verbose) {
|
|
161
|
+
core_1.info.lowLevel(`Xvfb: ${config.useXVFB}`);
|
|
162
|
+
}
|
|
163
|
+
const testPlanner = (_b = options.testPlanner) !== null && _b !== void 0 ? _b : e2e_1.defaultTestPlanner;
|
|
164
|
+
let interactionManager = null;
|
|
165
|
+
let xvfb = null;
|
|
166
|
+
try {
|
|
167
|
+
xvfb = e2e_1.Xvfb.startIfEnabled();
|
|
168
|
+
const browser = yield APIUtils_1.default.getBrowser();
|
|
169
|
+
const pages = yield browser.pages();
|
|
170
|
+
const page = pages.length > 0 ? pages[0] : yield browser.newPage();
|
|
171
|
+
interactionManager = new e2e_1.E2EInteractionManager(page);
|
|
172
|
+
if (options.evalInBrowserAfterInitLoad) {
|
|
173
|
+
interactionManager.setEvalFuncAfterInitLoad(options.evalInBrowserAfterInitLoad);
|
|
174
|
+
}
|
|
175
|
+
const visitPlan = testPlanner.getVisitPlan();
|
|
176
|
+
config.setDevice(visitPlan.device);
|
|
177
|
+
autoDismissDialog(page);
|
|
178
|
+
yield initBrowserInfoInConfig(browser);
|
|
179
|
+
core_1.browserInfo.monitorWebConsole(page);
|
|
180
|
+
yield setupPage(page, options);
|
|
181
|
+
yield interactionManager.visitAndGetSnapshots(options);
|
|
182
|
+
yield core_1.utils.closePuppeteer(browser, [page]);
|
|
183
|
+
}
|
|
184
|
+
catch (ex) {
|
|
185
|
+
const error = core_1.utils.getError(ex);
|
|
186
|
+
core_1.utils.checkUninstalledLibrary(error);
|
|
187
|
+
core_1.info.error(error.message);
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
if (interactionManager) {
|
|
191
|
+
interactionManager.clearCDPSession();
|
|
192
|
+
}
|
|
193
|
+
if (xvfb) {
|
|
194
|
+
xvfb.stop((err) => {
|
|
195
|
+
if (err) {
|
|
196
|
+
core_1.utils.haltOrThrow(err);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
exports.testInBrowser = testInBrowser;
|
|
@@ -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=E2EBasicAnalysis.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EBasicAnalysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EBasicAnalysis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,65 @@
|
|
|
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 heap_analysis_1 = require("@memlab/heap-analysis");
|
|
24
|
+
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
25
|
+
beforeEach(E2ETestSettings_1.testSetup);
|
|
26
|
+
function inject() {
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
window.injectHookForLink3 = () => {
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
window.__injectedValue3 = {};
|
|
31
|
+
};
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
window.injectHookForLink4 = () => {
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
window.__injectedValue4 = {};
|
|
36
|
+
const __injectedTimeoutValue1 = { v: 0 };
|
|
37
|
+
setTimeout(() => {
|
|
38
|
+
__injectedTimeoutValue1.v = 1;
|
|
39
|
+
}, 1);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
test('E2E SPA test hooks work as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
43
|
+
yield (0, index_1.run)({ scenario: E2ETestSettings_1.scenario, evalInBrowserAfterInitLoad: inject });
|
|
44
|
+
const snapshot = yield heap_analysis_1.PluginUtils.loadHeapSnapshot(E2ETestSettings_1.defaultAnalysisArgs);
|
|
45
|
+
let foundInjectedValueForLink3 = false;
|
|
46
|
+
let foundInjectedValueForLink4 = false;
|
|
47
|
+
let foundInjectedTimeoutValue1 = false;
|
|
48
|
+
snapshot.edges.forEach(e => {
|
|
49
|
+
if (e.name_or_index === '__injectedValue3') {
|
|
50
|
+
foundInjectedValueForLink3 = true;
|
|
51
|
+
}
|
|
52
|
+
if (e.name_or_index === '__injectedValue4') {
|
|
53
|
+
foundInjectedValueForLink4 = true;
|
|
54
|
+
}
|
|
55
|
+
if (e.name_or_index === '__injectedTimeoutValue1') {
|
|
56
|
+
foundInjectedTimeoutValue1 = true;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
// link-3 is not clicked, so injectHookForLink3 is not executed
|
|
60
|
+
expect(foundInjectedValueForLink3).toBe(false);
|
|
61
|
+
// link-4 is clicked, so injectHookForLink3 should be executed
|
|
62
|
+
expect(foundInjectedValueForLink4).toBe(true);
|
|
63
|
+
// __injectedValue is a local variable, which should not be retained
|
|
64
|
+
expect(foundInjectedTimeoutValue1).toBe(false);
|
|
65
|
+
}), 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=E2EDetachedDOMAnalysis.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EDetachedDOMAnalysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EDetachedDOMAnalysis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,49 @@
|
|
|
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 path_1 = __importDefault(require("path"));
|
|
26
|
+
const index_1 = require("../../index");
|
|
27
|
+
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
28
|
+
beforeEach(E2ETestSettings_1.testSetup);
|
|
29
|
+
function inject() {
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
window.injectHookForLink4 = () => {
|
|
32
|
+
// @ts-ignore
|
|
33
|
+
window.__injectedValue = document.createElement('table');
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
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 });
|
|
38
|
+
// test analysis from auto loading
|
|
39
|
+
let analysis = new index_1.DetachedDOMElementAnalysis();
|
|
40
|
+
yield analysis.run();
|
|
41
|
+
let domElems = analysis.getDetachedElements();
|
|
42
|
+
expect(domElems.some(node => node.name === 'Detached HTMLTableElement')).toBe(true);
|
|
43
|
+
// test analysis from file
|
|
44
|
+
const snapshotFile = path_1.default.join(result.config.curDataDir, 's3.heapsnapshot');
|
|
45
|
+
analysis = new index_1.DetachedDOMElementAnalysis();
|
|
46
|
+
yield analysis.analyzeSnapshotFromFile(snapshotFile);
|
|
47
|
+
domElems = analysis.getDetachedElements();
|
|
48
|
+
expect(domElems.some(node => node.name === 'Detached HTMLTableElement')).toBe(true);
|
|
49
|
+
}), 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=E2EDuplicateObjectAnalysis.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EDuplicateObjectAnalysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EDuplicateObjectAnalysis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
const path_1 = __importDefault(require("path"));
|
|
25
|
+
const index_1 = require("../../index");
|
|
26
|
+
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
27
|
+
beforeEach(E2ETestSettings_1.testSetup);
|
|
28
|
+
function inject() {
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
window.injectHookForLink4 = () => {
|
|
32
|
+
const arr = [];
|
|
33
|
+
for (let i = 0; i < 12345; ++i) {
|
|
34
|
+
arr.push({ v: i % 1 });
|
|
35
|
+
}
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
window.__injectedValue = arr;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
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 });
|
|
43
|
+
// test analysis from auto loading
|
|
44
|
+
let analysis = new index_1.ObjectShallowAnalysis();
|
|
45
|
+
yield analysis.run();
|
|
46
|
+
let dupcatedObjectInfo = analysis.getTopDuplicatedObjectInCount();
|
|
47
|
+
expect(dupcatedObjectInfo[0].n).toBe(12345);
|
|
48
|
+
// test analysis from file
|
|
49
|
+
const snapshotFile = path_1.default.join(result.config.curDataDir, 's3.heapsnapshot');
|
|
50
|
+
analysis = new index_1.ObjectShallowAnalysis();
|
|
51
|
+
yield analysis.analyzeSnapshotFromFile(snapshotFile);
|
|
52
|
+
dupcatedObjectInfo = analysis.getTopDuplicatedObjectInCount();
|
|
53
|
+
expect(dupcatedObjectInfo[0].n).toBe(12345);
|
|
54
|
+
}), 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=E2ERunMultipleSnapshots.example.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2ERunMultipleSnapshots.example.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2ERunMultipleSnapshots.example.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const index_1 = require("../../index");
|
|
22
|
+
const scenario = {
|
|
23
|
+
app: () => 'test-spa',
|
|
24
|
+
url: () => '',
|
|
25
|
+
action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
|
|
26
|
+
repeat: () => 4,
|
|
27
|
+
};
|
|
28
|
+
function inject() {
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
window.injectHookForLink4 = () => {
|
|
31
|
+
class LeakObject {
|
|
32
|
+
constructor() {
|
|
33
|
+
this.value = `value: ${Math.random()}`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
const leak = (window.__injectedValue = window.__injectedValue || []);
|
|
38
|
+
for (let i = 0; i < 10000; ++i) {
|
|
39
|
+
leak.push(new LeakObject());
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const promise = (0, index_1.run)({
|
|
44
|
+
scenario,
|
|
45
|
+
evalInBrowserAfterInitLoad: inject,
|
|
46
|
+
snapshotForEachStep: true,
|
|
47
|
+
});
|
|
48
|
+
promise.then(() => {
|
|
49
|
+
// test analysis from auto loading
|
|
50
|
+
const analysis = new index_1.ShapeUnboundGrowthAnalysis();
|
|
51
|
+
analysis.run();
|
|
52
|
+
});
|
|
@@ -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=E2ERunSingleSnapshot.example.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2ERunSingleSnapshot.example.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2ERunSingleSnapshot.example.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
const path_1 = __importDefault(require("path"));
|
|
25
|
+
const index_1 = require("../../index");
|
|
26
|
+
const scenario = {
|
|
27
|
+
app: () => 'test-spa',
|
|
28
|
+
url: () => '',
|
|
29
|
+
action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
|
|
30
|
+
};
|
|
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
|
+
});
|
|
@@ -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=E2EShapeUnboundGrowthAnalysis.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EShapeUnboundGrowthAnalysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EShapeUnboundGrowthAnalysis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,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 path_1 = __importDefault(require("path"));
|
|
26
|
+
const index_1 = require("../../index");
|
|
27
|
+
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
28
|
+
beforeEach(E2ETestSettings_1.testSetup);
|
|
29
|
+
function inject() {
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
window.injectHookForLink4 = () => {
|
|
32
|
+
function LeakObject() {
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
this.value = `value: ${Math.random()}`;
|
|
35
|
+
}
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
const leak = (window.__injectedValue = window.__injectedValue || []);
|
|
38
|
+
for (let i = 0; i < 10000; ++i) {
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
leak.push(new LeakObject());
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
test('Shape unbound analysis works as expected', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
45
|
+
const repeatScenario = Object.assign({ repeat: () => 2 }, E2ETestSettings_1.scenario);
|
|
46
|
+
// test analysis from auto loading
|
|
47
|
+
const result = yield (0, index_1.run)({
|
|
48
|
+
scenario: repeatScenario,
|
|
49
|
+
evalInBrowserAfterInitLoad: inject,
|
|
50
|
+
snapshotForEachStep: true,
|
|
51
|
+
});
|
|
52
|
+
// test analysis from auto loading
|
|
53
|
+
let analysis = new index_1.ShapeUnboundGrowthAnalysis();
|
|
54
|
+
let shapeSummary = yield analysis.run();
|
|
55
|
+
expect(shapeSummary.reduce((acc, summary) => acc || summary.shape.includes('LeakObject'), false)).toBe(true);
|
|
56
|
+
// test analysis from file
|
|
57
|
+
const snapshotDir = path_1.default.join(result.config.curDataDir);
|
|
58
|
+
analysis = new index_1.ShapeUnboundGrowthAnalysis();
|
|
59
|
+
shapeSummary = yield analysis.analyzeSnapshotsInDirectory(snapshotDir);
|
|
60
|
+
expect(shapeSummary.some((summary) => summary.shape.includes('LeakObject'))).toBe(true);
|
|
61
|
+
// expect incorrect use of heap analysis to throw
|
|
62
|
+
const snapshotFile = path_1.default.join(result.config.curDataDir, 's3.heapsnapshot');
|
|
63
|
+
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);
|
|
72
|
+
}), E2ETestSettings_1.testTimeout);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @emails oncall+ws_labs
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=E2EStringAnalysis.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EStringAnalysis.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/API/E2EStringAnalysis.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,66 @@
|
|
|
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 path_1 = __importDefault(require("path"));
|
|
26
|
+
const index_1 = require("../../index");
|
|
27
|
+
const E2ETestSettings_1 = require("./lib/E2ETestSettings");
|
|
28
|
+
beforeEach(E2ETestSettings_1.testSetup);
|
|
29
|
+
function inject() {
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
window.injectHookForLink4 = () => {
|
|
32
|
+
const arr = [];
|
|
33
|
+
for (let i = 0; i < 10000; ++i) {
|
|
34
|
+
arr.push('duplicated string value' + (i % 1));
|
|
35
|
+
}
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
window.__injectedValue = arr;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
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 });
|
|
42
|
+
// test analysis from auto loading
|
|
43
|
+
let analysis = new index_1.StringAnalysis();
|
|
44
|
+
yield analysis.run();
|
|
45
|
+
let dupStrings = analysis.getTopDuplicatedStringsInCount();
|
|
46
|
+
expect(dupStrings[0].n).toBe(10000);
|
|
47
|
+
expect(dupStrings[0].str).toBe('duplicated string value0');
|
|
48
|
+
// test analysis from file
|
|
49
|
+
const snapshotFile = path_1.default.join(result.config.curDataDir, 's3.heapsnapshot');
|
|
50
|
+
analysis = new index_1.StringAnalysis();
|
|
51
|
+
yield analysis.analyzeSnapshotFromFile(snapshotFile);
|
|
52
|
+
dupStrings = analysis.getTopDuplicatedStringsInCount();
|
|
53
|
+
expect(dupStrings[0].n).toBe(10000);
|
|
54
|
+
expect(dupStrings[0].str).toBe('duplicated string value0');
|
|
55
|
+
// expect incorrect use of heap analysis to throw
|
|
56
|
+
const snapshotDir = result.config.curDataDir;
|
|
57
|
+
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);
|
|
66
|
+
}), E2ETestSettings_1.testTimeout);
|
|
@@ -0,0 +1,23 @@
|
|
|
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 { Page } from 'puppeteer';
|
|
11
|
+
export declare const testTimeout: number;
|
|
12
|
+
export declare const defaultAnalysisArgs: {
|
|
13
|
+
args: {
|
|
14
|
+
_: never[];
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export declare const scenario: {
|
|
18
|
+
app: () => string;
|
|
19
|
+
url: () => string;
|
|
20
|
+
action: (page: Page) => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
export declare const testSetup: () => void;
|
|
23
|
+
//# sourceMappingURL=E2ETestSettings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2ETestSettings.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/API/lib/E2ETestSettings.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAGpC,eAAO,MAAM,WAAW,QAAgB,CAAC;AAEzC,eAAO,MAAM,mBAAmB;;;;CAAkB,CAAC;AAEnD,eAAO,MAAM,QAAQ;eACV,MAAM;eACN,MAAM;mBACM,IAAI,KAAG,QAAQ,IAAI,CAAC;CAE1C,CAAC;AAEF,eAAO,MAAM,SAAS,QAAO,IAK5B,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.testSetup = exports.scenario = exports.defaultAnalysisArgs = exports.testTimeout = void 0;
|
|
22
|
+
const core_1 = require("@memlab/core");
|
|
23
|
+
exports.testTimeout = 5 * 60 * 1000;
|
|
24
|
+
exports.defaultAnalysisArgs = { args: { _: [] } };
|
|
25
|
+
exports.scenario = {
|
|
26
|
+
app: () => 'test-spa',
|
|
27
|
+
url: () => '',
|
|
28
|
+
action: (page) => __awaiter(void 0, void 0, void 0, function* () { return yield page.click('[data-testid="link-4"]'); }),
|
|
29
|
+
};
|
|
30
|
+
const testSetup = () => {
|
|
31
|
+
core_1.config.isTest = true;
|
|
32
|
+
core_1.config.useXVFB = false;
|
|
33
|
+
core_1.config.skipExtraOps = true;
|
|
34
|
+
core_1.config.errorHandling = core_1.ErrorHandling.Throw;
|
|
35
|
+
};
|
|
36
|
+
exports.testSetup = testSetup;
|
|
@@ -0,0 +1,16 @@
|
|
|
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 { AnyValue } from '@memlab/core';
|
|
11
|
+
declare global {
|
|
12
|
+
interface Window {
|
|
13
|
+
injected: AnyValue;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=E2EHeapParser.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"E2EHeapParser.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/heap/E2EHeapParser.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,QAAQ,EAA2B,MAAM,cAAc,CAAC;AAOrE,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,QAAQ,EAAE,QAAQ,CAAC;KACpB;CACF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*
|
|
8
|
+
* @emails oncall+ws_labs
|
|
9
|
+
* @format
|
|
10
|
+
*/
|
|
11
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
12
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
13
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
14
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
15
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
16
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
17
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
const HeapParserTestUtils_1 = require("./lib/HeapParserTestUtils");
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
core_1.config.isTest = true;
|
|
25
|
+
});
|
|
26
|
+
const timeout = 5 * 60 * 1000;
|
|
27
|
+
test('Capture numeric value from heap in browser', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
28
|
+
const leakInjector = () => {
|
|
29
|
+
class TestObject {
|
|
30
|
+
constructor() {
|
|
31
|
+
this.numProp = 0.1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
window.injected = new TestObject();
|
|
35
|
+
};
|
|
36
|
+
const checker = (snapshot) => {
|
|
37
|
+
let detected = false;
|
|
38
|
+
snapshot.nodes.forEach((node) => {
|
|
39
|
+
if (node.name !== 'TestObject' || node.type !== 'object') {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const refs = node.references;
|
|
43
|
+
for (const ref of refs) {
|
|
44
|
+
if (ref.name_or_index === 'numProp') {
|
|
45
|
+
const node = ref.toNode;
|
|
46
|
+
if (node.type === 'number' &&
|
|
47
|
+
core_1.utils.getNumberNodeValue(node) === 0.1) {
|
|
48
|
+
detected = true;
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
return detected;
|
|
55
|
+
};
|
|
56
|
+
yield (0, HeapParserTestUtils_1.isExpectedSnapshot)(leakInjector, checker);
|
|
57
|
+
}), timeout);
|
|
@@ -0,0 +1,12 @@
|
|
|
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 { IHeapSnapshot } from '@memlab/core';
|
|
11
|
+
export declare function isExpectedSnapshot(leakInjector: () => void, checkSnapshotCb: (snapshot: IHeapSnapshot) => boolean): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=HeapParserTestUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HeapParserTestUtils.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/heap/lib/HeapParserTestUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAC,MAAM,cAAc,CAAC;AAUhD,wBAAsB,kBAAkB,CACtC,YAAY,EAAE,MAAM,IAAI,EACxB,eAAe,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,OAAO,GACpD,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
|
@@ -0,0 +1,99 @@
|
|
|
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
|
+
exports.isExpectedSnapshot = void 0;
|
|
25
|
+
const fs_1 = __importDefault(require("fs"));
|
|
26
|
+
const path_1 = __importDefault(require("path"));
|
|
27
|
+
const core_1 = require("@memlab/core");
|
|
28
|
+
const puppeteer = core_1.config.isFB
|
|
29
|
+
? require('puppeteer-core')
|
|
30
|
+
: require('puppeteer');
|
|
31
|
+
function isExpectedSnapshot(leakInjector, checkSnapshotCb) {
|
|
32
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
const snapshot = yield getHeapSnapshot(leakInjector);
|
|
34
|
+
expect(checkSnapshotCb(snapshot)).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
exports.isExpectedSnapshot = isExpectedSnapshot;
|
|
38
|
+
function getHeapDirPrefix() {
|
|
39
|
+
const dir = path_1.default.join(core_1.config.dataBaseDir, 'gen-files');
|
|
40
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
41
|
+
fs_1.default.mkdirSync(dir);
|
|
42
|
+
}
|
|
43
|
+
return dir;
|
|
44
|
+
}
|
|
45
|
+
function saveSnapshotToFile(page, file) {
|
|
46
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
47
|
+
core_1.info.lowLevel(`saving heap snapshot to file ${file}`);
|
|
48
|
+
let heap = '';
|
|
49
|
+
const devtoolsProtocolClient = yield page.target().createCDPSession();
|
|
50
|
+
devtoolsProtocolClient.on('HeapProfiler.addHeapSnapshotChunk', data => {
|
|
51
|
+
heap += data.chunk;
|
|
52
|
+
});
|
|
53
|
+
yield devtoolsProtocolClient.send('HeapProfiler.takeHeapSnapshot', {
|
|
54
|
+
reportProgress: false,
|
|
55
|
+
captureNumericValue: true,
|
|
56
|
+
});
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
fs_1.default.writeFile(file, heap, 'UTF-8', err => {
|
|
59
|
+
if (err) {
|
|
60
|
+
reject(err);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
resolve();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const TEST_URL = 'about:blank';
|
|
70
|
+
function dumpHeap(snapshotFile, leakInjector) {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
const browser = yield puppeteer.launch(core_1.config.puppeteerConfig);
|
|
73
|
+
const page = yield browser.newPage();
|
|
74
|
+
// set page size
|
|
75
|
+
yield page.setViewport({
|
|
76
|
+
width: 1680,
|
|
77
|
+
height: 1050,
|
|
78
|
+
deviceScaleFactor: 1,
|
|
79
|
+
});
|
|
80
|
+
// visit page
|
|
81
|
+
yield page.goto(TEST_URL);
|
|
82
|
+
// insert a memory leak object
|
|
83
|
+
yield page.evaluate(leakInjector);
|
|
84
|
+
// take a heap snapshot
|
|
85
|
+
yield saveSnapshotToFile(page, snapshotFile);
|
|
86
|
+
yield browser.close();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
let fileId = 0;
|
|
90
|
+
function getHeapSnapshot(leakInjector) {
|
|
91
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
92
|
+
const snapshotFile = path_1.default.join(getHeapDirPrefix(), `snapshot-${Date.now()}-${fileId++}.json`);
|
|
93
|
+
yield dumpHeap(snapshotFile, leakInjector);
|
|
94
|
+
// parse the heap
|
|
95
|
+
const opt = { buildNodeIdIndex: true };
|
|
96
|
+
const snapshot = yield core_1.utils.getSnapshotFromFile(snapshotFile, opt);
|
|
97
|
+
return snapshot;
|
|
98
|
+
});
|
|
99
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
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 * from './API';
|
|
11
|
+
export * from '@memlab/heap-analysis';
|
|
12
|
+
export { config } from '@memlab/core';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
23
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.config = void 0;
|
|
27
|
+
__exportStar(require("./API"), exports);
|
|
28
|
+
__exportStar(require("@memlab/heap-analysis"), exports);
|
|
29
|
+
var core_1 = require("@memlab/core");
|
|
30
|
+
Object.defineProperty(exports, "config", { enumerable: true, get: function () { return core_1.config; } });
|
|
@@ -0,0 +1,20 @@
|
|
|
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 { Browser } from 'puppeteer';
|
|
11
|
+
import type { MemLabConfig } from '@memlab/core';
|
|
12
|
+
declare function getBrowser(options?: {
|
|
13
|
+
config?: MemLabConfig;
|
|
14
|
+
warmup?: boolean;
|
|
15
|
+
}): Promise<Browser>;
|
|
16
|
+
declare const _default: {
|
|
17
|
+
getBrowser: typeof getBrowser;
|
|
18
|
+
};
|
|
19
|
+
export default _default;
|
|
20
|
+
//# sourceMappingURL=APIUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"APIUtils.d.ts","sourceRoot":"","sources":["../../src/lib/APIUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AACvC,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,cAAc,CAAC;AAU/C,iBAAe,UAAU,CACvB,OAAO,GAAE;IAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAM,GACtD,OAAO,CAAC,OAAO,CAAC,CAmBlB;;;;AAED,wBAEE"}
|
|
@@ -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
|
+
const core_1 = require("@memlab/core");
|
|
22
|
+
const puppeteer = core_1.constant.isFRL
|
|
23
|
+
? {}
|
|
24
|
+
: core_1.constant.isFB
|
|
25
|
+
? require('puppeteer-core')
|
|
26
|
+
: require('puppeteer');
|
|
27
|
+
function getBrowser(options = {}) {
|
|
28
|
+
var _a;
|
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
const runConfig = (_a = options.config) !== null && _a !== void 0 ? _a : core_1.config;
|
|
31
|
+
let browser;
|
|
32
|
+
if (runConfig.isLocalPuppeteer && !options.warmup) {
|
|
33
|
+
try {
|
|
34
|
+
browser = yield puppeteer.connect(Object.assign({ browserURL: `http://localhost:${runConfig.localBrowserPort}` }, runConfig.puppeteerConfig));
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
throw core_1.utils.haltOrThrow(core_1.utils.getError(e), {
|
|
38
|
+
primaryMessageToPrint: 'Failed to connect to local browser. Ensure that the local-puppeteer script is running.',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
browser = yield puppeteer.launch(runConfig.puppeteerConfig);
|
|
44
|
+
}
|
|
45
|
+
return browser;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
exports.default = {
|
|
49
|
+
getBrowser,
|
|
50
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@memlab/api",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "API of memlab",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"api"
|
|
7
|
+
],
|
|
8
|
+
"author": "Liang Gong <lgong@fb.com>",
|
|
9
|
+
"contributors": [],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@memlab/core": "^1.0.0",
|
|
21
|
+
"@memlab/e2e": "^1.0.0",
|
|
22
|
+
"@memlab/heap-analysis": "^1.0.0",
|
|
23
|
+
"ansi": "^0.3.1",
|
|
24
|
+
"babar": "^0.2.0",
|
|
25
|
+
"chalk": "^4.0.0",
|
|
26
|
+
"fs-extra": "^4.0.2",
|
|
27
|
+
"minimist": "^1.2.0",
|
|
28
|
+
"puppeteer": "^13.5.1",
|
|
29
|
+
"string-width": "^4.2.0",
|
|
30
|
+
"util.promisify": "^1.1.1",
|
|
31
|
+
"xvfb": "^0.4.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/fs-extra": "^9.0.3",
|
|
35
|
+
"@types/jest": "^27.4.1",
|
|
36
|
+
"@types/minimist": "^1.2.2",
|
|
37
|
+
"@types/node": "^12.16.3",
|
|
38
|
+
"@types/puppeteer": "^5.4.4",
|
|
39
|
+
"jest": "^27.5.1",
|
|
40
|
+
"ts-jest": "^27.1.4",
|
|
41
|
+
"typescript": "^4.6.3"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/facebookincubator/memlab.git",
|
|
46
|
+
"directory": "packages/api"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build-pkg": "tsc",
|
|
50
|
+
"test-pkg": "jest .",
|
|
51
|
+
"clean-pkg": "rm -rf ./dist && rm -rf ./node_modules && rm -f ./tsconfig.tsbuildinfo"
|
|
52
|
+
},
|
|
53
|
+
"bugs": {
|
|
54
|
+
"url": "https://github.com/facebookincubator/memlab/issues"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://github.com/facebookincubator/memlab#readme"
|
|
57
|
+
}
|