codeceptjs 3.3.6 → 3.3.7

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/docs/basics.md +2 -3
  2. package/docs/bdd.md +33 -0
  3. package/docs/best.md +8 -8
  4. package/docs/build/Appium.js +60 -22
  5. package/docs/build/GraphQL.js +6 -6
  6. package/docs/build/Nightmare.js +4 -4
  7. package/docs/build/Playwright.js +102 -39
  8. package/docs/build/Polly.js +0 -0
  9. package/docs/build/Protractor.js +25 -25
  10. package/docs/build/Puppeteer.js +7 -7
  11. package/docs/build/SeleniumWebdriver.js +0 -0
  12. package/docs/build/TestCafe.js +12 -12
  13. package/docs/build/WebDriver.js +32 -32
  14. package/docs/changelog.md +36 -1
  15. package/docs/helpers/Appium.md +103 -79
  16. package/docs/helpers/GraphQL.md +6 -6
  17. package/docs/helpers/Playwright.md +280 -245
  18. package/docs/helpers/Puppeteer.md +1 -1
  19. package/docs/helpers/REST.md +1 -1
  20. package/docs/helpers/WebDriver.md +2 -2
  21. package/docs/playwright.md +14 -0
  22. package/docs/quickstart.md +40 -13
  23. package/docs/translation.md +83 -56
  24. package/docs/typescript.md +49 -3
  25. package/docs/wiki/Books-&-Posts.md +0 -0
  26. package/docs/wiki/Community-Helpers-&-Plugins.md +0 -0
  27. package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -0
  28. package/docs/wiki/Examples.md +0 -0
  29. package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -0
  30. package/docs/wiki/Home.md +0 -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/codecept.js +3 -1
  37. package/lib/command/definitions.js +26 -2
  38. package/lib/command/generate.js +23 -9
  39. package/lib/command/init.js +32 -7
  40. package/lib/command/run.js +5 -1
  41. package/lib/container.js +15 -15
  42. package/lib/helper/Appium.js +60 -22
  43. package/lib/helper/GraphQL.js +6 -6
  44. package/lib/helper/Nightmare.js +4 -4
  45. package/lib/helper/Playwright.js +102 -39
  46. package/lib/helper/Protractor.js +25 -25
  47. package/lib/helper/Puppeteer.js +7 -7
  48. package/lib/helper/TestCafe.js +12 -12
  49. package/lib/helper/WebDriver.js +32 -32
  50. package/lib/helper/errors/ElementNotFound.js +1 -1
  51. package/lib/helper/extras/PlaywrightRestartOpts.js +0 -2
  52. package/lib/interfaces/bdd.js +26 -1
  53. package/lib/listener/artifacts.js +19 -0
  54. package/lib/rerun.js +12 -13
  55. package/lib/step.js +5 -5
  56. package/lib/translation.js +32 -0
  57. package/package.json +11 -17
  58. package/translations/ru-RU.js +1 -0
  59. package/typings/index.d.ts +29 -1
  60. package/typings/promiseBasedTypes.d.ts +10466 -0
  61. package/typings/types.d.ts +62 -12
  62. package/CHANGELOG.md +0 -2340
@@ -44,6 +44,8 @@ const {
44
44
  } = require('./extras/PlaywrightRestartOpts');
45
45
  const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
46
46
 
47
+ const pathSeparator = path.sep;
48
+
47
49
  /**
48
50
  * ## Configuration
49
51
  *
@@ -52,7 +54,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
52
54
  * @typedef PlaywrightConfig
53
55
  * @type {object}
54
56
  * @prop {string} url - base url of website to be tested
55
- * @prop {string} browser - a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
57
+ * @prop {string} [browser] - a browser to test on, either: `chromium`, `firefox`, `webkit`, `electron`. Default: chromium.
56
58
  * @prop {boolean} [show=false] - show browser window.
57
59
  * @prop {string|boolean} [restart=false] - restart strategy between tests. Possible values:
58
60
  * * 'context' or **false** - restarts [browser context](https://playwright.dev/docs/api/class-browsercontext) but keeps running browser. Recommended by Playwright team to keep tests isolated.
@@ -80,8 +82,11 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
80
82
  * @prop {string} [locale] - locale string. Example: 'en-GB', 'de-DE', 'fr-FR', ...
81
83
  * @prop {boolean} [manualStart] - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
82
84
  * @prop {object} [chromium] - pass additional chromium options
85
+ * @prop {object} [firefox] - pass additional firefox options
83
86
  * @prop {object} [electron] - (pass additional electron options
84
87
  * @prop {any} [channel] - (While Playwright can operate against the stock Google Chrome and Microsoft Edge browsers available on the machine. In particular, current Playwright version will support Stable and Beta channels of these browsers. See [Google Chrome & Microsoft Edge](https://playwright.dev/docs/browsers/#google-chrome--microsoft-edge).
88
+ * @prop {string[]} [ignoreLog] - An array with console message types that are not logged to debug log. Default value is `['warning', 'log']`. E.g. you can set `[]` to log all messages. See all possible [values](https://playwright.dev/docs/api/class-consolemessage#console-message-type).
89
+ * @prop {boolean} [ignoreHTTPSErrors] - Allows access to untrustworthy pages, e.g. to a page with an expired certificate. Default value is `false`
85
90
  */
86
91
  const config = {};
87
92
 
@@ -448,7 +453,7 @@ class Playwright extends Helper {
448
453
  const existingPages = await this.browserContext.pages();
449
454
  mainPage = existingPages[0] || await this.browserContext.newPage();
450
455
  }
451
- targetCreatedHandler.call(this, mainPage);
456
+ await targetCreatedHandler.call(this, mainPage);
452
457
 
453
458
  await this._setPage(mainPage);
454
459
 
@@ -513,12 +518,13 @@ class Playwright extends Helper {
513
518
  browserContext = browser.context();
514
519
  page = await browser.firstWindow();
515
520
  } else {
516
- browserContext = await this.browser.newContext(config);
521
+ browserContext = await this.browser.newContext(Object.assign(this.options, config));
517
522
  page = await browserContext.newPage();
518
523
  }
519
524
 
520
- targetCreatedHandler.call(this, page);
521
- this._setPage(page);
525
+ if (this.options.trace) await browserContext.tracing.start({ screenshots: true, snapshots: true });
526
+ await targetCreatedHandler.call(this, page);
527
+ await this._setPage(page);
522
528
  // Create a new page inside context.
523
529
  return browserContext;
524
530
  },
@@ -732,6 +738,19 @@ class Playwright extends Helper {
732
738
  });
733
739
 
734
740
  this.isRunning = true;
741
+ return this.browser;
742
+ }
743
+
744
+ /**
745
+ * Create a new browser context with a page. \
746
+ * Usually it should be run from a custom helper after call of `_startBrowser()`
747
+ * @param {object} [contextOptions] See https://playwright.dev/docs/api/class-browser#browser-new-context
748
+ */
749
+ async _createContextPage(contextOptions) {
750
+ this.browserContext = await this.browser.newContext(contextOptions);
751
+ const page = await this.browserContext.newPage();
752
+ targetCreatedHandler.call(this, page);
753
+ await this._setPage(page);
735
754
  }
736
755
 
737
756
  _getType() {
@@ -800,8 +819,8 @@ class Playwright extends Helper {
800
819
  if (this.isElectron) {
801
820
  throw new Error('Cannot open pages inside an Electron container');
802
821
  }
803
- if (!(/^\w+\:\/\//.test(url))) {
804
- url = this.options.url + url;
822
+ if (!(/^\w+\:(\/\/|.+)/.test(url))) {
823
+ url = this.options.url + (url.startsWith('/') ? url : `/${url}`);
805
824
  }
806
825
 
807
826
  if (this.options.basicAuth && (this.isAuthenticated !== true)) {
@@ -874,7 +893,7 @@ class Playwright extends Helper {
874
893
  */
875
894
  async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
876
895
  const els = await this._locate(locator);
877
- assertElementExists(els);
896
+ assertElementExists(els, locator);
878
897
 
879
898
  // Use manual mouse.move instead of .hover() so the offset can be added to the coordinates
880
899
  const { x, y } = await clickablePoint(els[0]);
@@ -901,6 +920,26 @@ class Playwright extends Helper {
901
920
  return this.page.dragAndDrop(buildLocatorString(src), buildLocatorString(dst), options);
902
921
  }
903
922
 
923
+ /**
924
+ * Restart browser with a new context and a new page
925
+ *
926
+ * ```js
927
+ * // Restart browser and use a new timezone
928
+ * I.restartBrowser({ timezoneId: 'America/Phoenix' });
929
+ * // Open URL in a new page in changed timezone
930
+ * I.amOnPage('/');
931
+ * // Restart browser, allow reading/copying of text from/into clipboard in Chrome
932
+ * I.restartBrowser({ permissions: ['clipboard-read', 'clipboard-write'] });
933
+ * ```
934
+ *
935
+ * @param {object} [contextOptions] [Options for browser context](https://playwright.dev/docs/api/class-browser#browser-new-context) when starting new browser
936
+ */
937
+ async restartBrowser(contextOptions) {
938
+ await this._stopBrowser();
939
+ await this._startBrowser();
940
+ await this._createContextPage(contextOptions);
941
+ }
942
+
904
943
  /**
905
944
  * {{> refreshPage }}
906
945
  */
@@ -1073,7 +1112,7 @@ class Playwright extends Helper {
1073
1112
  if (!page) {
1074
1113
  throw new Error(`There is no ability to switch to next tab with offset ${num}`);
1075
1114
  }
1076
- targetCreatedHandler.call(this, page);
1115
+ await targetCreatedHandler.call(this, page);
1077
1116
  await this._setPage(page);
1078
1117
  return this._waitForAction();
1079
1118
  }
@@ -1157,7 +1196,7 @@ class Playwright extends Helper {
1157
1196
  throw new Error('Cannot open new tabs inside an Electron container');
1158
1197
  }
1159
1198
  const page = await this.browserContext.newPage(options);
1160
- targetCreatedHandler.call(this, page);
1199
+ await targetCreatedHandler.call(this, page);
1161
1200
  await this._setPage(page);
1162
1201
  return this._waitForAction();
1163
1202
  }
@@ -1207,7 +1246,7 @@ class Playwright extends Helper {
1207
1246
  }
1208
1247
 
1209
1248
  /**
1210
- * Handles a file download.Aa file name is required to save the file on disk.
1249
+ * Handles a file download. A file name is required to save the file on disk.
1211
1250
  * Files are saved to "output" directory.
1212
1251
  *
1213
1252
  * Should be used with [FileSystem helper](https://codecept.io/helpers/FileSystem) to check that file were downloaded correctly.
@@ -1216,17 +1255,19 @@ class Playwright extends Helper {
1216
1255
  * I.handleDownloads('downloads/avatar.jpg');
1217
1256
  * I.click('Download Avatar');
1218
1257
  * I.amInPath('output/downloads');
1219
- * I.waitForFile('downloads/avatar.jpg', 5);
1258
+ * I.waitForFile('avatar.jpg', 5);
1220
1259
  *
1221
1260
  * ```
1222
1261
  *
1223
1262
  * @param {string} [fileName] set filename for downloaded file
1224
1263
  * @return {Promise<void>}
1225
1264
  */
1226
- async handleDownloads(fileName = 'downloads') {
1265
+ async handleDownloads(fileName) {
1227
1266
  this.page.waitForEvent('download').then(async (download) => {
1228
1267
  const filePath = await download.path();
1229
- const downloadPath = path.join(global.output_dir, fileName || path.basename(filePath));
1268
+ fileName = fileName || `downloads/${path.basename(filePath)}`;
1269
+
1270
+ const downloadPath = path.join(global.output_dir, fileName);
1230
1271
  if (!fs.existsSync(path.dirname(downloadPath))) {
1231
1272
  fs.mkdirSync(path.dirname(downloadPath), '0777');
1232
1273
  }
@@ -1469,7 +1510,7 @@ class Playwright extends Helper {
1469
1510
  throw new Error(`File at ${file} can not be found on local system`);
1470
1511
  }
1471
1512
  const els = await findFields.call(this, locator);
1472
- assertElementExists(els, 'Field');
1513
+ assertElementExists(els, locator, 'Field');
1473
1514
  await els[0].setInputFiles(file);
1474
1515
  return this._waitForAction();
1475
1516
  }
@@ -1623,7 +1664,7 @@ class Playwright extends Helper {
1623
1664
  */
1624
1665
  async seeNumberOfElements(locator, num) {
1625
1666
  const elements = await this._locate(locator);
1626
- return equals(`expected number of elements (${locator}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
1667
+ return equals(`expected number of elements (${(new Locator(locator))}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
1627
1668
  }
1628
1669
 
1629
1670
  /**
@@ -1633,7 +1674,7 @@ class Playwright extends Helper {
1633
1674
  */
1634
1675
  async seeNumberOfVisibleElements(locator, num) {
1635
1676
  const res = await this.grabNumberOfVisibleElements(locator);
1636
- return equals(`expected number of visible elements (${locator}) is ${num}, but found ${res}`).assert(res, num);
1677
+ return equals(`expected number of visible elements (${(new Locator(locator))}) is ${num}, but found ${res}`).assert(res, num);
1637
1678
  }
1638
1679
 
1639
1680
  /**
@@ -1707,6 +1748,7 @@ class Playwright extends Helper {
1707
1748
  *
1708
1749
  * @param {string|function} fn function to be executed in browser context.
1709
1750
  * @param {any} [arg] optional argument to pass to the function
1751
+ * @returns {Promise<any>}
1710
1752
  */
1711
1753
  async executeScript(fn, arg) {
1712
1754
  let context = this.page;
@@ -1854,7 +1896,7 @@ class Playwright extends Helper {
1854
1896
  }
1855
1897
  return true;
1856
1898
  });
1857
- return equals(`all elements (${locator}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
1899
+ return equals(`all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
1858
1900
  }
1859
1901
 
1860
1902
  /**
@@ -1883,7 +1925,7 @@ class Playwright extends Helper {
1883
1925
  }
1884
1926
  return true;
1885
1927
  });
1886
- return equals(`all elements (${locator}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount);
1928
+ return equals(`all elements (${(new Locator(locator))}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount);
1887
1929
  }
1888
1930
 
1889
1931
  /**
@@ -1947,7 +1989,7 @@ class Playwright extends Helper {
1947
1989
  assertElementExists(res, locator);
1948
1990
  if (res.length > 1) this.debug(`[Elements] Using first element out of ${res.length}`);
1949
1991
  const elem = res[0];
1950
- this.debug(`Screenshot of ${locator} element has been saved to ${outputFile}`);
1992
+ this.debug(`Screenshot of ${(new Locator(locator))} element has been saved to ${outputFile}`);
1951
1993
  return elem.screenshot({ path: outputFile, type: 'png' });
1952
1994
  }
1953
1995
 
@@ -2030,29 +2072,28 @@ class Playwright extends Helper {
2030
2072
  }
2031
2073
 
2032
2074
  if (this.options.recordVideo && this.page && this.page.video()) {
2033
- const videoPath = `${global.output_dir}/videos/${clearString(test.title)}.failed.webm`;
2034
- test.artifacts.video = await this.page.video().path();
2035
- fs.rename(test.artifacts.video, videoPath, (() => {
2036
- test.artifacts.video = videoPath;
2037
- }));
2075
+ test.artifacts.video = await saveVideoForPage(this.page, `${test.title}.failed`);
2076
+ for (const sessionName in this.sessionPages) {
2077
+ test.artifacts[`video_${sessionName}`] = await saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.failed`);
2078
+ }
2038
2079
  }
2039
2080
 
2040
2081
  if (this.options.trace) {
2041
- const path = `${`${global.output_dir}/trace/${clearString(test.title)}`.slice(0, 251)}.zip`;
2042
- await this.browserContext.tracing.stop({ path });
2043
- test.artifacts.trace = path;
2082
+ test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.failed`);
2083
+ for (const sessionName in this.sessionPages) {
2084
+ if (!this.sessionPages[sessionName].context) continue;
2085
+ test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context(), `${test.title}_${sessionName}.failed`);
2086
+ }
2044
2087
  }
2045
2088
  }
2046
2089
 
2047
2090
  async _passed(test) {
2048
2091
  if (this.options.recordVideo && this.page && this.page.video()) {
2049
- const videoPath = `${global.output_dir}/videos/${clearString(test.title)}.passed.webm`;
2050
-
2051
2092
  if (this.options.keepVideoForPassedTests) {
2052
- test.artifacts.video = await this.page.video().path();
2053
- fs.rename(test.artifacts.video, videoPath, (() => {
2054
- test.artifacts.video = videoPath;
2055
- }));
2093
+ test.artifacts.video = await saveVideoForPage(this.page, `${test.title}.passed`);
2094
+ for (const sessionName of Object.keys(this.sessionPages)) {
2095
+ test.artifacts[`video_${sessionName}`] = await saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.passed`);
2096
+ }
2056
2097
  } else {
2057
2098
  this.page.video().delete().catch(e => {});
2058
2099
  }
@@ -2060,9 +2101,13 @@ class Playwright extends Helper {
2060
2101
 
2061
2102
  if (this.options.trace) {
2062
2103
  if (this.options.keepTraceForPassedTests) {
2063
- const path = `${global.output_dir}/trace/${clearString(test.title)}.zip`;
2064
- await this.browserContext.tracing.stop({ path });
2065
- test.artifacts.trace = path;
2104
+ if (this.options.trace) {
2105
+ test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.passed`);
2106
+ for (const sessionName in this.sessionPages) {
2107
+ if (!this.sessionPages[sessionName].context) continue;
2108
+ test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context(), `${test.title}_${sessionName}.passed`);
2109
+ }
2110
+ }
2066
2111
  } else {
2067
2112
  await this.browserContext.tracing.stop();
2068
2113
  }
@@ -2783,7 +2828,7 @@ async function targetCreatedHandler(page) {
2783
2828
  page.on('load', () => {
2784
2829
  page.$('body')
2785
2830
  .catch(() => null)
2786
- .then(async context => {
2831
+ .then(async () => {
2787
2832
  if (this.context && this.context._type === 'Frame') {
2788
2833
  // we are inside iframe?
2789
2834
  const frameEl = await this.context.frameElement();
@@ -2808,7 +2853,7 @@ async function targetCreatedHandler(page) {
2808
2853
  try {
2809
2854
  await page.setViewportSize(parseWindowSize(this.options.windowSize));
2810
2855
  } catch (err) {
2811
- // target can be already closed, ignoring...
2856
+ this.debug('Target can be already closed, ignoring...');
2812
2857
  }
2813
2858
  }
2814
2859
  }
@@ -2933,3 +2978,21 @@ async function refreshContextSession() {
2933
2978
  });
2934
2979
  }
2935
2980
  }
2981
+
2982
+ async function saveVideoForPage(page, name) {
2983
+ if (!page.video()) return null;
2984
+ const fileName = `${global.output_dir}${pathSeparator}videos${pathSeparator}${Date.now()}_${clearString(name).slice(0, 245)}.webm`;
2985
+ page.video().saveAs(fileName).then(() => {
2986
+ if (!page) return;
2987
+ page.video().delete().catch(e => {});
2988
+ });
2989
+ return fileName;
2990
+ }
2991
+
2992
+ async function saveTraceForContext(context, name) {
2993
+ if (!context) return;
2994
+ if (!context.tracing) return;
2995
+ const fileName = `${`${global.output_dir}${pathSeparator}trace${pathSeparator}${Date.now()}_${clearString(name)}`.slice(0, 245)}.zip`;
2996
+ await context.tracing.stop({ path: fileName });
2997
+ return fileName;
2998
+ }
@@ -153,7 +153,7 @@ class Protractor extends Helper {
153
153
  if (config.proxy) config.capabilities.proxy = config.proxy;
154
154
  if (config.browser) config.capabilities.browserName = config.browser;
155
155
 
156
- config.waitForTimeout /= 1000; // convert to seconds
156
+ config.waitForTimeoutInSeconds = config.waitForTimeout / 1000; // convert to seconds
157
157
  return config;
158
158
  }
159
159
 
@@ -722,7 +722,7 @@ class Protractor extends Helper {
722
722
  */
723
723
  async grabTextFrom(locator) {
724
724
  const texts = await this.grabTextFromAll(locator);
725
- assertElementExists(texts);
725
+ assertElementExists(texts, locator);
726
726
  if (texts.length > 1) {
727
727
  this.debugSection('GrabText', `Using first element out of ${texts.length}`);
728
728
  }
@@ -748,7 +748,7 @@ class Protractor extends Helper {
748
748
  */
749
749
  async grabHTMLFrom(locator) {
750
750
  const html = await this.grabHTMLFromAll(locator);
751
- assertElementExists(html);
751
+ assertElementExists(html, locator);
752
752
  if (html.length > 1) {
753
753
  this.debugSection('GrabHTMl', `Using first element out of ${html.length}`);
754
754
  }
@@ -920,7 +920,7 @@ class Protractor extends Helper {
920
920
  */
921
921
  async seeNumberOfElements(locator, num) {
922
922
  const elements = await this._locate(locator);
923
- return equals(`expected number of elements (${locator}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
923
+ return equals(`expected number of elements (${(new Locator(locator))}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
924
924
  }
925
925
 
926
926
  /**
@@ -928,7 +928,7 @@ class Protractor extends Helper {
928
928
  */
929
929
  async seeNumberOfVisibleElements(locator, num) {
930
930
  const res = await this.grabNumberOfVisibleElements(locator);
931
- return equals(`expected number of visible elements (${locator}) is ${num}, but found ${res}`).assert(res, num);
931
+ return equals(`expected number of visible elements (${(new Locator(locator))}) is ${num}, but found ${res}`).assert(res, num);
932
932
  }
933
933
 
934
934
  /**
@@ -968,7 +968,7 @@ class Protractor extends Helper {
968
968
  missingAttributes.push(...missing);
969
969
  }
970
970
  }
971
- return equals(`all elements (${locator}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(missingAttributes.length, 0);
971
+ return equals(`all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(missingAttributes.length, 0);
972
972
  }
973
973
 
974
974
  /**
@@ -995,7 +995,7 @@ class Protractor extends Helper {
995
995
  }
996
996
  }
997
997
 
998
- return equals(`all elements (${locator}) to have attributes ${JSON.stringify(attributes)}`).assert(missingAttributes.length, 0);
998
+ return equals(`all elements (${(new Locator(locator))}) to have attributes ${JSON.stringify(attributes)}`).assert(missingAttributes.length, 0);
999
999
  }
1000
1000
 
1001
1001
  /**
@@ -1060,7 +1060,7 @@ class Protractor extends Helper {
1060
1060
  assertElementExists(res, locator);
1061
1061
  if (res.length > 1) this.debug(`[Elements] Using first element out of ${res.length}`);
1062
1062
  const elem = res[0];
1063
- this.debug(`Screenshot of ${locator} element has been saved to ${outputFile}`);
1063
+ this.debug(`Screenshot of ${(new Locator(locator))} element has been saved to ${outputFile}`);
1064
1064
  const png = await elem.takeScreenshot();
1065
1065
  return writeFile(png, outputFile);
1066
1066
  }
@@ -1200,8 +1200,8 @@ class Protractor extends Helper {
1200
1200
  async dragAndDrop(srcElement, destElement) {
1201
1201
  const srcEl = await this._locate(srcElement, true);
1202
1202
  const destEl = await this._locate(destElement, true);
1203
- assertElementExists(srcEl);
1204
- assertElementExists(destEl);
1203
+ assertElementExists(srcEl, srcElement);
1204
+ assertElementExists(destEl, destElement);
1205
1205
  return this.browser
1206
1206
  .actions()
1207
1207
  .dragAndDrop(srcEl[0], destEl[0])
@@ -1348,7 +1348,7 @@ class Protractor extends Helper {
1348
1348
  * {{> waitForElement }}
1349
1349
  */
1350
1350
  async waitForElement(locator, sec = null) {
1351
- const aSec = sec || this.options.waitForTimeout;
1351
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1352
1352
  const el = global.element(guessLocator(locator) || global.by.css(locator));
1353
1353
  return this.browser.wait(EC.presenceOf(el), aSec * 1000);
1354
1354
  }
@@ -1364,7 +1364,7 @@ class Protractor extends Helper {
1364
1364
  * {{> waitForDetached }}
1365
1365
  */
1366
1366
  async waitForDetached(locator, sec = null) {
1367
- const aSec = sec || this.options.waitForTimeout;
1367
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1368
1368
  const el = global.element(guessLocator(locator) || global.by.css(locator));
1369
1369
  return this.browser.wait(EC.not(EC.presenceOf(el)), aSec * 1000).catch((err) => {
1370
1370
  if (err.message && err.message.indexOf('Wait timed out after') > -1) {
@@ -1381,7 +1381,7 @@ class Protractor extends Helper {
1381
1381
  * ```
1382
1382
  */
1383
1383
  async waitForClickable(locator, sec = null) {
1384
- const aSec = sec || this.options.waitForTimeout;
1384
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1385
1385
  const el = global.element(guessLocator(locator) || global.by.css(locator));
1386
1386
  return this.browser.wait(EC.elementToBeClickable(el), aSec * 1000);
1387
1387
  }
@@ -1390,7 +1390,7 @@ class Protractor extends Helper {
1390
1390
  * {{> waitForVisible }}
1391
1391
  */
1392
1392
  async waitForVisible(locator, sec = null) {
1393
- const aSec = sec || this.options.waitForTimeout;
1393
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1394
1394
  const el = global.element(guessLocator(locator) || global.by.css(locator));
1395
1395
  return this.browser.wait(EC.visibilityOf(el), aSec * 1000);
1396
1396
  }
@@ -1406,7 +1406,7 @@ class Protractor extends Helper {
1406
1406
  * {{> waitForInvisible }}
1407
1407
  */
1408
1408
  async waitForInvisible(locator, sec = null) {
1409
- const aSec = sec || this.options.waitForTimeout;
1409
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1410
1410
  const el = global.element(guessLocator(locator) || global.by.css(locator));
1411
1411
  return this.browser.wait(EC.invisibilityOf(el), aSec * 1000);
1412
1412
  }
@@ -1431,12 +1431,12 @@ class Protractor extends Helper {
1431
1431
  };
1432
1432
  }
1433
1433
 
1434
- const aSec = sec || this.options.waitForTimeout;
1434
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1435
1435
  const guessLoc = guessLocator(locator) || global.by.css(locator);
1436
1436
 
1437
1437
  return this.browser.wait(visibilityCountOf(guessLoc, num), aSec * 1000)
1438
1438
  .catch(() => {
1439
- throw Error(`The number of elements (${locator}) is not ${num} after ${aSec} sec`);
1439
+ throw Error(`The number of elements (${(new Locator(locator))}) is not ${num} after ${aSec} sec`);
1440
1440
  });
1441
1441
  }
1442
1442
 
@@ -1444,12 +1444,12 @@ class Protractor extends Helper {
1444
1444
  * {{> waitForEnabled }}
1445
1445
  */
1446
1446
  async waitForEnabled(locator, sec = null) {
1447
- const aSec = sec || this.options.waitForTimeout;
1447
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1448
1448
  const el = global.element(guessLocator(locator) || global.by.css(locator));
1449
1449
 
1450
1450
  return this.browser.wait(EC.elementToBeClickable(el), aSec * 1000)
1451
1451
  .catch(() => {
1452
- throw Error(`element (${locator}) still not enabled after ${aSec} sec`);
1452
+ throw Error(`element (${(new Locator(locator))}) still not enabled after ${aSec} sec`);
1453
1453
  });
1454
1454
  }
1455
1455
 
@@ -1457,7 +1457,7 @@ class Protractor extends Helper {
1457
1457
  * {{> waitForValue }}
1458
1458
  */
1459
1459
  async waitForValue(field, value, sec = null) {
1460
- const aSec = sec || this.options.waitForTimeout;
1460
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1461
1461
 
1462
1462
  const valueToBeInElementValue = (loc) => {
1463
1463
  return async () => {
@@ -1490,7 +1490,7 @@ class Protractor extends Helper {
1490
1490
  }
1491
1491
  }
1492
1492
 
1493
- const aSec = sec || this.options.waitForTimeout;
1493
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1494
1494
  return this.browser.wait(() => this.browser.executeScript.call(this.browser, fn, ...args), aSec * 1000);
1495
1495
  }
1496
1496
 
@@ -1498,7 +1498,7 @@ class Protractor extends Helper {
1498
1498
  * {{> waitInUrl }}
1499
1499
  */
1500
1500
  async waitInUrl(urlPart, sec = null) {
1501
- const aSec = sec || this.options.waitForTimeout;
1501
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1502
1502
  const waitTimeout = aSec * 1000;
1503
1503
 
1504
1504
  return this.browser.wait(EC.urlContains(urlPart), waitTimeout)
@@ -1516,7 +1516,7 @@ class Protractor extends Helper {
1516
1516
  * {{> waitUrlEquals }}
1517
1517
  */
1518
1518
  async waitUrlEquals(urlPart, sec = null) {
1519
- const aSec = sec || this.options.waitForTimeout;
1519
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1520
1520
  const waitTimeout = aSec * 1000;
1521
1521
  const baseUrl = this.options.url;
1522
1522
  if (urlPart.indexOf('http') < 0) {
@@ -1542,7 +1542,7 @@ class Protractor extends Helper {
1542
1542
  context = this.context;
1543
1543
  }
1544
1544
  const el = global.element(guessLocator(context) || global.by.css(context));
1545
- const aSec = sec || this.options.waitForTimeout;
1545
+ const aSec = sec || this.options.waitForTimeoutInSeconds;
1546
1546
  return this.browser.wait(EC.textToBePresentInElement(el, text), aSec * 1000);
1547
1547
  }
1548
1548
 
@@ -1583,7 +1583,7 @@ class Protractor extends Helper {
1583
1583
  if (locator) {
1584
1584
  const res = await this._locate(locator, true);
1585
1585
  if (!res || res.length === 0) {
1586
- return truth(`elements of ${locator}`, 'to be seen').assert(false);
1586
+ return truth(`elements of ${(new Locator(locator))}`, 'to be seen').assert(false);
1587
1587
  }
1588
1588
  const elem = res[0];
1589
1589
  const location = await elem.getLocation();
@@ -696,7 +696,7 @@ class Puppeteer extends Helper {
696
696
  */
697
697
  async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
698
698
  const els = await this._locate(locator);
699
- assertElementExists(els);
699
+ assertElementExists(els, locator);
700
700
 
701
701
  // Use manual mouse.move instead of .hover() so the offset can be added to the coordinates
702
702
  const { x, y } = await getClickablePoint(els[0]);
@@ -1336,7 +1336,7 @@ class Puppeteer extends Helper {
1336
1336
  throw new Error(`File at ${file} can not be found on local system`);
1337
1337
  }
1338
1338
  const els = await findFields.call(this, locator);
1339
- assertElementExists(els, 'Field');
1339
+ assertElementExists(els, locator, 'Field');
1340
1340
  await els[0].uploadFile(file);
1341
1341
  return this._waitForAction();
1342
1342
  }
@@ -1491,7 +1491,7 @@ class Puppeteer extends Helper {
1491
1491
  */
1492
1492
  async seeNumberOfElements(locator, num) {
1493
1493
  const elements = await this._locate(locator);
1494
- return equals(`expected number of elements (${locator}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
1494
+ return equals(`expected number of elements (${(new Locator(locator))}) is ${num}, but found ${elements.length}`).assert(elements.length, num);
1495
1495
  }
1496
1496
 
1497
1497
  /**
@@ -1501,7 +1501,7 @@ class Puppeteer extends Helper {
1501
1501
  */
1502
1502
  async seeNumberOfVisibleElements(locator, num) {
1503
1503
  const res = await this.grabNumberOfVisibleElements(locator);
1504
- return equals(`expected number of visible elements (${locator}) is ${num}, but found ${res}`).assert(res, num);
1504
+ return equals(`expected number of visible elements (${(new Locator(locator))}) is ${num}, but found ${res}`).assert(res, num);
1505
1505
  }
1506
1506
 
1507
1507
  /**
@@ -1725,7 +1725,7 @@ class Puppeteer extends Helper {
1725
1725
  }
1726
1726
  return true;
1727
1727
  });
1728
- return equals(`all elements (${locator}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
1728
+ return equals(`all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
1729
1729
  }
1730
1730
 
1731
1731
  /**
@@ -1756,7 +1756,7 @@ class Puppeteer extends Helper {
1756
1756
  }
1757
1757
  return true;
1758
1758
  });
1759
- return equals(`all elements (${locator}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount);
1759
+ return equals(`all elements (${(new Locator(locator))}) to have attributes ${JSON.stringify(attributes)}`).assert(chunked.length, elemAmount);
1760
1760
  }
1761
1761
 
1762
1762
  /**
@@ -1819,7 +1819,7 @@ class Puppeteer extends Helper {
1819
1819
  assertElementExists(res, locator);
1820
1820
  if (res.length > 1) this.debug(`[Elements] Using first element out of ${res.length}`);
1821
1821
  const elem = res[0];
1822
- this.debug(`Screenshot of ${locator} element has been saved to ${outputFile}`);
1822
+ this.debug(`Screenshot of ${(new Locator(locator))} element has been saved to ${outputFile}`);
1823
1823
  return elem.screenshot({ path: outputFile, type: 'png' });
1824
1824
  }
1825
1825