codeceptjs 3.3.7-beta.1 → 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 -41
  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
 
@@ -477,8 +482,6 @@ class Playwright extends Helper {
477
482
 
478
483
  // close other sessions
479
484
  try {
480
- if (!this.browser.contexts) return this.browser;
481
-
482
485
  const contexts = await this.browser.contexts();
483
486
  const currentContext = contexts[0];
484
487
  if (currentContext && (this.options.keepCookies || this.options.keepBrowserState)) {
@@ -515,12 +518,13 @@ class Playwright extends Helper {
515
518
  browserContext = browser.context();
516
519
  page = await browser.firstWindow();
517
520
  } else {
518
- browserContext = await this.browser.newContext(config);
521
+ browserContext = await this.browser.newContext(Object.assign(this.options, config));
519
522
  page = await browserContext.newPage();
520
523
  }
521
524
 
522
- targetCreatedHandler.call(this, page);
523
- 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);
524
528
  // Create a new page inside context.
525
529
  return browserContext;
526
530
  },
@@ -734,6 +738,19 @@ class Playwright extends Helper {
734
738
  });
735
739
 
736
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);
737
754
  }
738
755
 
739
756
  _getType() {
@@ -802,8 +819,8 @@ class Playwright extends Helper {
802
819
  if (this.isElectron) {
803
820
  throw new Error('Cannot open pages inside an Electron container');
804
821
  }
805
- if (!(/^\w+\:\/\//.test(url))) {
806
- url = this.options.url + url;
822
+ if (!(/^\w+\:(\/\/|.+)/.test(url))) {
823
+ url = this.options.url + (url.startsWith('/') ? url : `/${url}`);
807
824
  }
808
825
 
809
826
  if (this.options.basicAuth && (this.isAuthenticated !== true)) {
@@ -876,7 +893,7 @@ class Playwright extends Helper {
876
893
  */
877
894
  async moveCursorTo(locator, offsetX = 0, offsetY = 0) {
878
895
  const els = await this._locate(locator);
879
- assertElementExists(els);
896
+ assertElementExists(els, locator);
880
897
 
881
898
  // Use manual mouse.move instead of .hover() so the offset can be added to the coordinates
882
899
  const { x, y } = await clickablePoint(els[0]);
@@ -903,6 +920,26 @@ class Playwright extends Helper {
903
920
  return this.page.dragAndDrop(buildLocatorString(src), buildLocatorString(dst), options);
904
921
  }
905
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
+
906
943
  /**
907
944
  * {{> refreshPage }}
908
945
  */
@@ -1075,7 +1112,7 @@ class Playwright extends Helper {
1075
1112
  if (!page) {
1076
1113
  throw new Error(`There is no ability to switch to next tab with offset ${num}`);
1077
1114
  }
1078
- targetCreatedHandler.call(this, page);
1115
+ await targetCreatedHandler.call(this, page);
1079
1116
  await this._setPage(page);
1080
1117
  return this._waitForAction();
1081
1118
  }
@@ -1159,7 +1196,7 @@ class Playwright extends Helper {
1159
1196
  throw new Error('Cannot open new tabs inside an Electron container');
1160
1197
  }
1161
1198
  const page = await this.browserContext.newPage(options);
1162
- targetCreatedHandler.call(this, page);
1199
+ await targetCreatedHandler.call(this, page);
1163
1200
  await this._setPage(page);
1164
1201
  return this._waitForAction();
1165
1202
  }
@@ -1209,7 +1246,7 @@ class Playwright extends Helper {
1209
1246
  }
1210
1247
 
1211
1248
  /**
1212
- * 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.
1213
1250
  * Files are saved to "output" directory.
1214
1251
  *
1215
1252
  * Should be used with [FileSystem helper](https://codecept.io/helpers/FileSystem) to check that file were downloaded correctly.
@@ -1218,17 +1255,19 @@ class Playwright extends Helper {
1218
1255
  * I.handleDownloads('downloads/avatar.jpg');
1219
1256
  * I.click('Download Avatar');
1220
1257
  * I.amInPath('output/downloads');
1221
- * I.waitForFile('downloads/avatar.jpg', 5);
1258
+ * I.waitForFile('avatar.jpg', 5);
1222
1259
  *
1223
1260
  * ```
1224
1261
  *
1225
1262
  * @param {string} [fileName] set filename for downloaded file
1226
1263
  * @return {Promise<void>}
1227
1264
  */
1228
- async handleDownloads(fileName = 'downloads') {
1265
+ async handleDownloads(fileName) {
1229
1266
  this.page.waitForEvent('download').then(async (download) => {
1230
1267
  const filePath = await download.path();
1231
- 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);
1232
1271
  if (!fs.existsSync(path.dirname(downloadPath))) {
1233
1272
  fs.mkdirSync(path.dirname(downloadPath), '0777');
1234
1273
  }
@@ -1471,7 +1510,7 @@ class Playwright extends Helper {
1471
1510
  throw new Error(`File at ${file} can not be found on local system`);
1472
1511
  }
1473
1512
  const els = await findFields.call(this, locator);
1474
- assertElementExists(els, 'Field');
1513
+ assertElementExists(els, locator, 'Field');
1475
1514
  await els[0].setInputFiles(file);
1476
1515
  return this._waitForAction();
1477
1516
  }
@@ -1625,7 +1664,7 @@ class Playwright extends Helper {
1625
1664
  */
1626
1665
  async seeNumberOfElements(locator, num) {
1627
1666
  const elements = await this._locate(locator);
1628
- 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);
1629
1668
  }
1630
1669
 
1631
1670
  /**
@@ -1635,7 +1674,7 @@ class Playwright extends Helper {
1635
1674
  */
1636
1675
  async seeNumberOfVisibleElements(locator, num) {
1637
1676
  const res = await this.grabNumberOfVisibleElements(locator);
1638
- 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);
1639
1678
  }
1640
1679
 
1641
1680
  /**
@@ -1709,6 +1748,7 @@ class Playwright extends Helper {
1709
1748
  *
1710
1749
  * @param {string|function} fn function to be executed in browser context.
1711
1750
  * @param {any} [arg] optional argument to pass to the function
1751
+ * @returns {Promise<any>}
1712
1752
  */
1713
1753
  async executeScript(fn, arg) {
1714
1754
  let context = this.page;
@@ -1856,7 +1896,7 @@ class Playwright extends Helper {
1856
1896
  }
1857
1897
  return true;
1858
1898
  });
1859
- 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);
1860
1900
  }
1861
1901
 
1862
1902
  /**
@@ -1885,7 +1925,7 @@ class Playwright extends Helper {
1885
1925
  }
1886
1926
  return true;
1887
1927
  });
1888
- 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);
1889
1929
  }
1890
1930
 
1891
1931
  /**
@@ -1949,7 +1989,7 @@ class Playwright extends Helper {
1949
1989
  assertElementExists(res, locator);
1950
1990
  if (res.length > 1) this.debug(`[Elements] Using first element out of ${res.length}`);
1951
1991
  const elem = res[0];
1952
- 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}`);
1953
1993
  return elem.screenshot({ path: outputFile, type: 'png' });
1954
1994
  }
1955
1995
 
@@ -2032,29 +2072,28 @@ class Playwright extends Helper {
2032
2072
  }
2033
2073
 
2034
2074
  if (this.options.recordVideo && this.page && this.page.video()) {
2035
- const videoPath = `${global.output_dir}/videos/${clearString(test.title)}.failed.webm`;
2036
- test.artifacts.video = await this.page.video().path();
2037
- fs.rename(test.artifacts.video, videoPath, (() => {
2038
- test.artifacts.video = videoPath;
2039
- }));
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
+ }
2040
2079
  }
2041
2080
 
2042
2081
  if (this.options.trace) {
2043
- const path = `${`${global.output_dir}/trace/${clearString(test.title)}`.slice(0, 251)}.zip`;
2044
- await this.browserContext.tracing.stop({ path });
2045
- 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
+ }
2046
2087
  }
2047
2088
  }
2048
2089
 
2049
2090
  async _passed(test) {
2050
2091
  if (this.options.recordVideo && this.page && this.page.video()) {
2051
- const videoPath = `${global.output_dir}/videos/${clearString(test.title)}.passed.webm`;
2052
-
2053
2092
  if (this.options.keepVideoForPassedTests) {
2054
- test.artifacts.video = await this.page.video().path();
2055
- fs.rename(test.artifacts.video, videoPath, (() => {
2056
- test.artifacts.video = videoPath;
2057
- }));
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
+ }
2058
2097
  } else {
2059
2098
  this.page.video().delete().catch(e => {});
2060
2099
  }
@@ -2062,9 +2101,13 @@ class Playwright extends Helper {
2062
2101
 
2063
2102
  if (this.options.trace) {
2064
2103
  if (this.options.keepTraceForPassedTests) {
2065
- const path = `${global.output_dir}/trace/${clearString(test.title)}.zip`;
2066
- await this.browserContext.tracing.stop({ path });
2067
- 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
+ }
2068
2111
  } else {
2069
2112
  await this.browserContext.tracing.stop();
2070
2113
  }
@@ -2785,7 +2828,7 @@ async function targetCreatedHandler(page) {
2785
2828
  page.on('load', () => {
2786
2829
  page.$('body')
2787
2830
  .catch(() => null)
2788
- .then(async context => {
2831
+ .then(async () => {
2789
2832
  if (this.context && this.context._type === 'Frame') {
2790
2833
  // we are inside iframe?
2791
2834
  const frameEl = await this.context.frameElement();
@@ -2810,7 +2853,7 @@ async function targetCreatedHandler(page) {
2810
2853
  try {
2811
2854
  await page.setViewportSize(parseWindowSize(this.options.windowSize));
2812
2855
  } catch (err) {
2813
- // target can be already closed, ignoring...
2856
+ this.debug('Target can be already closed, ignoring...');
2814
2857
  }
2815
2858
  }
2816
2859
  }
@@ -2935,3 +2978,21 @@ async function refreshContextSession() {
2935
2978
  });
2936
2979
  }
2937
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