@memlab/e2e 1.0.19 → 1.0.21

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.
@@ -7,21 +7,24 @@
7
7
  * @format
8
8
  * @oncall web_perf_infra
9
9
  */
10
- import type { AnyFunction, OperationArgs, MemLabConfig } from '@memlab/core';
11
- import type { CDPSession, Page } from 'puppeteer';
10
+ import type { Browser, CDPSession, Page, Target } from 'puppeteer';
11
+ import type { AnyFunction, Nullable, OperationArgs, MemLabConfig } from '@memlab/core';
12
12
  import { TestPlanner } from './lib/operations/TestPlanner';
13
13
  declare type PageInteractOptions = {
14
14
  config?: MemLabConfig;
15
15
  testPlanner?: TestPlanner;
16
16
  };
17
17
  export default class E2EInteractionManager {
18
- private cdpsession;
18
+ private mainThreadCdpsession;
19
19
  private page;
20
+ private browser;
20
21
  private pageHistoryLength;
21
22
  private evalFuncAfterInitLoad;
22
23
  private networkManager;
23
- constructor(page: Page);
24
- getCDPSession(): Promise<CDPSession>;
24
+ constructor(page: Page, browser: Browser);
25
+ getChosenCDPSession(): Promise<CDPSession>;
26
+ getMainThreadCDPSession(): Promise<CDPSession>;
27
+ selectCDPSession(predicate: (t: Target) => boolean): Promise<Nullable<CDPSession>>;
25
28
  clearCDPSession(): void;
26
29
  setEvalFuncAfterInitLoad(func: AnyFunction | null): void;
27
30
  protected initialLoad(page: Page, url: string, opArgs?: OperationArgs): Promise<void>;
@@ -35,7 +38,7 @@ export default class E2EInteractionManager {
35
38
  private writeSnapshotFileFromCDPSession;
36
39
  private saveHeapSnapshotToFile;
37
40
  private fullGC;
38
- private forceGC;
41
+ private forceMainThreadGC;
39
42
  private collectMetrics;
40
43
  }
41
44
  export {};
@@ -30,23 +30,56 @@ const TestPlanner_1 = __importDefault(require("./lib/operations/TestPlanner"));
30
30
  const NetworkManager_1 = __importDefault(require("./NetworkManager"));
31
31
  const { logMetaData, setPermissions, logTabProgress, maybeWaitForConsoleInput, applyAsyncWithRetry, compareURL, waitExtraForTab, checkURL, injectPageReloadChecker, checkPageReload, dispatchOperation, clearConsole, getNavigationHistoryLength, checkLastSnapshotChunk, getURLParameter, } = E2EUtils_1.default;
32
32
  class E2EInteractionManager {
33
- constructor(page) {
33
+ constructor(page, browser) {
34
34
  this.pageHistoryLength = [];
35
35
  this.evalFuncAfterInitLoad = null;
36
36
  this.page = page;
37
+ this.browser = browser;
37
38
  this.networkManager = new NetworkManager_1.default(page);
38
39
  }
39
- getCDPSession() {
40
+ getChosenCDPSession() {
40
41
  return __awaiter(this, void 0, void 0, function* () {
41
- if (!this.cdpsession) {
42
- this.cdpsession = yield this.page.target().createCDPSession();
43
- this.networkManager.setCDPSession(this.cdpsession);
42
+ if (core_1.config.isAnalyzingMainThread) {
43
+ return this.getMainThreadCDPSession();
44
+ }
45
+ // get web worker thread target
46
+ const cdpSession = yield this.selectCDPSession(target => {
47
+ var _a, _b;
48
+ const t = target;
49
+ const isWorker = ((_a = t._targetInfo) === null || _a === void 0 ? void 0 : _a.type) === 'worker';
50
+ let isTitleMatch = true;
51
+ if (core_1.config.targetWorkerTitle != null) {
52
+ isTitleMatch = ((_b = t._targetInfo) === null || _b === void 0 ? void 0 : _b.title) === core_1.config.targetWorkerTitle;
53
+ }
54
+ return isWorker && isTitleMatch;
55
+ });
56
+ if (cdpSession == null) {
57
+ throw core_1.utils.haltOrThrow('web worker or main thread heap under analysis not found');
58
+ }
59
+ return cdpSession;
60
+ });
61
+ }
62
+ getMainThreadCDPSession() {
63
+ return __awaiter(this, void 0, void 0, function* () {
64
+ if (!this.mainThreadCdpsession) {
65
+ this.mainThreadCdpsession = yield this.page.target().createCDPSession();
66
+ this.networkManager.setCDPSession(this.mainThreadCdpsession);
67
+ }
68
+ return this.mainThreadCdpsession;
69
+ });
70
+ }
71
+ selectCDPSession(predicate) {
72
+ return __awaiter(this, void 0, void 0, function* () {
73
+ const targets = yield this.browser.targets();
74
+ const target = targets.find(predicate);
75
+ if (!target) {
76
+ return null;
44
77
  }
45
- return this.cdpsession;
78
+ return yield target.createCDPSession();
46
79
  });
47
80
  }
48
81
  clearCDPSession() {
49
- this.cdpsession = null;
82
+ this.mainThreadCdpsession = null;
50
83
  }
51
84
  setEvalFuncAfterInitLoad(func) {
52
85
  this.evalFuncAfterInitLoad = func;
@@ -73,7 +106,8 @@ class E2EInteractionManager {
73
106
  }
74
107
  beforeInteractions() {
75
108
  return __awaiter(this, void 0, void 0, function* () {
76
- const session = yield this.getCDPSession();
109
+ // tracking main thread for network interception
110
+ const session = yield this.getMainThreadCDPSession();
77
111
  if (core_1.config.interceptScript) {
78
112
  this.networkManager.setCDPSession(session);
79
113
  yield this.networkManager.interceptScript();
@@ -270,7 +304,7 @@ class E2EInteractionManager {
270
304
  if (core_1.config.verbose) {
271
305
  core_1.info.lowLevel('Start tracking JS heap');
272
306
  }
273
- const session = yield this.getCDPSession();
307
+ const session = yield this.getMainThreadCDPSession();
274
308
  yield session.send('HeapProfiler.enable');
275
309
  });
276
310
  }
@@ -305,7 +339,7 @@ class E2EInteractionManager {
305
339
  return __awaiter(this, void 0, void 0, function* () {
306
340
  core_1.info.beginSection('heap snapshot');
307
341
  const start = Date.now();
308
- const session = yield this.getCDPSession();
342
+ const session = yield this.getChosenCDPSession();
309
343
  yield this.writeSnapshotFileFromCDPSession(file, session);
310
344
  const spanMs = Date.now() - start;
311
345
  if (core_1.config.verbose) {
@@ -328,12 +362,12 @@ class E2EInteractionManager {
328
362
  core_1.info.overwrite('running a full GC...');
329
363
  }
330
364
  // force GC 6 times to release feedback_cells
331
- yield this.forceGC(6);
365
+ yield this.forceMainThreadGC(6);
332
366
  });
333
367
  }
334
- forceGC(repeat = 1) {
368
+ forceMainThreadGC(repeat = 1) {
335
369
  return __awaiter(this, void 0, void 0, function* () {
336
- const client = yield this.getCDPSession();
370
+ const client = yield this.getMainThreadCDPSession();
337
371
  for (let i = 0; i < repeat; i++) {
338
372
  yield client.send('HeapProfiler.collectGarbage');
339
373
  // wait for a while and let GC do the job
@@ -351,7 +385,7 @@ class E2EInteractionManager {
351
385
  if (!core_1.config.runningMode.shouldGetMetrics(tabInfo)) {
352
386
  return;
353
387
  }
354
- yield this.forceGC();
388
+ yield this.forceMainThreadGC();
355
389
  // collect heap size
356
390
  const builtInMetrics = yield this.page.metrics();
357
391
  const size = core_1.utils.getReadableBytes(builtInMetrics.JSHeapUsedSize);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memlab/e2e",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "license": "MIT",
5
5
  "description": "memlab browser E2E interaction libraries",
6
6
  "author": "Liang Gong <lgong@fb.com>",
@@ -1,18 +1,41 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <link rel="icon" href="/favicon.ico" />
6
- <meta name="viewport" content="width=device-width,initial-scale=1" />
7
- <meta name="theme-color" content="#000000" />
8
- <meta
9
- name="description"
10
- content="Web page for e2e tests"
11
- />
12
- <title>React App</title>
13
- <script defer="defer" src="min.js"></script>
14
- </head>
15
- <body>
16
- <div id="root"></div>
17
- </body>
3
+
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <link rel="icon" href="/favicon.ico" />
7
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
8
+ <meta name="theme-color" content="#000000" />
9
+ <meta name="description" content="Web page for e2e tests" />
10
+ <title>React App</title>
11
+ <script>
12
+ // create a web worker
13
+ var blobURL = URL.createObjectURL(
14
+ new Blob(
15
+ [
16
+ '(',
17
+ function () {
18
+ function WorkerTestObject() {
19
+ this.idx = Math.random();
20
+ }
21
+ setInterval(() => {
22
+ self.holder = self.holder || [];
23
+ self.holder.push(new WorkerTestObject());
24
+ }, 5);
25
+ }.toString(),
26
+ ')()',
27
+ ],
28
+ { type: 'application/javascript' },
29
+ ),
30
+ );
31
+ var worker = new Worker(blobURL, {name: 'test-worker'});
32
+ URL.revokeObjectURL(blobURL);
33
+ </script>
34
+ <script defer="defer" src="min.js"></script>
35
+ </head>
36
+
37
+ <body>
38
+ <div id="root"></div>
39
+ </body>
40
+
18
41
  </html>