codeceptjs 3.5.5 → 3.5.7-beta.1

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 (151) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/docs/bdd.md +11 -7
  3. package/docs/build/ApiDataFactory.js +2 -1
  4. package/docs/build/Appium.js +25 -23
  5. package/docs/build/Expect.js +422 -0
  6. package/docs/build/FileSystem.js +1 -1
  7. package/docs/build/Nightmare.js +53 -56
  8. package/docs/build/Playwright.js +209 -135
  9. package/docs/build/Protractor.js +66 -69
  10. package/docs/build/Puppeteer.js +83 -83
  11. package/docs/build/TestCafe.js +56 -55
  12. package/docs/build/WebDriver.js +85 -86
  13. package/docs/changelog.md +63 -0
  14. package/docs/commands.md +12 -0
  15. package/docs/helpers/Appium.md +50 -32
  16. package/docs/helpers/Expect.md +275 -0
  17. package/docs/helpers/FileSystem.md +1 -1
  18. package/docs/helpers/Nightmare.md +141 -94
  19. package/docs/helpers/Playwright.md +281 -212
  20. package/docs/helpers/Protractor.md +229 -169
  21. package/docs/helpers/Puppeteer.md +257 -186
  22. package/docs/helpers/TestCafe.md +201 -149
  23. package/docs/helpers/WebDriver.md +253 -179
  24. package/docs/mobile.md +17 -21
  25. package/docs/plugins.md +35 -1
  26. package/docs/webapi/amOnPage.mustache +1 -1
  27. package/docs/webapi/appendField.mustache +1 -1
  28. package/docs/webapi/attachFile.mustache +1 -1
  29. package/docs/webapi/blur.mustache +1 -0
  30. package/docs/webapi/checkOption.mustache +1 -1
  31. package/docs/webapi/clearCookie.mustache +1 -1
  32. package/docs/webapi/clearField.mustache +1 -1
  33. package/docs/webapi/click.mustache +1 -1
  34. package/docs/webapi/clickLink.mustache +1 -1
  35. package/docs/webapi/closeCurrentTab.mustache +1 -1
  36. package/docs/webapi/closeOtherTabs.mustache +1 -1
  37. package/docs/webapi/dontSee.mustache +1 -1
  38. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +1 -1
  39. package/docs/webapi/dontSeeCookie.mustache +1 -1
  40. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +1 -1
  41. package/docs/webapi/dontSeeElement.mustache +1 -1
  42. package/docs/webapi/dontSeeElementInDOM.mustache +1 -1
  43. package/docs/webapi/dontSeeInCurrentUrl.mustache +1 -1
  44. package/docs/webapi/dontSeeInField.mustache +1 -1
  45. package/docs/webapi/dontSeeInSource.mustache +1 -1
  46. package/docs/webapi/dontSeeInTitle.mustache +1 -1
  47. package/docs/webapi/doubleClick.mustache +1 -1
  48. package/docs/webapi/downloadFile.mustache +1 -1
  49. package/docs/webapi/dragAndDrop.mustache +1 -1
  50. package/docs/webapi/dragSlider.mustache +1 -1
  51. package/docs/webapi/executeAsyncScript.mustache +0 -2
  52. package/docs/webapi/executeScript.mustache +0 -2
  53. package/docs/webapi/fillField.mustache +1 -1
  54. package/docs/webapi/focus.mustache +1 -0
  55. package/docs/webapi/forceClick.mustache +1 -1
  56. package/docs/webapi/forceRightClick.mustache +1 -1
  57. package/docs/webapi/grabCookie.mustache +1 -1
  58. package/docs/webapi/grabDataFromPerformanceTiming.mustache +1 -1
  59. package/docs/webapi/moveCursorTo.mustache +1 -1
  60. package/docs/webapi/openNewTab.mustache +1 -1
  61. package/docs/webapi/pressKey.mustache +1 -1
  62. package/docs/webapi/pressKeyDown.mustache +1 -1
  63. package/docs/webapi/pressKeyUp.mustache +1 -1
  64. package/docs/webapi/pressKeyWithKeyNormalization.mustache +1 -1
  65. package/docs/webapi/refreshPage.mustache +1 -1
  66. package/docs/webapi/resizeWindow.mustache +1 -1
  67. package/docs/webapi/rightClick.mustache +1 -1
  68. package/docs/webapi/saveElementScreenshot.mustache +1 -1
  69. package/docs/webapi/saveScreenshot.mustache +1 -1
  70. package/docs/webapi/say.mustache +1 -1
  71. package/docs/webapi/scrollIntoView.mustache +1 -1
  72. package/docs/webapi/scrollPageToBottom.mustache +1 -1
  73. package/docs/webapi/scrollPageToTop.mustache +1 -1
  74. package/docs/webapi/scrollTo.mustache +1 -1
  75. package/docs/webapi/see.mustache +1 -1
  76. package/docs/webapi/seeAttributesOnElements.mustache +1 -1
  77. package/docs/webapi/seeCheckboxIsChecked.mustache +1 -1
  78. package/docs/webapi/seeCookie.mustache +1 -1
  79. package/docs/webapi/seeCssPropertiesOnElements.mustache +1 -1
  80. package/docs/webapi/seeCurrentUrlEquals.mustache +1 -1
  81. package/docs/webapi/seeElement.mustache +1 -1
  82. package/docs/webapi/seeElementInDOM.mustache +1 -1
  83. package/docs/webapi/seeInCurrentUrl.mustache +1 -1
  84. package/docs/webapi/seeInField.mustache +1 -1
  85. package/docs/webapi/seeInPopup.mustache +1 -1
  86. package/docs/webapi/seeInSource.mustache +1 -1
  87. package/docs/webapi/seeInTitle.mustache +1 -1
  88. package/docs/webapi/seeNumberOfElements.mustache +1 -1
  89. package/docs/webapi/seeNumberOfVisibleElements.mustache +1 -1
  90. package/docs/webapi/seeTextEquals.mustache +1 -1
  91. package/docs/webapi/seeTitleEquals.mustache +1 -1
  92. package/docs/webapi/selectOption.mustache +1 -1
  93. package/docs/webapi/setCookie.mustache +1 -1
  94. package/docs/webapi/setGeoLocation.mustache +1 -1
  95. package/docs/webapi/switchTo.mustache +1 -1
  96. package/docs/webapi/switchToNextTab.mustache +1 -1
  97. package/docs/webapi/switchToPreviousTab.mustache +1 -1
  98. package/docs/webapi/type.mustache +1 -1
  99. package/docs/webapi/uncheckOption.mustache +1 -1
  100. package/docs/webapi/wait.mustache +1 -1
  101. package/docs/webapi/waitForClickable.mustache +1 -1
  102. package/docs/webapi/waitForDetached.mustache +1 -1
  103. package/docs/webapi/waitForElement.mustache +1 -1
  104. package/docs/webapi/waitForEnabled.mustache +1 -1
  105. package/docs/webapi/waitForFunction.mustache +1 -1
  106. package/docs/webapi/waitForInvisible.mustache +1 -1
  107. package/docs/webapi/waitForText.mustache +1 -1
  108. package/docs/webapi/waitForValue.mustache +1 -1
  109. package/docs/webapi/waitForVisible.mustache +1 -1
  110. package/docs/webapi/waitInUrl.mustache +1 -1
  111. package/docs/webapi/waitNumberOfVisibleElements.mustache +1 -1
  112. package/docs/webapi/waitToHide.mustache +1 -1
  113. package/docs/webapi/waitUrlEquals.mustache +1 -1
  114. package/lib/ai.js +12 -3
  115. package/lib/cli.js +3 -1
  116. package/lib/codecept.js +3 -0
  117. package/lib/command/dryRun.js +2 -1
  118. package/lib/command/info.js +24 -0
  119. package/lib/command/run-workers.js +3 -2
  120. package/lib/command/run.js +3 -2
  121. package/lib/data/context.js +14 -6
  122. package/lib/helper/ApiDataFactory.js +2 -1
  123. package/lib/helper/Appium.js +7 -5
  124. package/lib/helper/Expect.js +422 -0
  125. package/lib/helper/FileSystem.js +1 -1
  126. package/lib/helper/Playwright.js +134 -64
  127. package/lib/helper/Puppeteer.js +6 -6
  128. package/lib/helper/WebDriver.js +4 -4
  129. package/lib/helper/scripts/highlightElement.js +1 -1
  130. package/lib/html.js +3 -3
  131. package/lib/interfaces/gherkin.js +21 -2
  132. package/lib/output.js +1 -1
  133. package/lib/pause.js +6 -5
  134. package/lib/plugin/autoLogin.js +35 -8
  135. package/lib/plugin/heal.js +40 -7
  136. package/lib/plugin/retryTo.js +0 -2
  137. package/lib/plugin/tryTo.js +0 -3
  138. package/lib/recorder.js +12 -5
  139. package/lib/session.js +1 -1
  140. package/package.json +24 -17
  141. package/translations/de-DE.js +5 -0
  142. package/translations/fr-FR.js +14 -1
  143. package/translations/it-IT.js +1 -0
  144. package/translations/ja-JP.js +5 -0
  145. package/translations/pl-PL.js +5 -0
  146. package/translations/pt-BR.js +1 -0
  147. package/translations/ru-RU.js +1 -0
  148. package/translations/zh-CN.js +5 -0
  149. package/translations/zh-TW.js +5 -0
  150. package/typings/promiseBasedTypes.d.ts +905 -863
  151. package/typings/types.d.ts +909 -850
@@ -47,7 +47,6 @@ const {
47
47
  setRestartStrategy, restartsSession, restartsContext, restartsBrowser,
48
48
  } = require('./extras/PlaywrightRestartOpts');
49
49
  const { createValueEngine, createDisabledEngine } = require('./extras/PlaywrightPropEngine');
50
- const { highlightElement } = require('./scripts/highlightElement');
51
50
 
52
51
  const pathSeparator = path.sep;
53
52
 
@@ -94,7 +93,7 @@ const pathSeparator = path.sep;
94
93
  * @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).
95
94
  * @prop {boolean} [ignoreHTTPSErrors] - Allows access to untrustworthy pages, e.g. to a page with an expired certificate. Default value is `false`
96
95
  * @prop {boolean} [bypassCSP] - bypass Content Security Policy or CSP
97
- * @prop {boolean} [highlightElement] - highlight the interacting elements. Default: false
96
+ * @prop {boolean} [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
98
97
  */
99
98
  const config = {};
100
99
 
@@ -695,7 +694,7 @@ class Playwright extends Helper {
695
694
  * I.seeInPopup('Popup text');
696
695
  * ```
697
696
  * @param {string} text value to check.
698
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
697
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
699
698
  *
700
699
  */
701
700
  async seeInPopup(text) {
@@ -835,8 +834,9 @@ class Playwright extends Helper {
835
834
 
836
835
  async _stopBrowser() {
837
836
  this.withinLocator = null;
838
- this._setPage(null);
837
+ await this._setPage(null);
839
838
  this.context = null;
839
+ this.frame = null;
840
840
  popupStore.clear();
841
841
  await this.browser.close();
842
842
  }
@@ -875,6 +875,7 @@ class Playwright extends Helper {
875
875
  this.withinLocator = null;
876
876
  this.context = await this.page;
877
877
  this.contextLocator = null;
878
+ this.frame = null;
878
879
  }
879
880
 
880
881
  _extractDataFromPerformanceTiming(timing, ...dataNames) {
@@ -899,7 +900,8 @@ class Playwright extends Helper {
899
900
  * ```
900
901
  *
901
902
  * @param {string} url url path or global url.
902
- * @return {void} automatically synchronized promise with recorder #!
903
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
904
+ *
903
905
  */
904
906
  async amOnPage(url) {
905
907
  if (this.isElectron) {
@@ -937,7 +939,7 @@ class Playwright extends Helper {
937
939
  *
938
940
  * @param {number} width width in pixels or `maximize`.
939
941
  * @param {number} height height in pixels.
940
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
942
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
941
943
  *
942
944
  *
943
945
  * Unlike other drivers Playwright changes the size of a viewport, not the window!
@@ -965,14 +967,14 @@ class Playwright extends Helper {
965
967
  * Set headers for all next requests
966
968
  *
967
969
  * ```js
968
- * I.haveRequestHeaders({
970
+ * I.setPlaywrightRequestHeaders({
969
971
  * 'X-Sent-By': 'CodeceptJS',
970
972
  * });
971
973
  * ```
972
974
  *
973
975
  * @param {object} customHeaders headers to set
974
976
  */
975
- async haveRequestHeaders(customHeaders) {
977
+ async setPlaywrightRequestHeaders(customHeaders) {
976
978
  if (!customHeaders) {
977
979
  throw new Error('Cannot send empty headers.');
978
980
  }
@@ -991,7 +993,7 @@ class Playwright extends Helper {
991
993
  * @param {CodeceptJS.LocatorOrString} locator located by CSS|XPath|strict locator.
992
994
  * @param {number} [offsetX=0] (optional, `0` by default) X-axis offset.
993
995
  * @param {number} [offsetY=0] (optional, `0` by default) Y-axis offset.
994
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
996
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
995
997
  *
996
998
  *
997
999
  */
@@ -1018,6 +1020,7 @@ class Playwright extends Helper {
1018
1020
  *
1019
1021
  * @param {CodeceptJS.LocatorOrString} locator field located by label|name|CSS|XPath|strict locator.
1020
1022
  * @param {any} [options] Playwright only: [Additional options](https://playwright.dev/docs/api/class-locator#locator-focus) for available options object as 2nd argument.
1023
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1021
1024
  *
1022
1025
  *
1023
1026
  */
@@ -1047,6 +1050,7 @@ class Playwright extends Helper {
1047
1050
  *
1048
1051
  * @param {CodeceptJS.LocatorOrString} locator field located by label|name|CSS|XPath|strict locator.
1049
1052
  * @param {any} [options] Playwright only: [Additional options](https://playwright.dev/docs/api/class-locator#locator-blur) for available options object as 2nd argument.
1053
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1050
1054
  *
1051
1055
  *
1052
1056
  */
@@ -1067,7 +1071,7 @@ class Playwright extends Helper {
1067
1071
  *
1068
1072
  * @param {LocatorOrString} srcElement located by CSS|XPath|strict locator.
1069
1073
  * @param {LocatorOrString} destElement located by CSS|XPath|strict locator.
1070
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1074
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1071
1075
  *
1072
1076
  * @param {any} [options] [Additional options](https://playwright.dev/docs/api/class-page#page-drag-and-drop) can be passed as 3rd argument.
1073
1077
  *
@@ -1125,7 +1129,7 @@ class Playwright extends Helper {
1125
1129
  * ```js
1126
1130
  * I.refreshPage();
1127
1131
  * ```
1128
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1132
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1129
1133
  *
1130
1134
  */
1131
1135
  async refreshPage() {
@@ -1138,7 +1142,7 @@ class Playwright extends Helper {
1138
1142
  * ```js
1139
1143
  * I.scrollPageToTop();
1140
1144
  * ```
1141
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1145
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1142
1146
  *
1143
1147
  */
1144
1148
  scrollPageToTop() {
@@ -1153,7 +1157,7 @@ class Playwright extends Helper {
1153
1157
  * ```js
1154
1158
  * I.scrollPageToBottom();
1155
1159
  * ```
1156
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1160
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1157
1161
  *
1158
1162
  */
1159
1163
  async scrollPageToBottom() {
@@ -1182,7 +1186,7 @@ class Playwright extends Helper {
1182
1186
  * @param {CodeceptJS.LocatorOrString} locator located by CSS|XPath|strict locator.
1183
1187
  * @param {number} [offsetX=0] (optional, `0` by default) X-axis offset.
1184
1188
  * @param {number} [offsetY=0] (optional, `0` by default) Y-axis offset.
1185
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1189
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1186
1190
  *
1187
1191
  */
1188
1192
  async scrollTo(locator, offsetX = 0, offsetY = 0) {
@@ -1212,7 +1216,7 @@ class Playwright extends Helper {
1212
1216
  * ```
1213
1217
  *
1214
1218
  * @param {string} text text value to check.
1215
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1219
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1216
1220
  *
1217
1221
  */
1218
1222
  async seeInTitle(text) {
@@ -1251,7 +1255,7 @@ class Playwright extends Helper {
1251
1255
  * ```
1252
1256
  *
1253
1257
  * @param {string} text value to check.
1254
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1258
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1255
1259
  *
1256
1260
  */
1257
1261
  async seeTitleEquals(text) {
@@ -1267,7 +1271,7 @@ class Playwright extends Helper {
1267
1271
  * ```
1268
1272
  *
1269
1273
  * @param {string} text value to check.
1270
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1274
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1271
1275
  *
1272
1276
  */
1273
1277
  async dontSeeInTitle(text) {
@@ -1299,6 +1303,9 @@ class Playwright extends Helper {
1299
1303
  */
1300
1304
  async _locate(locator) {
1301
1305
  const context = await this.context || await this._getContext();
1306
+
1307
+ if (this.frame) return findElements(this.frame, locator);
1308
+
1302
1309
  return findElements(context, locator);
1303
1310
  }
1304
1311
 
@@ -1489,7 +1496,7 @@ class Playwright extends Helper {
1489
1496
  * I.seeElement('#modal');
1490
1497
  * ```
1491
1498
  * @param {CodeceptJS.LocatorOrString} locator located by CSS|XPath|strict locator.
1492
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1499
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1493
1500
  *
1494
1501
  *
1495
1502
  */
@@ -1507,7 +1514,7 @@ class Playwright extends Helper {
1507
1514
  * ```
1508
1515
  *
1509
1516
  * @param {CodeceptJS.LocatorOrString} locator located by CSS|XPath|Strict locator.
1510
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1517
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1511
1518
  *
1512
1519
  *
1513
1520
  */
@@ -1525,7 +1532,7 @@ class Playwright extends Helper {
1525
1532
  * I.seeElementInDOM('#modal');
1526
1533
  * ```
1527
1534
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
1528
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1535
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1529
1536
  *
1530
1537
  */
1531
1538
  async seeElementInDOM(locator) {
@@ -1541,7 +1548,7 @@ class Playwright extends Helper {
1541
1548
  * ```
1542
1549
  *
1543
1550
  * @param {CodeceptJS.LocatorOrString} locator located by CSS|XPath|Strict locator.
1544
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1551
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1545
1552
  *
1546
1553
  */
1547
1554
  async dontSeeElementInDOM(locator) {
@@ -1607,7 +1614,7 @@ class Playwright extends Helper {
1607
1614
  *
1608
1615
  * @param {CodeceptJS.LocatorOrString} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
1609
1616
  * @param {?CodeceptJS.LocatorOrString | null} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
1610
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1617
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1611
1618
  *
1612
1619
  *
1613
1620
  * @param {any} [options] [Additional options](https://playwright.dev/docs/api/class-page#page-click) for click available as 3rd argument.
@@ -1664,7 +1671,7 @@ class Playwright extends Helper {
1664
1671
  *
1665
1672
  * @param {CodeceptJS.LocatorOrString} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
1666
1673
  * @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
1667
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1674
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1668
1675
  *
1669
1676
  */
1670
1677
  async forceClick(locator, context = null) {
@@ -1684,7 +1691,7 @@ class Playwright extends Helper {
1684
1691
  *
1685
1692
  * @param {CodeceptJS.LocatorOrString} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
1686
1693
  * @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
1687
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1694
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1688
1695
  *
1689
1696
  *
1690
1697
  *
@@ -1707,7 +1714,7 @@ class Playwright extends Helper {
1707
1714
  *
1708
1715
  * @param {CodeceptJS.LocatorOrString} locator clickable element located by CSS|XPath|strict locator.
1709
1716
  * @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS|XPath|strict locator.
1710
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1717
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1711
1718
  *
1712
1719
  *
1713
1720
  *
@@ -1729,7 +1736,7 @@ class Playwright extends Helper {
1729
1736
  * ```
1730
1737
  * @param {CodeceptJS.LocatorOrString} field checkbox located by label | name | CSS | XPath | strict locator.
1731
1738
  * @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
1732
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1739
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1733
1740
  *
1734
1741
  *
1735
1742
  * [Additional options](https://playwright.dev/docs/api/class-elementhandle#element-handle-check) for check available as 3rd argument.
@@ -1761,7 +1768,7 @@ class Playwright extends Helper {
1761
1768
  * ```
1762
1769
  * @param {CodeceptJS.LocatorOrString} field checkbox located by label | name | CSS | XPath | strict locator.
1763
1770
  * @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
1764
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1771
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1765
1772
  *
1766
1773
  *
1767
1774
  * [Additional options](https://playwright.dev/docs/api/class-elementhandle#element-handle-uncheck) for uncheck available as 3rd argument.
@@ -1790,7 +1797,7 @@ class Playwright extends Helper {
1790
1797
  * ```
1791
1798
  *
1792
1799
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1793
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1800
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1794
1801
  *
1795
1802
  */
1796
1803
  async seeCheckboxIsChecked(field) {
@@ -1807,7 +1814,7 @@ class Playwright extends Helper {
1807
1814
  * ```
1808
1815
  *
1809
1816
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1810
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1817
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1811
1818
  *
1812
1819
  */
1813
1820
  async dontSeeCheckboxIsChecked(field) {
@@ -1826,7 +1833,7 @@ class Playwright extends Helper {
1826
1833
  * ```
1827
1834
  *
1828
1835
  * @param {string} key name of key to press down.
1829
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1836
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1830
1837
  *
1831
1838
  */
1832
1839
  async pressKeyDown(key) {
@@ -1847,7 +1854,7 @@ class Playwright extends Helper {
1847
1854
  * ```
1848
1855
  *
1849
1856
  * @param {string} key name of key to release.
1850
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1857
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1851
1858
  *
1852
1859
  */
1853
1860
  async pressKeyUp(key) {
@@ -1916,7 +1923,7 @@ class Playwright extends Helper {
1916
1923
  * - `'Tab'`
1917
1924
  *
1918
1925
  * @param {string|string[]} key key or array of keys to press.
1919
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1926
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1920
1927
  *
1921
1928
  *
1922
1929
  * _Note:_ Shortcuts like `'Meta'` + `'A'` do not work on macOS ([GoogleChrome/Puppeteer#1313](https://github.com/GoogleChrome/puppeteer/issues/1313)).
@@ -1967,7 +1974,7 @@ class Playwright extends Helper {
1967
1974
  *
1968
1975
  * @param {string|string[]} key or array of keys to type.
1969
1976
  * @param {?number} [delay=null] (optional) delay in ms between key presses
1970
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
1977
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
1971
1978
  *
1972
1979
  */
1973
1980
  async type(keys, delay = null) {
@@ -1998,7 +2005,7 @@ class Playwright extends Helper {
1998
2005
  * ```
1999
2006
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
2000
2007
  * @param {CodeceptJS.StringOrSecret} value text value to fill.
2001
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2008
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2002
2009
  *
2003
2010
  *
2004
2011
  */
@@ -2009,7 +2016,7 @@ class Playwright extends Helper {
2009
2016
 
2010
2017
  await el.clear();
2011
2018
 
2012
- highlightActiveElement.call(this, el, await this._getContext());
2019
+ await highlightActiveElement.call(this, el);
2013
2020
 
2014
2021
  await el.type(value.toString(), { delay: this.options.pressKeyDelay });
2015
2022
 
@@ -2039,7 +2046,7 @@ class Playwright extends Helper {
2039
2046
 
2040
2047
  const el = els[0];
2041
2048
 
2042
- highlightActiveElement.call(this, el, this.page);
2049
+ await highlightActiveElement.call(this, el);
2043
2050
 
2044
2051
  await el.clear();
2045
2052
 
@@ -2057,7 +2064,7 @@ class Playwright extends Helper {
2057
2064
  * ```
2058
2065
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator
2059
2066
  * @param {string} value text value to append.
2060
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2067
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2061
2068
  *
2062
2069
  *
2063
2070
  *
@@ -2065,7 +2072,7 @@ class Playwright extends Helper {
2065
2072
  async appendField(field, value) {
2066
2073
  const els = await findFields.call(this, field);
2067
2074
  assertElementExists(els, field, 'Field');
2068
- highlightActiveElement.call(this, els[0], await this._getContext());
2075
+ await highlightActiveElement.call(this, els[0]);
2069
2076
  await els[0].press('End');
2070
2077
  await els[0].type(value.toString(), { delay: this.options.pressKeyDelay });
2071
2078
  return this._waitForAction();
@@ -2083,7 +2090,7 @@ class Playwright extends Helper {
2083
2090
  * ```
2084
2091
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
2085
2092
  * @param {CodeceptJS.StringOrSecret} value value to check.
2086
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2093
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2087
2094
  *
2088
2095
  */
2089
2096
  async seeInField(field, value) {
@@ -2102,7 +2109,7 @@ class Playwright extends Helper {
2102
2109
  *
2103
2110
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
2104
2111
  * @param {CodeceptJS.StringOrSecret} value value to check.
2105
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2112
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2106
2113
  *
2107
2114
  */
2108
2115
  async dontSeeInField(field, value) {
@@ -2122,7 +2129,7 @@ class Playwright extends Helper {
2122
2129
  *
2123
2130
  * @param {CodeceptJS.LocatorOrString} locator field located by label|name|CSS|XPath|strict locator.
2124
2131
  * @param {string} pathToFile local file path relative to codecept.conf.ts or codecept.conf.js config file.
2125
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2132
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2126
2133
  *
2127
2134
  *
2128
2135
  */
@@ -2159,7 +2166,7 @@ class Playwright extends Helper {
2159
2166
  * ```
2160
2167
  * @param {LocatorOrString} select field located by label|name|CSS|XPath|strict locator.
2161
2168
  * @param {string|Array<*>} option visible text or value of option.
2162
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2169
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2163
2170
  *
2164
2171
  */
2165
2172
  async selectOption(select, option) {
@@ -2167,7 +2174,7 @@ class Playwright extends Helper {
2167
2174
  assertElementExists(els, select, 'Selectable field');
2168
2175
  const el = els[0];
2169
2176
 
2170
- highlightActiveElement.call(this, el, await this._getContext());
2177
+ await highlightActiveElement.call(this, el);
2171
2178
 
2172
2179
  if (!Array.isArray(option)) option = [option];
2173
2180
 
@@ -2201,7 +2208,7 @@ class Playwright extends Helper {
2201
2208
  * ```
2202
2209
  *
2203
2210
  * @param {string} url a fragment to check
2204
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2211
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2205
2212
  *
2206
2213
  */
2207
2214
  async seeInCurrentUrl(url) {
@@ -2212,7 +2219,7 @@ class Playwright extends Helper {
2212
2219
  * Checks that current url does not contain a provided fragment.
2213
2220
  *
2214
2221
  * @param {string} url value to check.
2215
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2222
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2216
2223
  *
2217
2224
  */
2218
2225
  async dontSeeInCurrentUrl(url) {
@@ -2230,7 +2237,7 @@ class Playwright extends Helper {
2230
2237
  * ```
2231
2238
  *
2232
2239
  * @param {string} url value to check.
2233
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2240
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2234
2241
  *
2235
2242
  */
2236
2243
  async seeCurrentUrlEquals(url) {
@@ -2247,7 +2254,7 @@ class Playwright extends Helper {
2247
2254
  * ```
2248
2255
  *
2249
2256
  * @param {string} url value to check.
2250
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2257
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2251
2258
  *
2252
2259
  */
2253
2260
  async dontSeeCurrentUrlEquals(url) {
@@ -2265,7 +2272,7 @@ class Playwright extends Helper {
2265
2272
  * ```
2266
2273
  * @param {string} text expected on page.
2267
2274
  * @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text.
2268
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2275
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2269
2276
  *
2270
2277
  *
2271
2278
  *
@@ -2283,7 +2290,7 @@ class Playwright extends Helper {
2283
2290
  *
2284
2291
  * @param {string} text element value to check.
2285
2292
  * @param {CodeceptJS.LocatorOrString?} [context=null] element located by CSS|XPath|strict locator.
2286
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2293
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2287
2294
  *
2288
2295
  */
2289
2296
  async seeTextEquals(text, context = null) {
@@ -2301,7 +2308,7 @@ class Playwright extends Helper {
2301
2308
  *
2302
2309
  * @param {string} text which is not present.
2303
2310
  * @param {CodeceptJS.LocatorOrString} [context] (optional) element located by CSS|XPath|strict locator in which to perfrom search.
2304
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2311
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2305
2312
  *
2306
2313
  *
2307
2314
  *
@@ -2363,7 +2370,7 @@ class Playwright extends Helper {
2363
2370
  * I.seeInSource('<h1>Green eggs &amp; ham</h1>');
2364
2371
  * ```
2365
2372
  * @param {string} text value to check.
2366
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2373
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2367
2374
  *
2368
2375
  */
2369
2376
  async seeInSource(text) {
@@ -2379,7 +2386,7 @@ class Playwright extends Helper {
2379
2386
  * ```
2380
2387
  *
2381
2388
  * @param {string} value to check.
2382
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2389
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2383
2390
  *
2384
2391
  */
2385
2392
  async dontSeeInSource(text) {
@@ -2398,7 +2405,7 @@ class Playwright extends Helper {
2398
2405
  *
2399
2406
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
2400
2407
  * @param {number} num number of elements.
2401
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2408
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2402
2409
  *
2403
2410
  *
2404
2411
  *
@@ -2418,7 +2425,7 @@ class Playwright extends Helper {
2418
2425
  *
2419
2426
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
2420
2427
  * @param {number} num number of elements.
2421
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2428
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2422
2429
  *
2423
2430
  *
2424
2431
  *
@@ -2444,7 +2451,7 @@ class Playwright extends Helper {
2444
2451
  * ```
2445
2452
  *
2446
2453
  * @param {Cookie|Array<Cookie>} cookie a cookie object or array of cookie objects.
2447
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2454
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2448
2455
  *
2449
2456
  */
2450
2457
  async setCookie(cookie) {
@@ -2462,7 +2469,7 @@ class Playwright extends Helper {
2462
2469
  * ```
2463
2470
  *
2464
2471
  * @param {string} name cookie name.
2465
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2472
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2466
2473
  *
2467
2474
  *
2468
2475
  */
@@ -2479,7 +2486,7 @@ class Playwright extends Helper {
2479
2486
  * ```
2480
2487
  *
2481
2488
  * @param {string} name cookie name.
2482
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2489
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2483
2490
  *
2484
2491
  */
2485
2492
  async dontSeeCookie(name) {
@@ -2498,7 +2505,7 @@ class Playwright extends Helper {
2498
2505
  * ```
2499
2506
  *
2500
2507
  * @param {?string} [name=null] cookie name.
2501
- * @returns {Promise<string>|Promise<string[]>} attribute value
2508
+ * @returns {any} attribute value
2502
2509
  *
2503
2510
  *
2504
2511
  * Returns cookie in JSON format. If name not passed returns all cookies for this domain.
@@ -2520,7 +2527,7 @@ class Playwright extends Helper {
2520
2527
  * ```
2521
2528
  *
2522
2529
  * @param {?string} [cookie=null] (optional, `null` by default) cookie name
2523
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2530
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2524
2531
  *
2525
2532
  */
2526
2533
  async clearCookie() {
@@ -2555,11 +2562,11 @@ class Playwright extends Helper {
2555
2562
  * @returns {Promise<any>}
2556
2563
  */
2557
2564
  async executeScript(fn, arg) {
2558
- let context = this.page;
2559
- if (this.context && this.context.constructor.name === 'Frame') {
2560
- context = this.context; // switching to iframe context
2565
+ if (this.context && this.context.constructor.name === 'FrameLocator') {
2566
+ // switching to iframe context
2567
+ return this.context.locator(':root').evaluate(fn, arg);
2561
2568
  }
2562
- return context.evaluate.apply(context, [fn, arg]);
2569
+ return this.page.evaluate.apply(this.page, [fn, arg]);
2563
2570
  }
2564
2571
 
2565
2572
  /**
@@ -2750,7 +2757,7 @@ class Playwright extends Helper {
2750
2757
  *
2751
2758
  * @param {CodeceptJS.LocatorOrString} locator located by CSS|XPath|strict locator.
2752
2759
  * @param {object} cssProperties object with CSS properties and their values to check.
2753
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2760
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2754
2761
  *
2755
2762
  *
2756
2763
  */
@@ -2796,7 +2803,7 @@ class Playwright extends Helper {
2796
2803
  *
2797
2804
  * @param {CodeceptJS.LocatorOrString} locator located by CSS|XPath|strict locator.
2798
2805
  * @param {object} attributes attributes and their values to check.
2799
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2806
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2800
2807
  *
2801
2808
  *
2802
2809
  */
@@ -2836,7 +2843,7 @@ class Playwright extends Helper {
2836
2843
  *
2837
2844
  * @param {CodeceptJS.LocatorOrString} locator located by label|name|CSS|XPath|strict locator.
2838
2845
  * @param {number} offsetX position to drag.
2839
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2846
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2840
2847
  *
2841
2848
  *
2842
2849
  */
@@ -2914,7 +2921,7 @@ class Playwright extends Helper {
2914
2921
  *
2915
2922
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
2916
2923
  * @param {string} fileName file name to save.
2917
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2924
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2918
2925
  *
2919
2926
  *
2920
2927
  */
@@ -2940,7 +2947,7 @@ class Playwright extends Helper {
2940
2947
  *
2941
2948
  * @param {string} fileName file name to save.
2942
2949
  * @param {boolean} [fullPage=false] (optional, `false` by default) flag to enable fullscreen screenshot mode.
2943
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
2950
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
2944
2951
  *
2945
2952
  */
2946
2953
  async saveScreenshot(fileName, fullPage) {
@@ -3078,7 +3085,7 @@ class Playwright extends Helper {
3078
3085
  * ```
3079
3086
  *
3080
3087
  * @param {number} sec number of second to wait.
3081
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3088
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3082
3089
  *
3083
3090
  */
3084
3091
  async wait(sec) {
@@ -3093,7 +3100,7 @@ class Playwright extends Helper {
3093
3100
  *
3094
3101
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
3095
3102
  * @param {number} [sec=1] (optional) time in seconds to wait, 1 by default.
3096
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3103
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3097
3104
  *
3098
3105
  */
3099
3106
  async waitForEnabled(locator, sec) {
@@ -3129,7 +3136,7 @@ class Playwright extends Helper {
3129
3136
  * @param {LocatorOrString} field input field.
3130
3137
  * @param {string }value expected value.
3131
3138
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
3132
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3139
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3133
3140
  *
3134
3141
  */
3135
3142
  async waitForValue(field, value, sec) {
@@ -3166,7 +3173,7 @@ class Playwright extends Helper {
3166
3173
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
3167
3174
  * @param {number} num number of elements.
3168
3175
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
3169
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3176
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3170
3177
  *
3171
3178
  *
3172
3179
  */
@@ -3208,7 +3215,7 @@ class Playwright extends Helper {
3208
3215
  *
3209
3216
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
3210
3217
  * @param {number} [sec] (optional, `1` by default) time in seconds to wait
3211
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3218
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3212
3219
  *
3213
3220
  */
3214
3221
  async waitForClickable(locator, waitTimeout) {
@@ -3227,7 +3234,7 @@ class Playwright extends Helper {
3227
3234
  *
3228
3235
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
3229
3236
  * @param {number} [sec] (optional, `1` by default) time in seconds to wait
3230
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3237
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3231
3238
  *
3232
3239
  *
3233
3240
  */
@@ -3236,10 +3243,11 @@ class Playwright extends Helper {
3236
3243
  locator = new Locator(locator, 'css');
3237
3244
 
3238
3245
  const context = await this._getContext();
3239
- const waiter = context.waitForSelector(buildLocatorString(locator), { timeout: waitTimeout, state: 'attached' });
3240
- return waiter.catch((err) => {
3241
- throw new Error(`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${err.message}`);
3242
- });
3246
+ try {
3247
+ await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'attached' });
3248
+ } catch (e) {
3249
+ throw new Error(`element (${locator.toString()}) still not present on page after ${waitTimeout / 1000} sec\n${e.message}`);
3250
+ }
3243
3251
  }
3244
3252
 
3245
3253
  /**
@@ -3252,7 +3260,7 @@ class Playwright extends Helper {
3252
3260
  *
3253
3261
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
3254
3262
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
3255
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3263
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3256
3264
  *
3257
3265
  *
3258
3266
  * This method accepts [React selectors](https://codecept.io/react).
@@ -3261,10 +3269,26 @@ class Playwright extends Helper {
3261
3269
  const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
3262
3270
  locator = new Locator(locator, 'css');
3263
3271
  const context = await this._getContext();
3264
- const waiter = context.waitForSelector(buildLocatorString(locator), { timeout: waitTimeout, state: 'visible' });
3265
- return waiter.catch((err) => {
3266
- throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${err.message}`);
3267
- });
3272
+ let count = 0;
3273
+
3274
+ // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented
3275
+ let waiter;
3276
+ if (this.frame) {
3277
+ do {
3278
+ waiter = await this.frame.locator(buildLocatorString(locator)).first().isVisible();
3279
+ await this.wait(1);
3280
+ count += 1000;
3281
+ if (waiter) break;
3282
+ } while (count <= waitTimeout);
3283
+
3284
+ if (!waiter) throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec.`);
3285
+ }
3286
+
3287
+ try {
3288
+ await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'visible' });
3289
+ } catch (e) {
3290
+ throw new Error(`element (${locator.toString()}) still not visible after ${waitTimeout / 1000} sec\n${e.message}`);
3291
+ }
3268
3292
  }
3269
3293
 
3270
3294
  /**
@@ -3277,17 +3301,34 @@ class Playwright extends Helper {
3277
3301
  *
3278
3302
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
3279
3303
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
3280
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3304
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3281
3305
  *
3282
3306
  */
3283
3307
  async waitForInvisible(locator, sec) {
3284
3308
  const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
3285
3309
  locator = new Locator(locator, 'css');
3286
3310
  const context = await this._getContext();
3287
- const waiter = context.waitForSelector(buildLocatorString(locator), { timeout: waitTimeout, state: 'hidden' });
3288
- return waiter.catch((err) => {
3289
- throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec\n${err.message}`);
3290
- });
3311
+ let waiter;
3312
+ let count = 0;
3313
+
3314
+ // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented
3315
+ if (this.frame) {
3316
+ do {
3317
+ waiter = await this.frame.locator(buildLocatorString(locator)).first().isHidden();
3318
+ await this.wait(1);
3319
+ count += 1000;
3320
+ if (waiter) break;
3321
+ } while (count <= waitTimeout);
3322
+
3323
+ if (!waiter) throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec.`);
3324
+ return;
3325
+ }
3326
+
3327
+ try {
3328
+ await context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'hidden' });
3329
+ } catch (e) {
3330
+ throw new Error(`element (${locator.toString()}) still visible after ${waitTimeout / 1000} sec\n${e.message}`);
3331
+ }
3291
3332
  }
3292
3333
 
3293
3334
  /**
@@ -3300,20 +3341,36 @@ class Playwright extends Helper {
3300
3341
  *
3301
3342
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
3302
3343
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
3303
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3344
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3304
3345
  *
3305
3346
  */
3306
3347
  async waitToHide(locator, sec) {
3307
3348
  const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeout;
3308
3349
  locator = new Locator(locator, 'css');
3309
3350
  const context = await this._getContext();
3310
- return context.waitForSelector(buildLocatorString(locator), { timeout: waitTimeout, state: 'hidden' }).catch((err) => {
3351
+ let waiter;
3352
+ let count = 0;
3353
+
3354
+ // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented
3355
+ if (this.frame) {
3356
+ do {
3357
+ waiter = await this.frame.locator(buildLocatorString(locator)).first().isHidden();
3358
+ await this.wait(1);
3359
+ count += 1000;
3360
+ if (waiter) break;
3361
+ } while (count <= waitTimeout);
3362
+
3363
+ if (!waiter) throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec.`);
3364
+ return;
3365
+ }
3366
+
3367
+ return context.locator(buildLocatorString(locator)).first().waitFor({ timeout: waitTimeout, state: 'hidden' }).catch((err) => {
3311
3368
  throw new Error(`element (${locator.toString()}) still not hidden after ${waitTimeout / 1000} sec\n${err.message}`);
3312
3369
  });
3313
3370
  }
3314
3371
 
3315
3372
  async _getContext() {
3316
- if (this.context && this.context.constructor.name === 'Frame') {
3373
+ if (this.context && this.context.constructor.name === 'FrameLocator') {
3317
3374
  return this.context;
3318
3375
  }
3319
3376
  return this.page;
@@ -3328,7 +3385,7 @@ class Playwright extends Helper {
3328
3385
  *
3329
3386
  * @param {string} urlPart value to check.
3330
3387
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
3331
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3388
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3332
3389
  *
3333
3390
  */
3334
3391
  async waitInUrl(urlPart, sec = null) {
@@ -3357,7 +3414,7 @@ class Playwright extends Helper {
3357
3414
  *
3358
3415
  * @param {string} urlPart value to check.
3359
3416
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
3360
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3417
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3361
3418
  *
3362
3419
  */
3363
3420
  async waitUrlEquals(urlPart, sec = null) {
@@ -3394,7 +3451,7 @@ class Playwright extends Helper {
3394
3451
  * @param {string }text to wait for.
3395
3452
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
3396
3453
  * @param {CodeceptJS.LocatorOrString} [context] (optional) element located by CSS|XPath|strict locator.
3397
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3454
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3398
3455
  *
3399
3456
  */
3400
3457
  async waitForText(text, sec = null, context = null) {
@@ -3406,7 +3463,12 @@ class Playwright extends Helper {
3406
3463
  if (context) {
3407
3464
  const locator = new Locator(context, 'css');
3408
3465
  if (!locator.isXPath()) {
3409
- waiter = contextObject.waitForSelector(`${locator.isCustom() ? `${locator.type}=${locator.value}` : locator.simplify()} >> text=${text}`, { timeout: waitTimeout, state: 'visible' });
3466
+ try {
3467
+ await contextObject.locator(`${locator.isCustom() ? `${locator.type}=${locator.value}` : locator.simplify()} >> text=${text}`).first().waitFor({ timeout: waitTimeout, state: 'visible' });
3468
+ } catch (e) {
3469
+ console.log(e);
3470
+ throw new Error(`Text "${text}" was not found on page after ${waitTimeout / 1000} sec\n${e.message}`);
3471
+ }
3410
3472
  }
3411
3473
 
3412
3474
  if (locator.isXPath()) {
@@ -3418,11 +3480,18 @@ class Playwright extends Helper {
3418
3480
  }, [locator.value, text, $XPath.toString()], { timeout: waitTimeout });
3419
3481
  }
3420
3482
  } else {
3421
- waiter = contextObject.waitForFunction(text => document.body && document.body.innerText.indexOf(text) > -1, text, { timeout: waitTimeout });
3483
+ // we have this as https://github.com/microsoft/playwright/issues/26829 is not yet implemented
3484
+ // eslint-disable-next-line no-lonely-if
3485
+ const _contextObject = this.frame ? this.frame : contextObject;
3486
+ let count = 0;
3487
+ do {
3488
+ waiter = await _contextObject.locator(`:has-text('${text}')`).first().isVisible();
3489
+ await this.wait(1);
3490
+ count += 1000;
3491
+ } while (count <= waitTimeout);
3492
+
3493
+ if (!waiter) throw new Error(`Text "${text}" was not found on page after ${waitTimeout / 1000} sec`);
3422
3494
  }
3423
- return waiter.catch((err) => {
3424
- throw new Error(`Text "${text}" was not found on page after ${waitTimeout / 1000} sec\n${err.message}`);
3425
- });
3426
3495
  }
3427
3496
 
3428
3497
  /**
@@ -3466,7 +3535,7 @@ class Playwright extends Helper {
3466
3535
  * ```
3467
3536
  *
3468
3537
  * @param {?CodeceptJS.LocatorOrString} [locator=null] (optional, `null` by default) element located by CSS|XPath|strict locator.
3469
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3538
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3470
3539
  *
3471
3540
  */
3472
3541
  async switchTo(locator) {
@@ -3481,37 +3550,37 @@ class Playwright extends Helper {
3481
3550
  }
3482
3551
 
3483
3552
  if (locator >= 0 && locator < childFrames.length) {
3484
- this.context = childFrames[locator];
3553
+ this.context = await this.page.frameLocator('iframe').nth(locator);
3485
3554
  this.contextLocator = locator;
3486
3555
  } else {
3487
3556
  throw new Error('Element #invalidIframeSelector was not found by text|CSS|XPath');
3488
3557
  }
3489
3558
  return;
3490
3559
  }
3491
- let contentFrame;
3492
3560
 
3493
3561
  if (!locator) {
3494
- this.context = await this.page.frames()[0];
3562
+ this.context = this.page;
3495
3563
  this.contextLocator = null;
3564
+ this.frame = null;
3496
3565
  return;
3497
3566
  }
3498
3567
 
3499
3568
  // iframe by selector
3500
- const els = await this._locate(locator);
3501
- if (!els[0]) {
3502
- throw new Error(`Element ${JSON.stringify(locator)} was not found by text|CSS|XPath`);
3569
+ locator = buildLocatorString(new Locator(locator, 'css'));
3570
+ const frame = await this._locateElement(locator);
3571
+
3572
+ if (!frame) {
3573
+ throw new Error(`Frame ${JSON.stringify(locator)} was not found by text|CSS|XPath`);
3503
3574
  }
3504
3575
 
3505
- // get content of the first iframe
3506
- locator = new Locator(locator, 'css');
3507
- if ((locator.frame && locator.frame === 'iframe') || locator.value.toLowerCase() === 'iframe') {
3508
- contentFrame = await this.page.frames()[1];
3509
- // get content of the iframe using its name
3510
- } else if (locator.value.toLowerCase().includes('name=')) {
3511
- const frameName = locator.value.split('=')[1].replace(/"/g, '').replaceAll(/]/g, '');
3512
- contentFrame = await this.page.frame(frameName);
3576
+ if (this.frame) {
3577
+ this.frame = await this.frame.frameLocator(locator);
3578
+ } else {
3579
+ this.frame = await this.page.frameLocator(locator);
3513
3580
  }
3514
3581
 
3582
+ const contentFrame = this.frame;
3583
+
3515
3584
  if (contentFrame) {
3516
3585
  this.context = contentFrame;
3517
3586
  this.contextLocator = null;
@@ -3538,7 +3607,7 @@ class Playwright extends Helper {
3538
3607
  * @param {string|function} fn to be executed in browser context.
3539
3608
  * @param {any[]|number} [argsOrSec] (optional, `1` by default) arguments for function or seconds.
3540
3609
  * @param {number} [sec] (optional, `1` by default) time in seconds to wait
3541
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3610
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3542
3611
  *
3543
3612
  */
3544
3613
  async waitForFunction(fn, argsOrSec = null, sec = null) {
@@ -3607,7 +3676,7 @@ class Playwright extends Helper {
3607
3676
  *
3608
3677
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
3609
3678
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
3610
- * ⚠️ returns a _promise_ which is synchronized internally by recorder
3679
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3611
3680
  *
3612
3681
  */
3613
3682
  async waitForDetached(locator, sec) {
@@ -3617,17 +3686,21 @@ class Playwright extends Helper {
3617
3686
  let waiter;
3618
3687
  const context = await this._getContext();
3619
3688
  if (!locator.isXPath()) {
3620
- waiter = context.waitForSelector(`${locator.isCustom() ? `${locator.type}=${locator.value}` : locator.simplify()}`, { timeout: waitTimeout, state: 'detached' });
3689
+ try {
3690
+ await context.locator(`${locator.isCustom() ? `${locator.type}=${locator.value}` : locator.simplify()}`).first().waitFor({ timeout: waitTimeout, state: 'detached' });
3691
+ } catch (e) {
3692
+ throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${e.message}`);
3693
+ }
3621
3694
  } else {
3622
3695
  const visibleFn = function ([locator, $XPath]) {
3623
3696
  eval($XPath); // eslint-disable-line no-eval
3624
3697
  return $XPath(null, locator).length === 0;
3625
3698
  };
3626
3699
  waiter = context.waitForFunction(visibleFn, [locator.value, $XPath.toString()], { timeout: waitTimeout });
3700
+ return waiter.catch((err) => {
3701
+ throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${err.message}`);
3702
+ });
3627
3703
  }
3628
- return waiter.catch((err) => {
3629
- throw new Error(`element (${locator.toString()}) still on page after ${waitTimeout / 1000} sec\n${err.message}`);
3630
- });
3631
3704
  }
3632
3705
 
3633
3706
  async _waitForAction() {
@@ -3654,7 +3727,8 @@ class Playwright extends Helper {
3654
3727
  * loadEventEnd: 241
3655
3728
  * }
3656
3729
  * ```
3657
- * @return {Promise<any>} automatically synchronized promise through #recorder
3730
+ * @returns {Promise<void>} automatically synchronized promise through #recorder
3731
+ *
3658
3732
  */
3659
3733
  async grabDataFromPerformanceTiming() {
3660
3734
  return perfTiming;
@@ -4272,7 +4346,7 @@ async function findElement(matcher, locator) {
4272
4346
  if (locator.react) return findReact(matcher, locator);
4273
4347
  locator = new Locator(locator, 'css');
4274
4348
 
4275
- return matcher.locator(buildLocatorString(locator));
4349
+ return matcher.locator(buildLocatorString(locator)).first();
4276
4350
  }
4277
4351
 
4278
4352
  async function getVisibleElements(elements) {
@@ -4302,7 +4376,7 @@ async function proceedClick(locator, context = null, options = {}) {
4302
4376
  assertElementExists(els, locator, 'Clickable element');
4303
4377
  }
4304
4378
 
4305
- highlightActiveElement.call(this, els[0], await this._getContext());
4379
+ await highlightActiveElement.call(this, els[0]);
4306
4380
 
4307
4381
  /*
4308
4382
  using the force true options itself but instead dispatching a click
@@ -4352,13 +4426,10 @@ async function proceedSee(assertType, text, context, strict = false) {
4352
4426
  let allText;
4353
4427
 
4354
4428
  if (!context) {
4355
- let el = await this.context;
4356
- if (el && !el.getProperty) {
4357
- // Fallback to body
4358
- el = await this.page.$('body');
4359
- }
4429
+ const el = await this.context;
4430
+
4431
+ allText = el.constructor.name ? [await el.locator('body').innerText()] : [await el.innerText()];
4360
4432
 
4361
- allText = [await el.innerText()];
4362
4433
  description = 'web application';
4363
4434
  } else {
4364
4435
  const locator = new Locator(context, 'css');
@@ -4531,8 +4602,7 @@ async function elementSelected(element) {
4531
4602
  function isFrameLocator(locator) {
4532
4603
  locator = new Locator(locator);
4533
4604
  if (locator.isFrame()) {
4534
- const _locator = new Locator(locator.value);
4535
- return _locator.value;
4605
+ return locator.value;
4536
4606
  }
4537
4607
  return false;
4538
4608
  }
@@ -4728,10 +4798,14 @@ async function saveTraceForContext(context, name) {
4728
4798
  return fileName;
4729
4799
  }
4730
4800
 
4731
- function highlightActiveElement(element, context) {
4732
- if (!this.options.highlightElement && !store.debugMode) return;
4733
-
4734
- highlightElement(element, context);
4801
+ async function highlightActiveElement(element) {
4802
+ if (this.options.highlightElement && global.debugMode) {
4803
+ await element.evaluate(el => {
4804
+ const prevStyle = el.style.boxShadow;
4805
+ el.style.boxShadow = '0px 0px 4px 3px rgba(255, 0, 0, 0.7)';
4806
+ setTimeout(() => el.style.boxShadow = prevStyle, 2000);
4807
+ });
4808
+ }
4735
4809
  }
4736
4810
 
4737
4811
  const createAdvancedTestResults = (url, dataToCheck, requests) => {