@memlab/e2e 1.0.2 → 1.0.5

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 CHANGED
@@ -3,5 +3,6 @@
3
3
  This is the memlab E2E testing framework for headless/headful Chromium. It is mainly responsible
4
4
  for controling/interacting with browser, recording heap snapshots, and logging other execution meta data.
5
5
 
6
- ## Full documentation
7
- https://facebookincubator.github.io/memlab
6
+ ## Online Resources
7
+ * [Official Website and Demo](https://facebookincubator.github.io/memlab)
8
+ * [Documentation](https://facebookincubator.github.io/memlab/docs/intro)
@@ -31,6 +31,7 @@ export declare class TestPlanner {
31
31
  private prepareSynthesizer;
32
32
  private generateVisitPlan;
33
33
  loadCookies(visitPlan: IE2EScenarioVisitPlan, synthesizer: IE2EScenarioSynthesizer): Cookies;
34
+ private populateDomainInCookiesFromScenario;
34
35
  private populateDomainInCookies;
35
36
  private setSnapshotMode;
36
37
  private assignSnapshotIds;
@@ -107,7 +107,8 @@ class TestPlanner {
107
107
  loadCookies(visitPlan, synthesizer) {
108
108
  var _a;
109
109
  if (this.scenario && this.scenario.cookies) {
110
- return this.scenario.cookies();
110
+ const cookies = this.scenario.cookies();
111
+ return this.populateDomainInCookiesFromScenario(cookies, this.scenario);
111
112
  }
112
113
  let cookieFile = synthesizer.getCookieFile(visitPlan);
113
114
  // if no cookie file is specified
@@ -122,6 +123,20 @@ class TestPlanner {
122
123
  const cookies = JSON.parse(fs_1.default.readFileSync(cookieFile, 'UTF-8'));
123
124
  return this.populateDomainInCookies(cookies, synthesizer.getDomain(), synthesizer.getDomainPrefixes());
124
125
  }
126
+ populateDomainInCookiesFromScenario(cookies, scenario) {
127
+ const ret = [];
128
+ const url = new URL(scenario.url());
129
+ const domain = '.' + url.hostname.split('.').slice(1).join('.');
130
+ for (const cookie of cookies) {
131
+ if (cookie.domain) {
132
+ ret.push(Object.assign({}, cookie));
133
+ }
134
+ else {
135
+ ret.push(Object.assign(Object.assign({}, cookie), { domain }));
136
+ }
137
+ }
138
+ return ret;
139
+ }
125
140
  populateDomainInCookies(cookies, domain, domainPrefixes) {
126
141
  const cookiesTemplate = cookies;
127
142
  const ret = [];
@@ -53,7 +53,10 @@ class DefaultScenarioSynthesizer extends BaseSynthesizer_1.default {
53
53
  getPageLoadChecker() {
54
54
  return (page) => __awaiter(this, void 0, void 0, function* () {
55
55
  yield InteractionUtils_1.default.waitFor(500);
56
- yield page.waitForNavigation({ waitUntil: 'networkidle0' });
56
+ yield page.waitForNavigation({
57
+ waitUntil: 'networkidle0',
58
+ timeout: this.config.waitForNetworkInDefaultScenario,
59
+ });
57
60
  return true;
58
61
  });
59
62
  }
@@ -36,6 +36,6 @@ function back(page) {
36
36
  }
37
37
  // specify the number of repeat for the action
38
38
  function repeat() {
39
- return 15;
39
+ return 1;
40
40
  }
41
41
  module.exports = { action, back, repeat, url };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memlab/e2e",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
4
4
  "license": "MIT",
5
5
  "description": "memlab browser E2E interaction libraries",
6
6
  "author": "Liang Gong <lgong@fb.com>",
@@ -48,6 +48,7 @@
48
48
  },
49
49
  "scripts": {
50
50
  "build-pkg": "tsc",
51
+ "publish-patch": "npm version patch --force && npm publish",
51
52
  "clean-pkg": "rm -rf ./dist && rm -rf ./node_modules && rm -f ./tsconfig.tsbuildinfo"
52
53
  },
53
54
  "bugs": {
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @emails oncall+ws_labs
8
8
  * @format
9
+ * @oncall ws_labs
9
10
  */
10
11
 
11
12
  import Layout from '../components/layout.jsx';
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @emails oncall+ws_labs
8
8
  * @format
9
+ * @oncall ws_labs
9
10
  */
10
11
 
11
12
  import {Head, Html, Main, NextScript} from 'next/document';
@@ -2,14 +2,17 @@
2
2
  import Link from 'next/link';
3
3
  import React, {useEffect} from 'react';
4
4
 
5
- export default function UnboundObject() {
5
+ export default function OversizedObject() {
6
6
  const bigArray = Array(1024 * 1024 * 2).fill(0);
7
7
 
8
8
  const eventHandler = () => {
9
- console.log('Does something with with hugeObject', bigArray);
9
+ // the eventHandler closure keeps a reference
10
+ // to the bigArray in the outter scope
11
+ console.log('Using hugeObject', bigArray);
10
12
  };
11
13
 
12
14
  useEffect(() => {
15
+ // eventHandler is never unregistered
13
16
  window.addEventListener('custom-click', eventHandler);
14
17
  }, []);
15
18
 
@@ -18,7 +21,7 @@ export default function UnboundObject() {
18
21
  <div className="row">
19
22
  <Link href="/">Go back</Link>
20
23
  </div>
21
- <br />
24
+ <br/>
22
25
  <div className="row">
23
26
  Object<code>bigArray</code>is leaked. Please check <code>Memory</code>{' '}
24
27
  tab in devtools
@@ -6,6 +6,7 @@
6
6
  *
7
7
  * @emails oncall+ws_labs
8
8
  * @format
9
+ * @oncall ws_labs
9
10
  */
10
11
 
11
12
  import Link from 'next/link';
@@ -24,7 +25,7 @@ export default function Home() {
24
25
  <p>Detached DOM element</p>
25
26
  </div>
26
27
  <div className="col-md-3">
27
- <Link href="/examples/unbound-object">
28
+ <Link href="/examples/oversized-object">
28
29
  <a>
29
30
  <h2>Example 2 &rarr;</h2>
30
31
  </a>
@@ -11,28 +11,30 @@ function url() {
11
11
  * Specify how memlab should perform action that you want
12
12
  * to test whether the action is causing memory leak.
13
13
  *
14
- * @param page - Puppeteer's [page object](https://pptr.dev/api/puppeteer.page/).
14
+ * @param page - Puppeteer's page object:
15
+ * https://pptr.dev/api/puppeteer.page/
15
16
  */
16
17
  async function action(page) {
17
- const [button] = await page.$x(
18
+ const elements = await page.$x(
18
19
  "//button[contains(., 'Create detached DOMs')]"
19
20
  );
21
+ const [button] = elements;
20
22
  if (button) {
21
23
  await button.click();
22
24
  }
25
+ // clean up external references from memlab
26
+ await Promise.all(elements.map(e => e.dispose()));
23
27
  }
24
28
 
25
29
  /**
26
30
  * Specify how memlab should perform action that would
27
31
  * reset the action you performed above.
28
32
  *
29
- * @param page - Puppeteer's [page object](https://pptr.dev/api/puppeteer.page/).
33
+ * @param page - Puppeteer's page object:
34
+ * https://pptr.dev/api/puppeteer.page/
30
35
  */
31
36
  async function back(page) {
32
- const [button] = await page.$x('a[href="/"]');
33
- if (button) {
34
- await button.click();
35
- }
37
+ await page.click('a[href="/"]');
36
38
  }
37
39
 
38
40
  module.exports = { action, back, url };
@@ -0,0 +1,9 @@
1
+ /* @nolint */
2
+
3
+ // leakFilter is called with each object (node) in browser
4
+ // allocated by `action` but not released after the `back` call
5
+ function leakFilter(node, _snapshot, _leakedNodeIds) {
6
+ return node.retainedSize > 1000 * 1000;
7
+ }
8
+
9
+ module.exports = { leakFilter };
@@ -0,0 +1,23 @@
1
+ /* @nolint */
2
+
3
+ function url() {
4
+ return 'http://localhost:3000/';
5
+ }
6
+
7
+ // action where you suspect the memory leak might be happening
8
+ async function action(page) {
9
+ await page.click('a[href="/examples/oversized-object"]');
10
+ }
11
+
12
+ // how to go back to the state before actionw
13
+ async function back(page) {
14
+ await page.click('a[href="/"]');
15
+ }
16
+
17
+ // leakFilter is called with each object (node) in browser
18
+ // allocated by `action` but not released after the `back` call
19
+ function leakFilter(node, _snapshot, _leakedNodeIds) {
20
+ return node.retainedSize > 1000 * 1000;
21
+ }
22
+
23
+ module.exports = { action, back, leakFilter, url };
@@ -0,0 +1,17 @@
1
+ /* @nolint */
2
+
3
+ function url() {
4
+ return 'http://localhost:3000/';
5
+ }
6
+
7
+ // action where you suspect the memory leak might be happening
8
+ async function action(page) {
9
+ await page.click('a[href="/examples/oversized-object"]');
10
+ }
11
+
12
+ // how to go back to the state before actionw
13
+ async function back(page) {
14
+ await page.click('a[href="/"]');
15
+ }
16
+
17
+ module.exports = { action, back, url };
@@ -11,7 +11,7 @@
11
11
 
12
12
  import React from 'react';
13
13
 
14
- // Use the the window.injectHookForLink{n} hook to inject objects
14
+ // Use the window.injectHookForLink{n} hook to inject objects
15
15
  // to memory when link-{n} is triggered, for example:
16
16
  //
17
17
  // window.injectHookForLink4 = () => {
@@ -1,22 +0,0 @@
1
- // @nolint
2
-
3
- // memlab/packages/e2e/static/example/scenario/unbound-object.js
4
- function url() {
5
- return "http://localhost:3000/";
6
- }
7
-
8
- // action where you suspect the memory leak might be happening
9
- async function action(page) {
10
- await page.click('a[href="/examples/unbound-object"]');
11
- }
12
-
13
- // how to go back to the state before actionw
14
- async function back(page) {
15
- await page.click('a[href="/"]');
16
- }
17
-
18
- // function leakFilter(node, _snapshot, _leakedNodeIds) {
19
- // return node.retainedSize > 1000 * 1000;
20
- // };
21
-
22
- module.exports = { action, back, url };