codeceptjs 3.5.3 → 3.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +0 -2
  2. package/docs/build/Appium.js +8 -6
  3. package/docs/build/GraphQL.js +25 -0
  4. package/docs/build/Nightmare.js +11 -6
  5. package/docs/build/Playwright.js +425 -193
  6. package/docs/build/Protractor.js +13 -8
  7. package/docs/build/Puppeteer.js +20 -14
  8. package/docs/build/TestCafe.js +17 -10
  9. package/docs/build/WebDriver.js +41 -37
  10. package/docs/changelog.md +170 -1
  11. package/docs/community-helpers.md +8 -4
  12. package/docs/examples.md +8 -2
  13. package/docs/helpers/Appium.md +2 -2
  14. package/docs/helpers/GraphQL.md +21 -0
  15. package/docs/helpers/Nightmare.md +2 -2
  16. package/docs/helpers/Playwright.md +239 -122
  17. package/docs/helpers/Protractor.md +2 -2
  18. package/docs/helpers/Puppeteer.md +3 -3
  19. package/docs/helpers/TestCafe.md +2 -2
  20. package/docs/helpers/WebDriver.md +3 -3
  21. package/docs/playwright.md +24 -1
  22. package/docs/webapi/dontSeeInField.mustache +1 -1
  23. package/docs/webapi/seeInField.mustache +1 -1
  24. package/docs/wiki/Books-&-Posts.md +0 -0
  25. package/docs/wiki/Community-Helpers-&-Plugins.md +8 -4
  26. package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +46 -14
  27. package/docs/wiki/Examples.md +8 -2
  28. package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -0
  29. package/docs/wiki/Home.md +0 -0
  30. package/docs/wiki/Migration-to-Appium-v2---CodeceptJS.md +83 -0
  31. package/docs/wiki/Release-Process.md +0 -0
  32. package/docs/wiki/Roadmap.md +0 -0
  33. package/docs/wiki/Tests.md +0 -0
  34. package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -0
  35. package/docs/wiki/Videos.md +0 -0
  36. package/lib/command/definitions.js +2 -7
  37. package/lib/command/run-multiple/collection.js +17 -5
  38. package/lib/helper/Appium.js +6 -4
  39. package/lib/helper/GraphQL.js +25 -0
  40. package/lib/helper/Nightmare.js +9 -4
  41. package/lib/helper/Playwright.js +422 -190
  42. package/lib/helper/Protractor.js +11 -6
  43. package/lib/helper/Puppeteer.js +18 -12
  44. package/lib/helper/TestCafe.js +15 -8
  45. package/lib/helper/WebDriver.js +39 -35
  46. package/lib/helper/errors/ElementNotFound.js +2 -1
  47. package/lib/helper/extras/PlaywrightReact.js +9 -0
  48. package/lib/helper/scripts/highlightElement.js +1 -1
  49. package/lib/interfaces/bdd.js +1 -1
  50. package/lib/mochaFactory.js +2 -1
  51. package/lib/pause.js +5 -4
  52. package/lib/plugin/heal.js +2 -3
  53. package/lib/plugin/selenoid.js +6 -1
  54. package/lib/step.js +27 -10
  55. package/lib/utils.js +4 -0
  56. package/lib/workers.js +3 -1
  57. package/package.json +14 -14
  58. package/typings/promiseBasedTypes.d.ts +145 -126
  59. package/typings/types.d.ts +152 -133
  60. package/CHANGELOG.md +0 -2563
  61. package/docs/build/Polly.js +0 -42
  62. package/docs/build/SeleniumWebdriver.js +0 -76
@@ -821,12 +821,13 @@ class Protractor extends Helper {
821
821
  * I.seeInField('#searchform input','Search');
822
822
  * ```
823
823
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
824
- * @param {string} value value to check.
824
+ * @param {CodeceptJS.StringOrSecret} value value to check.
825
825
  * ⚠️ returns a _promise_ which is synchronized internally by recorder
826
826
  *
827
827
  */
828
828
  async seeInField(field, value) {
829
- return proceedSeeInField.call(this, 'assert', field, value);
829
+ const _value = (typeof value === 'boolean') ? value : value.toString();
830
+ return proceedSeeInField.call(this, 'assert', field, _value);
830
831
  }
831
832
 
832
833
  /**
@@ -839,12 +840,13 @@ class Protractor extends Helper {
839
840
  * ```
840
841
  *
841
842
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
842
- * @param {string} value value to check.
843
+ * @param {CodeceptJS.StringOrSecret} value value to check.
843
844
  * ⚠️ returns a _promise_ which is synchronized internally by recorder
844
845
  *
845
846
  */
846
847
  async dontSeeInField(field, value) {
847
- return proceedSeeInField.call(this, 'negate', field, value);
848
+ const _value = (typeof value === 'boolean') ? value : value.toString();
849
+ return proceedSeeInField.call(this, 'negate', field, _value);
848
850
  }
849
851
 
850
852
  /**
@@ -1645,7 +1647,7 @@ class Protractor extends Helper {
1645
1647
  const stream = fs.createWriteStream(outputFile);
1646
1648
  stream.write(Buffer.from(png, 'base64'));
1647
1649
  stream.end();
1648
- return new Promise(resolve => stream.on('finish', resolve));
1650
+ return new Promise(resolve => stream.on('finish', resolve)); // eslint-disable-line no-promise-executor-return
1649
1651
  };
1650
1652
 
1651
1653
  const res = await this._locate(locator);
@@ -1680,7 +1682,7 @@ class Protractor extends Helper {
1680
1682
  const stream = fs.createWriteStream(outputFile);
1681
1683
  stream.write(Buffer.from(png, 'base64'));
1682
1684
  stream.end();
1683
- return new Promise(resolve => stream.on('finish', resolve));
1685
+ return new Promise(resolve => stream.on('finish', resolve)); // eslint-disable-line no-promise-executor-return
1684
1686
  };
1685
1687
 
1686
1688
  if (!fullPage) {
@@ -2458,8 +2460,11 @@ class Protractor extends Helper {
2458
2460
  const body = document.body;
2459
2461
  const html = document.documentElement;
2460
2462
  window.scrollTo(0, Math.max(
2461
- body.scrollHeight, body.offsetHeight,
2462
- html.clientHeight, html.scrollHeight, html.offsetHeight
2463
+ body.scrollHeight,
2464
+ body.offsetHeight,
2465
+ html.clientHeight,
2466
+ html.scrollHeight,
2467
+ html.offsetHeight
2463
2468
  ));
2464
2469
  });
2465
2470
  /* eslint-enable */
@@ -23,7 +23,7 @@ const {
23
23
  screenshotOutputFolder,
24
24
  getNormalizedKeyAttributeValue,
25
25
  isModifierKey,
26
- requireWithFallback,
26
+ requireWithFallback, normalizeSpacesInString,
27
27
  } = require('../utils');
28
28
  const {
29
29
  isColorProperty,
@@ -69,7 +69,7 @@ const consoleLogStore = new Console();
69
69
  * @prop {boolean} [manualStart=false] - do not start browser before a test, start it manually inside a helper with `this.helpers["Puppeteer"]._startBrowser()`.
70
70
  * @prop {string} [browser=chrome] - can be changed to `firefox` when using [puppeteer-firefox](https://codecept.io/helpers/Puppeteer-firefox).
71
71
  * @prop {object} [chrome] - pass additional [Puppeteer run options](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions).
72
- * @prop {boolean} [highlightElement] - highlight the interacting elements
72
+ * @prop {boolean} [highlightElement] - highlight the interacting elements. Default: false
73
73
  */
74
74
  const config = {};
75
75
 
@@ -231,6 +231,7 @@ class Puppeteer extends Helper {
231
231
  keepBrowserState: false,
232
232
  show: false,
233
233
  defaultPopupAction: 'accept',
234
+ highlightElement: false,
234
235
  };
235
236
 
236
237
  return Object.assign(defaults, config);
@@ -857,8 +858,11 @@ class Puppeteer extends Helper {
857
858
  const body = document.body;
858
859
  const html = document.documentElement;
859
860
  window.scrollTo(0, Math.max(
860
- body.scrollHeight, body.offsetHeight,
861
- html.clientHeight, html.scrollHeight, html.offsetHeight,
861
+ body.scrollHeight,
862
+ body.offsetHeight,
863
+ html.clientHeight,
864
+ html.scrollHeight,
865
+ html.offsetHeight,
862
866
  ));
863
867
  });
864
868
  }
@@ -1756,7 +1760,7 @@ class Puppeteer extends Helper {
1756
1760
  await this._evaluateHandeInContext(el => el.innerHTML = '', el);
1757
1761
  }
1758
1762
 
1759
- highlightActiveElement.call(this, el, this.page);
1763
+ highlightActiveElement.call(this, el, await this._getContext());
1760
1764
  await el.type(value.toString(), { delay: this.options.pressKeyDelay });
1761
1765
 
1762
1766
  return this._waitForAction();
@@ -1797,7 +1801,7 @@ class Puppeteer extends Helper {
1797
1801
  async appendField(field, value) {
1798
1802
  const els = await findVisibleFields.call(this, field);
1799
1803
  assertElementExists(els, field, 'Field');
1800
- highlightActiveElement.call(this, els[0], this.page);
1804
+ highlightActiveElement.call(this, els[0], await this._getContext());
1801
1805
  await els[0].press('End');
1802
1806
  await els[0].type(value.toString(), { delay: this.options.pressKeyDelay });
1803
1807
  return this._waitForAction();
@@ -1814,12 +1818,13 @@ class Puppeteer extends Helper {
1814
1818
  * I.seeInField('#searchform input','Search');
1815
1819
  * ```
1816
1820
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1817
- * @param {string} value value to check.
1821
+ * @param {CodeceptJS.StringOrSecret} value value to check.
1818
1822
  * ⚠️ returns a _promise_ which is synchronized internally by recorder
1819
1823
  *
1820
1824
  */
1821
1825
  async seeInField(field, value) {
1822
- return proceedSeeInField.call(this, 'assert', field, value);
1826
+ const _value = (typeof value === 'boolean') ? value : value.toString();
1827
+ return proceedSeeInField.call(this, 'assert', field, _value);
1823
1828
  }
1824
1829
 
1825
1830
  /**
@@ -1832,12 +1837,13 @@ class Puppeteer extends Helper {
1832
1837
  * ```
1833
1838
  *
1834
1839
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1835
- * @param {string} value value to check.
1840
+ * @param {CodeceptJS.StringOrSecret} value value to check.
1836
1841
  * ⚠️ returns a _promise_ which is synchronized internally by recorder
1837
1842
  *
1838
1843
  */
1839
1844
  async dontSeeInField(field, value) {
1840
- return proceedSeeInField.call(this, 'negate', field, value);
1845
+ const _value = (typeof value === 'boolean') ? value : value.toString();
1846
+ return proceedSeeInField.call(this, 'negate', field, _value);
1841
1847
  }
1842
1848
 
1843
1849
  /**
@@ -1900,7 +1906,7 @@ class Puppeteer extends Helper {
1900
1906
  if (await el.getProperty('tagName').then(t => t.jsonValue()) !== 'SELECT') {
1901
1907
  throw new Error('Element is not <select>');
1902
1908
  }
1903
- highlightActiveElement.call(this, els[0], this.page);
1909
+ highlightActiveElement.call(this, els[0], await this._getContext());
1904
1910
  if (!Array.isArray(option)) option = [option];
1905
1911
 
1906
1912
  for (const key in option) {
@@ -3438,7 +3444,7 @@ async function proceedClick(locator, context = null, options = {}) {
3438
3444
  assertElementExists(els, locator, 'Clickable element');
3439
3445
  }
3440
3446
 
3441
- highlightActiveElement.call(this, els[0], this.page);
3447
+ highlightActiveElement.call(this, els[0], await this._getContext());
3442
3448
 
3443
3449
  await els[0].click(options);
3444
3450
  const promises = [];
@@ -3498,7 +3504,7 @@ async function proceedSee(assertType, text, context, strict = false) {
3498
3504
  if (strict) {
3499
3505
  return allText.map(elText => equals(description)[assertType](text, elText));
3500
3506
  }
3501
- return stringIncludes(description)[assertType](text, allText.join(' | '));
3507
+ return stringIncludes(description)[assertType](normalizeSpacesInString(text), normalizeSpacesInString(allText.join(' | ')));
3502
3508
  }
3503
3509
 
3504
3510
  async function findCheckable(locator, context) {
@@ -3793,7 +3799,7 @@ function getNormalizedKey(key) {
3793
3799
  }
3794
3800
 
3795
3801
  function highlightActiveElement(element, context) {
3796
- if (!this.options.enableHighlight && !store.debugMode) return;
3802
+ if (!this.options.highlightElement && !store.debugMode) return;
3797
3803
 
3798
3804
  highlightElement(element, context);
3799
3805
  }
@@ -20,7 +20,7 @@ const { urlEquals } = require('../assert/equal');
20
20
  const { empty } = require('../assert/empty');
21
21
  const { truth } = require('../assert/truth');
22
22
  const {
23
- xpathLocator,
23
+ xpathLocator, normalizeSpacesInString,
24
24
  } = require('../utils');
25
25
  const Locator = require('../locator');
26
26
 
@@ -933,9 +933,9 @@ class TestCafe extends Helper {
933
933
  async see(text, context = null) {
934
934
  let els;
935
935
  if (context) {
936
- els = (await findElements.call(this, this.context, context)).withText(text);
936
+ els = (await findElements.call(this, this.context, context)).withText(normalizeSpacesInString(text));
937
937
  } else {
938
- els = (await findElements.call(this, this.context, '*')).withText(text);
938
+ els = (await findElements.call(this, this.context, '*')).withText(normalizeSpacesInString(text));
939
939
  }
940
940
 
941
941
  return this.t
@@ -1091,18 +1091,19 @@ class TestCafe extends Helper {
1091
1091
  * I.seeInField('#searchform input','Search');
1092
1092
  * ```
1093
1093
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1094
- * @param {string} value value to check.
1094
+ * @param {CodeceptJS.StringOrSecret} value value to check.
1095
1095
  * ⚠️ returns a _promise_ which is synchronized internally by recorder
1096
1096
  *
1097
1097
  */
1098
1098
  async seeInField(field, value) {
1099
+ const _value = (typeof value === 'boolean') ? value : value.toString();
1099
1100
  // const expectedValue = findElements.call(this, this.context, field).value;
1100
1101
  const els = await findFields.call(this, field);
1101
1102
  assertElementExists(els, field, 'Field');
1102
1103
  const el = await els.nth(0);
1103
1104
 
1104
1105
  return this.t
1105
- .expect(await el.value).eql(value)
1106
+ .expect(await el.value).eql(_value)
1106
1107
  .catch(mapError);
1107
1108
  }
1108
1109
 
@@ -1116,18 +1117,19 @@ class TestCafe extends Helper {
1116
1117
  * ```
1117
1118
  *
1118
1119
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1119
- * @param {string} value value to check.
1120
+ * @param {CodeceptJS.StringOrSecret} value value to check.
1120
1121
  * ⚠️ returns a _promise_ which is synchronized internally by recorder
1121
1122
  *
1122
1123
  */
1123
1124
  async dontSeeInField(field, value) {
1125
+ const _value = (typeof value === 'boolean') ? value : value.toString();
1124
1126
  // const expectedValue = findElements.call(this, this.context, field).value;
1125
1127
  const els = await findFields.call(this, field);
1126
1128
  assertElementExists(els, field, 'Field');
1127
1129
  const el = await els.nth(0);
1128
1130
 
1129
1131
  return this.t
1130
- .expect(el.value).notEql(value)
1132
+ .expect(el.value).notEql(_value)
1131
1133
  .catch(mapError);
1132
1134
  }
1133
1135
 
@@ -1502,8 +1504,11 @@ class TestCafe extends Helper {
1502
1504
  const body = document.body;
1503
1505
  const html = document.documentElement;
1504
1506
  window.scrollTo(0, Math.max(
1505
- body.scrollHeight, body.offsetHeight,
1506
- html.clientHeight, html.scrollHeight, html.offsetHeight,
1507
+ body.scrollHeight,
1508
+ body.offsetHeight,
1509
+ html.clientHeight,
1510
+ html.scrollHeight,
1511
+ html.offsetHeight,
1507
1512
  ));
1508
1513
  }).with({ boundTestRun: this.t })().catch(mapError);
1509
1514
  }
@@ -1926,7 +1931,9 @@ class TestCafe extends Helper {
1926
1931
  }
1927
1932
 
1928
1933
  async function waitForFunction(browserFn, waitTimeout) {
1929
- const pause = () => new Promise((done => setTimeout(done, 50)));
1934
+ const pause = () => new Promise((done => {
1935
+ setTimeout(done, 50);
1936
+ }));
1930
1937
 
1931
1938
  const start = Date.now();
1932
1939
  // eslint-disable-next-line no-constant-condition
@@ -62,7 +62,7 @@ const webRoot = 'body';
62
62
  * @prop {object} [desiredCapabilities] Selenium's [desired capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities).
63
63
  * @prop {boolean} [manualStart=false] - do not start browser before a test, start it manually inside a helper with `this.helpers["WebDriver"]._startBrowser()`.
64
64
  * @prop {object} [timeouts] [WebDriver timeouts](http://webdriver.io/docs/timeouts.html) defined as hash.
65
- * @prop {boolean} [highlightElement] - highlight the interacting elements
65
+ * @prop {boolean} [highlightElement] - highlight the interacting elements. Default: false
66
66
  */
67
67
  const config = {};
68
68
 
@@ -429,6 +429,7 @@ class WebDriver extends Helper {
429
429
  keepCookies: false,
430
430
  keepBrowserState: false,
431
431
  deprecationWarnings: false,
432
+ highlightElement: false,
432
433
  };
433
434
 
434
435
  // override defaults with config
@@ -1713,13 +1714,14 @@ class WebDriver extends Helper {
1713
1714
  * I.seeInField('#searchform input','Search');
1714
1715
  * ```
1715
1716
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1716
- * @param {string} value value to check.
1717
+ * @param {CodeceptJS.StringOrSecret} value value to check.
1717
1718
  * ⚠️ returns a _promise_ which is synchronized internally by recorder
1718
1719
  *
1719
1720
  *
1720
1721
  */
1721
1722
  async seeInField(field, value) {
1722
- return proceedSeeField.call(this, 'assert', field, value);
1723
+ const _value = (typeof value === 'boolean') ? value : value.toString();
1724
+ return proceedSeeField.call(this, 'assert', field, _value);
1723
1725
  }
1724
1726
 
1725
1727
  /**
@@ -1732,13 +1734,14 @@ class WebDriver extends Helper {
1732
1734
  * ```
1733
1735
  *
1734
1736
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1735
- * @param {string} value value to check.
1737
+ * @param {CodeceptJS.StringOrSecret} value value to check.
1736
1738
  * ⚠️ returns a _promise_ which is synchronized internally by recorder
1737
1739
  *
1738
1740
  *
1739
1741
  */
1740
1742
  async dontSeeInField(field, value) {
1741
- return proceedSeeField.call(this, 'negate', field, value);
1743
+ const _value = (typeof value === 'boolean') ? value : value.toString();
1744
+ return proceedSeeField.call(this, 'negate', field, _value);
1742
1745
  }
1743
1746
 
1744
1747
  /**
@@ -2970,7 +2973,9 @@ class WebDriver extends Helper {
2970
2973
  *
2971
2974
  */
2972
2975
  async wait(sec) {
2973
- return new Promise(resolve => setTimeout(resolve, sec * 1000));
2976
+ return new Promise(resolve => {
2977
+ setTimeout(resolve, sec * 1000);
2978
+ });
2974
2979
  }
2975
2980
 
2976
2981
  /**
@@ -3135,20 +3140,18 @@ class WebDriver extends Helper {
3135
3140
  const aSec = sec || this.options.waitForTimeoutInSeconds;
3136
3141
  const _context = context || this.root;
3137
3142
 
3138
- return this.browser.waitUntil(
3139
- async () => {
3140
- const res = await this.$$(withStrictLocator.call(this, _context));
3141
- if (!res || res.length === 0) return false;
3142
- const selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)));
3143
- if (Array.isArray(selected)) {
3144
- return selected.filter(part => part.indexOf(text) >= 0).length > 0;
3145
- }
3146
- return selected.indexOf(text) >= 0;
3147
- }, {
3148
- timeout: aSec * 1000,
3149
- timeoutMsg: `element (${_context}) is not in DOM or there is no element(${_context}) with text "${text}" after ${aSec} sec`,
3150
- },
3151
- );
3143
+ return this.browser.waitUntil(async () => {
3144
+ const res = await this.$$(withStrictLocator.call(this, _context));
3145
+ if (!res || res.length === 0) return false;
3146
+ const selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)));
3147
+ if (Array.isArray(selected)) {
3148
+ return selected.filter(part => part.indexOf(text) >= 0).length > 0;
3149
+ }
3150
+ return selected.indexOf(text) >= 0;
3151
+ }, {
3152
+ timeout: aSec * 1000,
3153
+ timeoutMsg: `element (${_context}) is not in DOM or there is no element(${_context}) with text "${text}" after ${aSec} sec`,
3154
+ });
3152
3155
  }
3153
3156
 
3154
3157
  /**
@@ -3168,20 +3171,18 @@ class WebDriver extends Helper {
3168
3171
  const client = this.browser;
3169
3172
  const aSec = sec || this.options.waitForTimeoutInSeconds;
3170
3173
 
3171
- return client.waitUntil(
3172
- async () => {
3173
- const res = await findFields.call(this, field);
3174
- if (!res || res.length === 0) return false;
3175
- const selected = await forEachAsync(res, async el => el.getValue());
3176
- if (Array.isArray(selected)) {
3177
- return selected.filter(part => part.indexOf(value) >= 0).length > 0;
3178
- }
3179
- return selected.indexOf(value) >= 0;
3180
- }, {
3181
- timeout: aSec * 1000,
3182
- timeoutMsg: `element (${field}) is not in DOM or there is no element(${field}) with value "${value}" after ${aSec} sec`,
3183
- },
3184
- );
3174
+ return client.waitUntil(async () => {
3175
+ const res = await findFields.call(this, field);
3176
+ if (!res || res.length === 0) return false;
3177
+ const selected = await forEachAsync(res, async el => el.getValue());
3178
+ if (Array.isArray(selected)) {
3179
+ return selected.filter(part => part.indexOf(value) >= 0).length > 0;
3180
+ }
3181
+ return selected.indexOf(value) >= 0;
3182
+ }, {
3183
+ timeout: aSec * 1000,
3184
+ timeoutMsg: `element (${field}) is not in DOM or there is no element(${field}) with value "${value}" after ${aSec} sec`,
3185
+ });
3185
3186
  }
3186
3187
 
3187
3188
  /**
@@ -3525,8 +3526,11 @@ class WebDriver extends Helper {
3525
3526
  const body = document.body;
3526
3527
  const html = document.documentElement;
3527
3528
  window.scrollTo(0, Math.max(
3528
- body.scrollHeight, body.offsetHeight,
3529
- html.clientHeight, html.scrollHeight, html.offsetHeight
3529
+ body.scrollHeight,
3530
+ body.offsetHeight,
3531
+ html.clientHeight,
3532
+ html.scrollHeight,
3533
+ html.offsetHeight
3530
3534
  ));
3531
3535
  });
3532
3536
  /* eslint-enable */
@@ -4075,7 +4079,7 @@ function isModifierKey(key) {
4075
4079
  }
4076
4080
 
4077
4081
  function highlightActiveElement(element) {
4078
- if (!this.options.enableHighlight && !store.debugMode) return;
4082
+ if (!this.options.highlightElement && !store.debugMode) return;
4079
4083
 
4080
4084
  highlightElement(element, this.browser);
4081
4085
  }
package/docs/changelog.md CHANGED
@@ -7,11 +7,180 @@ layout: Section
7
7
 
8
8
  # Releases
9
9
 
10
+ ## 3.5.4
11
+
12
+ 🐛 Bug Fixes:
13
+ * **[Playwright]** When passing `userDataDir`, it throws error after test execution ([#3814](https://github.com/codeceptjs/CodeceptJS/issues/3814)) - by **[KobeNguyenT](https://github.com/KobeNguyenT)**
14
+ * [CodeceptJS-CLI] Improve command to generate types ([#3788](https://github.com/codeceptjs/CodeceptJS/issues/3788)) - by **[KobeNguyenT](https://github.com/KobeNguyenT)**
15
+ * Heal plugin fix ([#3820](https://github.com/codeceptjs/CodeceptJS/issues/3820)) - by **[davert](https://github.com/davert)**
16
+ * Fix for error in using `all` with `run-workers` ([#3805](https://github.com/codeceptjs/CodeceptJS/issues/3805)) - by **[KobeNguyenT](https://github.com/KobeNguyenT)**
17
+ ```js
18
+ helpers: {
19
+ Playwright: {
20
+ url: 'https://github.com',
21
+ show: false,
22
+ browser: 'chromium',
23
+ waitForNavigation: 'load',
24
+ waitForTimeout: 30_000,
25
+ trace: true,
26
+ keepTraceForPassedTests: true
27
+ },
28
+ },
29
+ multiple: {
30
+ profile1: {
31
+ browsers: [
32
+ {
33
+ browser: "chromium",
34
+ }
35
+ ]
36
+ },
37
+ },
38
+ ```
39
+ * Highlight elements issues ([#3779](https://github.com/codeceptjs/CodeceptJS/issues/3779)) ([#3778](https://github.com/codeceptjs/CodeceptJS/issues/3778)) - by **[philkas](https://github.com/philkas)**
40
+ * Support `&nbsp` symbol in `I.see` method ([#3815](https://github.com/codeceptjs/CodeceptJS/issues/3815)) - by **[KobeNguyenT](https://github.com/KobeNguyenT)**
41
+
42
+ ```js
43
+ // HTML code uses &nbsp; instead of space
44
+ <div class="dJHe_" style="color: rgb(255, 255, 255);">My&nbsp;Text!</div>
45
+
46
+ I.see("My Text!") // this test would work with both &nbsp; and space
47
+ ```
48
+
49
+ 📖 Documentation
50
+ * Improve the configuration of electron testing when the app is build with electron-forge ([#3802](https://github.com/codeceptjs/CodeceptJS/issues/3802)) - by **[KobeNguyenT](https://github.com/KobeNguyenT)**
51
+
52
+ ```js
53
+ const path = require("path");
54
+
55
+ exports.config = {
56
+ helpers: {
57
+ Playwright: {
58
+ browser: "electron",
59
+ electron: {
60
+ executablePath: require("electron"),
61
+ args: [path.join(__dirname, ".webpack/main/index.js")],
62
+ },
63
+ },
64
+ },
65
+ // rest of config
66
+ }
67
+ ```
68
+
69
+ 🛩️ Features
70
+
71
+ #### **[Playwright]** new features and improvements
72
+ * Parse the response in recording network steps ([#3771](https://github.com/codeceptjs/CodeceptJS/issues/3771)) - by **[KobeNguyenT](https://github.com/KobeNguyenT)**
73
+
74
+ ```js
75
+ const traffics = await I.grabRecordedNetworkTraffics();
76
+ expect(traffics[0].url).to.equal('https://reqres.in/api/comments/1');
77
+ expect(traffics[0].response.status).to.equal(200);
78
+ expect(traffics[0].response.body).to.contain({ name: 'this was mocked' });
79
+
80
+ expect(traffics[1].url).to.equal('https://reqres.in/api/comments/1');
81
+ expect(traffics[1].response.status).to.equal(200);
82
+ expect(traffics[1].response.body).to.contain({ name: 'this was another mocked' });
83
+ ```
84
+ * Grab metrics ([#3809](https://github.com/codeceptjs/CodeceptJS/issues/3809)) - by **[KobeNguyenT](https://github.com/KobeNguyenT)**
85
+
86
+ ```js
87
+ const metrics = await I.grabMetrics();
88
+
89
+ // returned metrics
90
+
91
+ [
92
+ { name: 'Timestamp', value: 1584904.203473 },
93
+ { name: 'AudioHandlers', value: 0 },
94
+ { name: 'AudioWorkletProcessors', value: 0 },
95
+ { name: 'Documents', value: 22 },
96
+ { name: 'Frames', value: 10 },
97
+ { name: 'JSEventListeners', value: 366 },
98
+ { name: 'LayoutObjects', value: 1240 },
99
+ { name: 'MediaKeySessions', value: 0 },
100
+ { name: 'MediaKeys', value: 0 },
101
+ { name: 'Nodes', value: 4505 },
102
+ { name: 'Resources', value: 141 },
103
+ { name: 'ContextLifecycleStateObservers', value: 34 },
104
+ { name: 'V8PerContextDatas', value: 4 },
105
+ { name: 'WorkerGlobalScopes', value: 0 },
106
+ { name: 'UACSSResources', value: 0 },
107
+ { name: 'RTCPeerConnections', value: 0 },
108
+ { name: 'ResourceFetchers', value: 22 },
109
+ { name: 'AdSubframes', value: 0 },
110
+ { name: 'DetachedScriptStates', value: 2 },
111
+ { name: 'ArrayBufferContents', value: 1 },
112
+ { name: 'LayoutCount', value: 0 },
113
+ { name: 'RecalcStyleCount', value: 0 },
114
+ { name: 'LayoutDuration', value: 0 },
115
+ { name: 'RecalcStyleDuration', value: 0 },
116
+ { name: 'DevToolsCommandDuration', value: 0.000013 },
117
+ { name: 'ScriptDuration', value: 0 },
118
+ { name: 'V8CompileDuration', value: 0 },
119
+ { name: 'TaskDuration', value: 0.000014 },
120
+ { name: 'TaskOtherDuration', value: 0.000001 },
121
+ { name: 'ThreadTime', value: 0.000046 },
122
+ { name: 'ProcessTime', value: 0.616852 },
123
+ { name: 'JSHeapUsedSize', value: 19004908 },
124
+ { name: 'JSHeapTotalSize', value: 26820608 },
125
+ { name: 'FirstMeaningfulPaint', value: 0 },
126
+ { name: 'DomContentLoaded', value: 1584903.690491 },
127
+ { name: 'NavigationStart', value: 1584902.841845 }
128
+ ]
129
+ ```
130
+
131
+ * Grab WebSocket (WS) messages ([#3789](https://github.com/codeceptjs/CodeceptJS/issues/3789)) - by **[KobeNguyenT](https://github.com/KobeNguyenT)**
132
+ * `flushWebSocketMessages`
133
+ * `grabWebSocketMessages`
134
+ * `startRecordingWebSocketMessages`
135
+ * `stopRecordingWebSocketMessages`
136
+
137
+ ```js
138
+ await I.startRecordingWebSocketMessages();
139
+ I.amOnPage('https://websocketstest.com/');
140
+ I.waitForText('Work for You!');
141
+ I.flushNetworkTraffics();
142
+ const wsMessages = I.grabWebSocketMessages();
143
+ expect(wsMessages.length).to.equal(0);
144
+ ```
145
+
146
+ ```js
147
+ await I.startRecordingWebSocketMessages();
148
+ await I.amOnPage('https://websocketstest.com/');
149
+ I.waitForText('Work for You!');
150
+ const wsMessages = I.grabWebSocketMessages();
151
+ expect(wsMessages.length).to.greaterThan(0);
152
+ ```
153
+
154
+ ```js
155
+ await I.startRecordingWebSocketMessages();
156
+ await I.amOnPage('https://websocketstest.com/');
157
+ I.waitForText('Work for You!');
158
+ const wsMessages = I.grabWebSocketMessages();
159
+ await I.stopRecordingWebSocketMessages();
160
+ await I.amOnPage('https://websocketstest.com/');
161
+ I.waitForText('Work for You!');
162
+ const afterWsMessages = I.grabWebSocketMessages();
163
+ expect(wsMessages.length).to.equal(afterWsMessages.length);
164
+ ```
165
+
166
+ * Move from `ElementHandle` to `Locator`. This change is quite major, but it happened under hood, so should not affect your code. ([#3738](https://github.com/codeceptjs/CodeceptJS/issues/3738)) - by **[KobeNguyenT](https://github.com/KobeNguyenT)**
167
+
10
168
  ## 3.5.3
11
169
 
12
170
  🛩️ Features
13
171
 
14
- * **[Playwright]** Provide new steps to check network traffic [#3748](https://github.com/codeceptjs/CodeceptJS/issues/3748) - by **[ngraf](https://github.com/ngraf)** **[KobeNguyenT](https://github.com/KobeNguyenT)**
172
+ * **[Playwright]** Added commands to check network traffic [#3748](https://github.com/codeceptjs/CodeceptJS/issues/3748) - by **[ngraf](https://github.com/ngraf)** **[KobeNguyenT](https://github.com/KobeNguyenT)**
173
+ * `startRecordingTraffic`
174
+ * `grabRecordedNetworkTraffics`
175
+ * `blockTraffic`
176
+ * `mockTraffic`
177
+ * `flushNetworkTraffics`
178
+ * `stopRecordingTraffic`
179
+ * `seeTraffic`
180
+ * `grabTrafficUrl`
181
+ * `dontSeeTraffic`
182
+
183
+ Examples:
15
184
 
16
185
  ```js
17
186
  // recording traffics and verify the traffic
@@ -31,9 +31,6 @@ Please **add your own** by editing this page.
31
31
  * [codeceptjs-bshelper](https://github.com/PeterNgTr/codeceptjs-bshelper) - a helper which updates `Test Names` & `Test Results` on Browserstack
32
32
  * [codeceptjs-tbhelper](https://github.com/testingbot/codeceptjs-tbhelper) - a helper which updates `Test Names` & `Test Results` on TestingBot
33
33
 
34
- ## Integrations
35
- * [codeceptjs-testrail](https://github.com/PeterNgTr/codeceptjs-testrail) - a plugin to integrate with [Testrail](https://www.gurock.com/testrail)
36
-
37
34
  ## Visual-Testing
38
35
  * [codeceptjs-resemblehelper](https://github.com/puneet0191/codeceptjs-resemblehelper) - a helper which helps with visual testing using resemble.js.
39
36
  * [codeceptjs-applitoolshelper](https://www.npmjs.com/package/codeceptjs-applitoolshelper) - a helper which helps interaction with [Applitools](https://applitools.com)
@@ -42,8 +39,10 @@ Please **add your own** by editing this page.
42
39
  ## Reporters
43
40
  * [codeceptjs-rphelper](https://github.com/reportportal/agent-js-codecept) is a CodeceptJS helper which can publish tests results on ReportPortal after execution.
44
41
  * [codeceptjs-xray-helper](https://www.npmjs.com/package/codeceptjs-xray-helper) is a CodeceptJS helper which can publish tests results on [XRAY](https://confluence.xpand-it.com/display/XRAYCLOUD/Import+Execution+Results+-+REST).
42
+ * [codeceptjs-xray-cloud-helper](https://www.npmjs.com/package/codeceptjs-xray-cloud-helper) is a helper that automatically retrieves the result of CodeceptJS tests and sends them to XRAY/JIRA(cloud version) via [XRAY Cloud API](https://docs.getxray.app/display/XRAYCLOUD/Import+Execution+Results+-+REST+v2#ImportExecutionResultsRESTv2-XrayJSONresults).
45
43
  * [codeceptjs-slack-reporter](https://www.npmjs.com/package/codeceptjs-slack-reporter) Get a Slack notification when one or more scenarios fail.
46
44
  * [codeceptjs-browserlogs-plugin](https://github.com/pavkam/codeceptjs-browserlogs-plugin) Record the browser logs for failed tests.
45
+ * [codeceptjs-testrail](https://github.com/PeterNgTr/codeceptjs-testrail) - a plugin to integrate with [Testrail](https://www.gurock.com/testrail)
47
46
 
48
47
  ## Browser request control
49
48
  * [codeceptjs-resources-check](https://github.com/luarmr/codeceptjs-resources-check) Load a URL with Puppeteer and listen to the requests while the page is loading. Enabling count the number or check the sizes of the requests.
@@ -55,4 +54,9 @@ Please **add your own** by editing this page.
55
54
  ## Other
56
55
 
57
56
  * [codeceptjs-cmdhelper](https://github.com/thiagodp/codeceptjs-cmdhelper) allows you to run commands in the terminal/console
58
- * [eslint-plugin-codeceptjs](https://www.npmjs.com/package/eslint-plugin-codeceptjs) Eslint rules for CodeceptJS.
57
+ * [eslint-plugin-codeceptjs](https://www.npmjs.com/package/eslint-plugin-codeceptjs) Eslint rules for CodeceptJS.
58
+ * [codeceptjs-datalayer-helper](https://github.com/kobenguyent/codeceptjs-datalayer-helper) CodeceptJS DataLayer helper helps you to get the datalayer JavaScript array that is used to store information and send this data to the tag manager.
59
+ * [codeceptjs-a11y-helper](https://github.com/kobenguyent/codeceptjs-a11y-helper) accessibility tests integrated with CodeceptJS - Playwright-axe
60
+ * [codeceptjs-lighthouse-helper](https://github.com/kobenguyent/codeceptjs-lighthouse-helper) lighthouse audit integrated with CodeceptJS - Playwright
61
+ * [Snowplow Data analytics](https://www.npmjs.com/package/@viasat/codeceptjs-snowplow-helper) - Test your Snowplow events implementations with CodeceptJS and Snowplow Micro.
62
+ * [codeceptjs-failure-logger](https://github.com/kobenguyent/codeceptjs-failure-logger) - Log failed CodeceptJS tests to file
package/docs/examples.md CHANGED
@@ -16,6 +16,7 @@ Playground repository where you can run tests in different helpers on a basic si
16
16
 
17
17
  Tests repository demonstrate usage of
18
18
 
19
+ * Playwright helper
19
20
  * Puppeteer helper
20
21
  * WebDriver helper
21
22
  * TestCafe plugin
@@ -28,7 +29,6 @@ Tests repository demonstrate usage of
28
29
  CodeceptJS repo contains basic tests (both failing and passing) just to show how it works.
29
30
  Our team uses it to test new features and run simple scenarios.
30
31
 
31
-
32
32
  ## [CodeceptJS Cucumber E2E Framework](https://github.com/gkushang/codeceptjs-e2e)
33
33
 
34
34
  This repository contains complete E2E framework for CodeceptJS with Cucumber and SauceLabs Integration
@@ -146,4 +146,10 @@ This is necessary if all integrations with TMS and CI/CD are already configured,
146
146
  * HTTP request client with session support and unit tests
147
147
  * Exemplary code control
148
148
  * Ready to launch in a CI/CD system as is
149
- * OOP, Test data models and builders, endpoint decorators
149
+ * OOP, Test data models and builders, endpoint decorators
150
+
151
+ ## [Playwright fun with CodeceptJS](https://github.com/PeterNgTr/codeceptjs-playwright-fun)
152
+ * Tests are written in TS
153
+ * CI/CD with Github Actions
154
+ * Page Object Model is applied
155
+ * ReportPortal Integration