codeceptjs 3.3.1 → 3.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +4 -25
  3. package/docs/api.md +4 -0
  4. package/docs/basics.md +2 -0
  5. package/docs/build/Appium.js +18 -28
  6. package/docs/build/JSONResponse.js +44 -3
  7. package/docs/build/Nightmare.js +53 -53
  8. package/docs/build/Playwright.js +95 -103
  9. package/docs/build/Protractor.js +66 -66
  10. package/docs/build/Puppeteer.js +74 -74
  11. package/docs/build/REST.js +8 -4
  12. package/docs/build/TestCafe.js +53 -53
  13. package/docs/build/WebDriver.js +84 -86
  14. package/docs/changelog.md +49 -0
  15. package/docs/helpers/Appium.md +212 -268
  16. package/docs/helpers/JSONResponse.md +24 -0
  17. package/docs/helpers/Nightmare.md +92 -141
  18. package/docs/helpers/Playwright.md +302 -413
  19. package/docs/helpers/Puppeteer.md +171 -231
  20. package/docs/helpers/REST.md +2 -0
  21. package/docs/helpers/TestCafe.md +125 -174
  22. package/docs/helpers/WebDriver.md +184 -247
  23. package/docs/plugins.md +41 -1
  24. package/docs/secrets.md +30 -0
  25. package/docs/webapi/amOnPage.mustache +1 -1
  26. package/docs/webapi/appendField.mustache +1 -1
  27. package/docs/webapi/attachFile.mustache +1 -1
  28. package/docs/webapi/checkOption.mustache +1 -1
  29. package/docs/webapi/clearCookie.mustache +1 -1
  30. package/docs/webapi/clearField.mustache +1 -1
  31. package/docs/webapi/click.mustache +1 -1
  32. package/docs/webapi/clickLink.mustache +1 -1
  33. package/docs/webapi/closeCurrentTab.mustache +1 -1
  34. package/docs/webapi/closeOtherTabs.mustache +1 -1
  35. package/docs/webapi/dontSee.mustache +1 -1
  36. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +1 -1
  37. package/docs/webapi/dontSeeCookie.mustache +1 -1
  38. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +1 -1
  39. package/docs/webapi/dontSeeElement.mustache +1 -1
  40. package/docs/webapi/dontSeeElementInDOM.mustache +1 -1
  41. package/docs/webapi/dontSeeInCurrentUrl.mustache +1 -1
  42. package/docs/webapi/dontSeeInField.mustache +1 -1
  43. package/docs/webapi/dontSeeInSource.mustache +1 -1
  44. package/docs/webapi/dontSeeInTitle.mustache +1 -1
  45. package/docs/webapi/doubleClick.mustache +1 -1
  46. package/docs/webapi/downloadFile.mustache +1 -1
  47. package/docs/webapi/dragAndDrop.mustache +1 -1
  48. package/docs/webapi/dragSlider.mustache +1 -1
  49. package/docs/webapi/executeAsyncScript.mustache +1 -1
  50. package/docs/webapi/executeScript.mustache +1 -1
  51. package/docs/webapi/fillField.mustache +1 -1
  52. package/docs/webapi/forceClick.mustache +1 -1
  53. package/docs/webapi/forceRightClick.mustache +1 -1
  54. package/docs/webapi/grabDataFromPerformanceTiming.mustache +1 -1
  55. package/docs/webapi/moveCursorTo.mustache +1 -1
  56. package/docs/webapi/openNewTab.mustache +1 -1
  57. package/docs/webapi/pressKey.mustache +1 -1
  58. package/docs/webapi/pressKeyDown.mustache +1 -1
  59. package/docs/webapi/pressKeyUp.mustache +1 -1
  60. package/docs/webapi/pressKeyWithKeyNormalization.mustache +1 -1
  61. package/docs/webapi/refreshPage.mustache +1 -1
  62. package/docs/webapi/resizeWindow.mustache +1 -1
  63. package/docs/webapi/rightClick.mustache +1 -1
  64. package/docs/webapi/saveElementScreenshot.mustache +1 -1
  65. package/docs/webapi/saveScreenshot.mustache +1 -1
  66. package/docs/webapi/say.mustache +1 -1
  67. package/docs/webapi/scrollIntoView.mustache +1 -1
  68. package/docs/webapi/scrollPageToBottom.mustache +1 -1
  69. package/docs/webapi/scrollPageToTop.mustache +1 -1
  70. package/docs/webapi/scrollTo.mustache +1 -1
  71. package/docs/webapi/see.mustache +1 -1
  72. package/docs/webapi/seeAttributesOnElements.mustache +1 -1
  73. package/docs/webapi/seeCheckboxIsChecked.mustache +1 -1
  74. package/docs/webapi/seeCookie.mustache +1 -1
  75. package/docs/webapi/seeCssPropertiesOnElements.mustache +1 -1
  76. package/docs/webapi/seeCurrentUrlEquals.mustache +1 -1
  77. package/docs/webapi/seeElement.mustache +1 -1
  78. package/docs/webapi/seeElementInDOM.mustache +1 -1
  79. package/docs/webapi/seeInCurrentUrl.mustache +1 -1
  80. package/docs/webapi/seeInField.mustache +1 -1
  81. package/docs/webapi/seeInPopup.mustache +1 -1
  82. package/docs/webapi/seeInSource.mustache +1 -1
  83. package/docs/webapi/seeInTitle.mustache +1 -1
  84. package/docs/webapi/seeNumberOfElements.mustache +1 -1
  85. package/docs/webapi/seeNumberOfVisibleElements.mustache +1 -1
  86. package/docs/webapi/seeTextEquals.mustache +1 -1
  87. package/docs/webapi/seeTitleEquals.mustache +1 -1
  88. package/docs/webapi/selectOption.mustache +1 -1
  89. package/docs/webapi/setCookie.mustache +1 -1
  90. package/docs/webapi/setGeoLocation.mustache +1 -1
  91. package/docs/webapi/switchTo.mustache +1 -1
  92. package/docs/webapi/switchToNextTab.mustache +1 -1
  93. package/docs/webapi/switchToPreviousTab.mustache +1 -1
  94. package/docs/webapi/type.mustache +1 -1
  95. package/docs/webapi/uncheckOption.mustache +1 -1
  96. package/docs/webapi/wait.mustache +1 -1
  97. package/docs/webapi/waitForClickable.mustache +1 -1
  98. package/docs/webapi/waitForDetached.mustache +1 -1
  99. package/docs/webapi/waitForElement.mustache +1 -1
  100. package/docs/webapi/waitForEnabled.mustache +1 -1
  101. package/docs/webapi/waitForFunction.mustache +1 -1
  102. package/docs/webapi/waitForInvisible.mustache +1 -1
  103. package/docs/webapi/waitForText.mustache +1 -1
  104. package/docs/webapi/waitForValue.mustache +1 -1
  105. package/docs/webapi/waitForVisible.mustache +1 -1
  106. package/docs/webapi/waitInUrl.mustache +1 -1
  107. package/docs/webapi/waitNumberOfVisibleElements.mustache +1 -1
  108. package/docs/webapi/waitToHide.mustache +1 -1
  109. package/docs/webapi/waitUrlEquals.mustache +1 -1
  110. package/lib/cli.js +1 -1
  111. package/lib/command/interactive.js +1 -1
  112. package/lib/command/run-workers.js +1 -1
  113. package/lib/command/workers/runTests.js +15 -0
  114. package/lib/helper/Appium.js +0 -10
  115. package/lib/helper/JSONResponse.js +44 -3
  116. package/lib/helper/Playwright.js +24 -32
  117. package/lib/helper/REST.js +8 -4
  118. package/lib/helper/WebDriver.js +5 -7
  119. package/lib/output.js +4 -0
  120. package/lib/plugin/customLocator.js +50 -3
  121. package/lib/plugin/retryFailedStep.js +1 -1
  122. package/lib/plugin/retryTo.js +1 -8
  123. package/lib/secret.js +30 -0
  124. package/lib/step.js +1 -1
  125. package/package.json +4 -4
  126. package/typings/types.d.ts +1016 -520
package/CHANGELOG.md CHANGED
@@ -1,3 +1,52 @@
1
+ ## 3.3.4
2
+
3
+ * Added support for masking fields in objects via `secret` function:
4
+
5
+ ```js
6
+ I.sendPostRequest('/auth', secret({ name: 'jon', password: '123456' }, 'password'));
7
+ ```
8
+ * Added [a guide about using of `secret`](/secrets) function
9
+ * [Appium] Use `touchClick` when interacting with elements in iOS. See #3317 by @mikk150
10
+ * [Playwright] Added `cdpConnection` option to connect over CDP. See #3309 by @Hmihaly
11
+ * [customLocator plugin] Allowed to specify multiple attributes for custom locator. Thanks to @aruiz-caritsqa
12
+
13
+ ```js
14
+ plugins: {
15
+ customLocator: {
16
+ enabled: true,
17
+ prefix: '$',
18
+ attribute: ['data-qa', 'data-test'],
19
+ }
20
+ }
21
+ ```
22
+ * [retryTo plugin] Fixed #3147 using `pollInterval` option. See #3351 by @cyonkee
23
+ * [Playwright] Fixed grabbing of browser console messages and window resize in new tab. Thanks to @mirao
24
+ * [REST] Added `prettyPrintJson` option to print JSON in nice way by @PeterNgTr
25
+ * [JSONResponse] Updated response validation to iterate over array items if response is array. Thanks to @PeterNgTr
26
+
27
+ ```js
28
+ // response.data == [
29
+ // { user: { name: 'jon', email: 'jon@doe.com' } },
30
+ // { user: { name: 'matt', email: 'matt@doe.com' } },
31
+ //]
32
+
33
+ I.seeResponseContainsKeys(['user']);
34
+ I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } });
35
+ I.seeResponseContainsJson({ user: { email: 'matt@doe.com' } });
36
+ I.dontSeeResponseContainsJson({ user: 2 });
37
+ ```
38
+
39
+ ## 3.3.3
40
+
41
+ * Fixed `DataCloneError: () => could not be cloned` when running data tests in run-workers
42
+ * 🇺🇦 Added #StandWithUkraine notice to CLI
43
+
44
+
45
+ ## 3.3.2
46
+
47
+ * [REST] Fixed override of headers/token in `haveRequestHeaders()` and `amBearerAuthenticated()`. See #3304 by @mirao
48
+ * Reverted typings change introduced in #3245. [More details on this](https://twitter.com/CodeceptJS/status/1519725963856207873)
49
+
1
50
  ## 3.3.1
2
51
 
3
52
  🛩️ Features:
package/README.md CHANGED
@@ -1,30 +1,9 @@
1
- > # 🇺🇦 UKRAINE NEEDS YOUR HELP NOW!
2
- >
3
- > I'm the creator of this project and I'm Ukrainian.
4
- >
5
- > **My country, Ukraine, [is being invaded by the Russian Federation, right now](https://www.bbc.com/news/world-europe-60504334)**. I've fled Kyiv and now I'm safe with my family in the western part of Ukraine. At least for now.
6
- > Russia is hitting target all over my country by ballistic missiles.
7
- >
8
- > **Please, save me and help to save my country!**
9
- >
10
- > Ukrainian National Bank opened [an account to Raise Funds for Ukraine’s Armed Forces](https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi):
11
- >
12
- > ```
13
- > SWIFT Code NBU: NBUA UA UX
14
- > JP MORGAN CHASE BANK, New York
15
- > SWIFT Code: CHASUS33
16
- > Account: 400807238
17
- > 383 Madison Avenue, New York, NY 10179, USA
18
- > IBAN: UA843000010000000047330992708
19
- > ```
20
- >
21
- > You can also donate to [charity supporting Ukrainian army](https://savelife.in.ua/en/donate/).
22
- >
23
- > **THANK YOU!**
1
+ [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-direct-single.svg)](https://stand-with-ukraine.pp.ua)
2
+
24
3
 
25
4
 
26
5
  [<img src="https://img.shields.io/badge/slack-@codeceptjs-purple.svg?logo=slack">](https://join.slack.com/t/codeceptjs/shared_invite/enQtMzA5OTM4NDM2MzA4LWE4MThhN2NmYTgxNTU5MTc4YzAyYWMwY2JkMmZlYWI5MWQ2MDM5MmRmYzZmYmNiNmY5NTAzM2EwMGIwOTNhOGQ) [<img src="https://img.shields.io/badge/discourse-codeceptjs-purple">](https://codecept.discourse.group) [![NPM version][npm-image]][npm-url]
27
- [![StandWithUkraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md) [![RussianWarship](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/RussianWarship.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md)
6
+ [![StandWithUkraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md)
28
7
 
29
8
  Build Status:
30
9
 
@@ -34,7 +13,7 @@ Build Status:
34
13
  [![Appium Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/appium.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/appium.yml)
35
14
  [![TestCafe Tests](https://github.com/codeceptjs/CodeceptJS/actions/workflows/testcafe.yml/badge.svg)](https://github.com/codeceptjs/CodeceptJS/actions/workflows/testcafe.yml)
36
15
 
37
- # CodeceptJS
16
+ # CodeceptJS [![Made in Ukraine](https://img.shields.io/badge/made_in-ukraine-ffd700.svg?labelColor=0057b7)](https://stand-with-ukraine.pp.ua)
38
17
 
39
18
  Reference: [Helpers API](https://github.com/codeceptjs/CodeceptJS/tree/master/docs/helpers)
40
19
 
package/docs/api.md CHANGED
@@ -263,6 +263,8 @@ The most basic thing to check in response is existence of keys in JSON object. U
263
263
  I.seeResponseContainsKeys(['name', 'email']);
264
264
  ```
265
265
 
266
+ > ℹ️ If response is an array, it will check that every element in array have provided keys
267
+
266
268
  However, this is a very naive approach. It won't work for arrays or nested objects.
267
269
  To check complex JSON structures `JSONResponse` helper uses [`joi`](https://joi.dev) library.
268
270
  It has rich API to validate JSON by the schema defined using JavaScript.
@@ -296,6 +298,8 @@ I.seeResponseContainsJson({
296
298
  })
297
299
  ```
298
300
 
301
+ > ℹ️ If response is an array, it will check that at least one element in array matches JSON
302
+
299
303
  To perform arbitrary assertions on a response object use `seeResponseValidByCallback`.
300
304
  It allows you to do any kind of assertions by using `expect` from [`chai`](https://www.chaijs.com) library.
301
305
 
package/docs/basics.md CHANGED
@@ -212,6 +212,8 @@ To fill in sensitive data use the `secret` function, it won't expose actual valu
212
212
  I.fillField('password', secret('123456'));
213
213
  ```
214
214
 
215
+ > ℹ️ Learn more about [masking secret](/secrets/) output
216
+
215
217
  ### Assertions
216
218
 
217
219
  In order to verify the expected behavior of a web application, its content should be checked.
@@ -332,7 +332,6 @@ class Appium extends Webdriver {
332
332
  *
333
333
  * @param {*} caps
334
334
  * @param {*} fn
335
- * @return {Promise<any>}
336
335
  */
337
336
  async runOnIOS(caps, fn) {
338
337
  if (this.platform !== 'ios') return;
@@ -375,7 +374,6 @@ class Appium extends Webdriver {
375
374
  *
376
375
  * @param {*} caps
377
376
  * @param {*} fn
378
- * @return {Promise<any>}
379
377
  */
380
378
  async runOnAndroid(caps, fn) {
381
379
  if (this.platform !== 'android') return;
@@ -396,7 +394,6 @@ class Appium extends Webdriver {
396
394
  * ```
397
395
  *
398
396
  * @param {*} fn
399
- * @return {Promise<any>}
400
397
  */
401
398
  /* eslint-disable */
402
399
  async runInWeb(fn) {
@@ -493,7 +490,6 @@ class Appium extends Webdriver {
493
490
  *
494
491
  * @param {string} appId
495
492
  * @param {string} [bundleId] ID of bundle
496
- * @return {Promise<any>}
497
493
  */
498
494
  async removeApp(appId, bundleId) {
499
495
  onlyForApps.call(this, 'Android');
@@ -601,7 +597,6 @@ class Appium extends Webdriver {
601
597
  * ```
602
598
  *
603
599
  * @param {'LANDSCAPE'|'PORTRAIT'} orientation LANDSCAPE or PORTRAIT
604
- * @return {Promise<any>}
605
600
  *
606
601
  * Appium: support Android and iOS
607
602
  */
@@ -730,7 +725,6 @@ class Appium extends Webdriver {
730
725
  * Switch to the specified context.
731
726
  *
732
727
  * @param {*} context the context to switch to
733
- * @return {Promise<any>}
734
728
  */
735
729
  async _switchToContext(context) {
736
730
  return this.browser.switchContext(context);
@@ -836,7 +830,6 @@ class Appium extends Webdriver {
836
830
  * ```
837
831
  *
838
832
  * @param {object} settings object
839
- * @return {Promise<any>}
840
833
  *
841
834
  * Appium: support Android and iOS
842
835
  */
@@ -861,7 +854,6 @@ class Appium extends Webdriver {
861
854
  *
862
855
  * @param {'tapOutside' | 'pressKey'} [strategy] Desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’)
863
856
  * @param {string} [key] Optional key
864
- * @return {Promise<any>}
865
857
  */
866
858
  async hideDeviceKeyboard(strategy, key) {
867
859
  onlyForApps.call(this);
@@ -984,7 +976,6 @@ class Appium extends Webdriver {
984
976
  *
985
977
  * @param {object} from
986
978
  * @param {object} to
987
- * @return {Promise<any>}
988
979
  *
989
980
  * Appium: support Android and iOS
990
981
  */
@@ -1217,7 +1208,6 @@ class Appium extends Webdriver {
1217
1208
  * Appium: support Android and iOS
1218
1209
  *
1219
1210
  * @param {Array} actions Array of touch actions
1220
- * @return {Promise<any>}
1221
1211
  */
1222
1212
  async touchPerform(actions) {
1223
1213
  onlyForApps.call(this);
@@ -1342,7 +1332,7 @@ class Appium extends Webdriver {
1342
1332
  * ```
1343
1333
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator
1344
1334
  * @param {string} value text value to append.
1345
- * @return {Promise<any>}
1335
+ * [!] returns a _promise_ which is synchronized internally by recorder
1346
1336
  *
1347
1337
  */
1348
1338
  async appendField(field, value) {
@@ -1363,7 +1353,7 @@ class Appium extends Webdriver {
1363
1353
  * ```
1364
1354
  * @param {CodeceptJS.LocatorOrString} field checkbox located by label | name | CSS | XPath | strict locator.
1365
1355
  * @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS | XPath | strict locator.
1366
- * @return {Promise<any>}
1356
+ * [!] returns a _promise_ which is synchronized internally by recorder
1367
1357
  *
1368
1358
  */
1369
1359
  async checkOption(field) {
@@ -1396,7 +1386,7 @@ class Appium extends Webdriver {
1396
1386
  *
1397
1387
  * @param {CodeceptJS.LocatorOrString} locator clickable link or button located by text, or any element located by CSS|XPath|strict locator.
1398
1388
  * @param {?CodeceptJS.LocatorOrString | null} [context=null] (optional, `null` by default) element to search in CSS|XPath|Strict locator.
1399
- * @return {Promise<any>}
1389
+ * [!] returns a _promise_ which is synchronized internally by recorder
1400
1390
  *
1401
1391
  *
1402
1392
  */
@@ -1415,7 +1405,7 @@ class Appium extends Webdriver {
1415
1405
  * ```
1416
1406
  *
1417
1407
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1418
- * @return {Promise<any>}
1408
+ * [!] returns a _promise_ which is synchronized internally by recorder
1419
1409
  *
1420
1410
  */
1421
1411
  async dontSeeCheckboxIsChecked(field) {
@@ -1431,7 +1421,7 @@ class Appium extends Webdriver {
1431
1421
  * ```
1432
1422
  *
1433
1423
  * @param {CodeceptJS.LocatorOrString} locator located by CSS|XPath|Strict locator.
1434
- * @return {Promise<any>}
1424
+ * [!] returns a _promise_ which is synchronized internally by recorder
1435
1425
  */
1436
1426
  async dontSeeElement(locator) {
1437
1427
  if (this.isWeb) return super.dontSeeElement(locator);
@@ -1449,7 +1439,7 @@ class Appium extends Webdriver {
1449
1439
  *
1450
1440
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1451
1441
  * @param {string} value value to check.
1452
- * @return {Promise<any>}
1442
+ * [!] returns a _promise_ which is synchronized internally by recorder
1453
1443
  *
1454
1444
  */
1455
1445
  async dontSeeInField(field, value) {
@@ -1468,7 +1458,7 @@ class Appium extends Webdriver {
1468
1458
  *
1469
1459
  * @param {string} text which is not present.
1470
1460
  * @param {CodeceptJS.LocatorOrString} [context] (optional) element located by CSS|XPath|strict locator in which to perfrom search.
1471
- * @return {Promise<any>}
1461
+ * [!] returns a _promise_ which is synchronized internally by recorder
1472
1462
  */
1473
1463
  async dontSee(text, context = null) {
1474
1464
  if (this.isWeb) return super.dontSee(text, context);
@@ -1491,7 +1481,7 @@ class Appium extends Webdriver {
1491
1481
  * ```
1492
1482
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1493
1483
  * @param {CodeceptJS.StringOrSecret} value text value to fill.
1494
- * @return {Promise<any>}
1484
+ * [!] returns a _promise_ which is synchronized internally by recorder
1495
1485
  *
1496
1486
  */
1497
1487
  async fillField(field, value) {
@@ -1652,7 +1642,7 @@ class Appium extends Webdriver {
1652
1642
  *
1653
1643
  * @param {LocatorOrString} locator located by CSS|XPath|strict locator.
1654
1644
  * @param {ScrollIntoViewOptions} scrollIntoViewOptions see https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView.
1655
- * @return {Promise<any>}
1645
+ * [!] returns a _promise_ which is synchronized internally by recorder
1656
1646
  *
1657
1647
  * Supported only for web testing
1658
1648
  */
@@ -1670,7 +1660,7 @@ class Appium extends Webdriver {
1670
1660
  * ```
1671
1661
  *
1672
1662
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1673
- * @return {Promise<any>}
1663
+ * [!] returns a _promise_ which is synchronized internally by recorder
1674
1664
  *
1675
1665
  */
1676
1666
  async seeCheckboxIsChecked(field) {
@@ -1686,7 +1676,7 @@ class Appium extends Webdriver {
1686
1676
  * I.seeElement('#modal');
1687
1677
  * ```
1688
1678
  * @param {CodeceptJS.LocatorOrString} locator located by CSS|XPath|strict locator.
1689
- * @return {Promise<any>}
1679
+ * [!] returns a _promise_ which is synchronized internally by recorder
1690
1680
  *
1691
1681
  */
1692
1682
  async seeElement(locator) {
@@ -1706,7 +1696,7 @@ class Appium extends Webdriver {
1706
1696
  * ```
1707
1697
  * @param {CodeceptJS.LocatorOrString} field located by label|name|CSS|XPath|strict locator.
1708
1698
  * @param {string} value value to check.
1709
- * @return {Promise<any>}
1699
+ * [!] returns a _promise_ which is synchronized internally by recorder
1710
1700
  *
1711
1701
  */
1712
1702
  async seeInField(field, value) {
@@ -1725,7 +1715,7 @@ class Appium extends Webdriver {
1725
1715
  * ```
1726
1716
  * @param {string} text expected on page.
1727
1717
  * @param {?CodeceptJS.LocatorOrString} [context=null] (optional, `null` by default) element located by CSS|Xpath|strict locator in which to search for text.
1728
- * @return {Promise<any>}
1718
+ * [!] returns a _promise_ which is synchronized internally by recorder
1729
1719
  *
1730
1720
  */
1731
1721
  async see(text, context) {
@@ -1754,7 +1744,7 @@ class Appium extends Webdriver {
1754
1744
  * ```
1755
1745
  * @param {LocatorOrString} select field located by label|name|CSS|XPath|strict locator.
1756
1746
  * @param {string|Array<*>} option visible text or value of option.
1757
- * @return {Promise<any>}
1747
+ * [!] returns a _promise_ which is synchronized internally by recorder
1758
1748
  *
1759
1749
  * Supported only for web testing
1760
1750
  */
@@ -1774,7 +1764,7 @@ class Appium extends Webdriver {
1774
1764
  *
1775
1765
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
1776
1766
  * @param {number} [sec] (optional, `1` by default) time in seconds to wait
1777
- * @return {Promise<any>}
1767
+ * [!] returns a _promise_ which is synchronized internally by recorder
1778
1768
  *
1779
1769
  */
1780
1770
  async waitForElement(locator, sec = null) {
@@ -1792,7 +1782,7 @@ class Appium extends Webdriver {
1792
1782
  *
1793
1783
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
1794
1784
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
1795
- * @return {Promise<any>}
1785
+ * [!] returns a _promise_ which is synchronized internally by recorder
1796
1786
  *
1797
1787
  */
1798
1788
  async waitForVisible(locator, sec = null) {
@@ -1810,7 +1800,7 @@ class Appium extends Webdriver {
1810
1800
  *
1811
1801
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
1812
1802
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
1813
- * @return {Promise<any>}
1803
+ * [!] returns a _promise_ which is synchronized internally by recorder
1814
1804
  *
1815
1805
  */
1816
1806
  async waitForInvisible(locator, sec = null) {
@@ -1831,7 +1821,7 @@ class Appium extends Webdriver {
1831
1821
  * @param {string }text to wait for.
1832
1822
  * @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
1833
1823
  * @param {CodeceptJS.LocatorOrString} [context] (optional) element located by CSS|XPath|strict locator.
1834
- * @return {Promise<any>}
1824
+ * [!] returns a _promise_ which is synchronized internally by recorder
1835
1825
  *
1836
1826
  */
1837
1827
  async waitForText(text, sec = null, context = null) {
@@ -1,3 +1,4 @@
1
+ const assert = require('assert');
1
2
  const chai = require('chai');
2
3
  const joi = require('joi');
3
4
  const chaiDeepMatch = require('chai-deep-match');
@@ -173,12 +174,30 @@ class JSONResponse extends Helper {
173
174
  *
174
175
  * I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } });
175
176
  * ```
177
+ * If an array is received, checks that at least one element contains JSON
178
+ * ```js
179
+ * // response.data == [{ user: { name: 'jon', email: 'jon@doe.com' } }]
180
+ *
181
+ * I.seeResponseContainsJson({ user: { email: 'jon@doe.com' } });
182
+ * ```
176
183
  *
177
184
  * @param {object} json
178
185
  */
179
186
  seeResponseContainsJson(json = {}) {
180
187
  this._checkResponseReady();
181
- expect(this.response.data).to.deep.match(json);
188
+ if (Array.isArray(this.response.data)) {
189
+ let fails = 0;
190
+ for (const el of this.response.data) {
191
+ try {
192
+ expect(el).to.deep.match(json);
193
+ } catch (err) {
194
+ fails++;
195
+ }
196
+ }
197
+ assert.ok(fails < this.response.data.length, `No elements in array matched ${JSON.stringify(json)}`);
198
+ } else {
199
+ expect(this.response.data).to.deep.match(json);
200
+ }
182
201
  }
183
202
 
184
203
  /**
@@ -189,12 +208,22 @@ class JSONResponse extends Helper {
189
208
  *
190
209
  * I.dontSeeResponseContainsJson({ user: 2 });
191
210
  * ```
211
+ * If an array is received, checks that no element of array contains json:
212
+ * ```js
213
+ * // response.data == [{ user: 1 }, { user: 3 }]
214
+ *
215
+ * I.dontSeeResponseContainsJson({ user: 2 });
216
+ * ```
192
217
  *
193
218
  * @param {object} json
194
219
  */
195
220
  dontSeeResponseContainsJson(json = {}) {
196
221
  this._checkResponseReady();
197
- expect(this.response.data).not.to.deep.match(json);
222
+ if (Array.isArray(this.response.data)) {
223
+ this.response.data.forEach(data => expect(data).not.to.deep.match(json));
224
+ } else {
225
+ expect(this.response.data).not.to.deep.match(json);
226
+ }
198
227
  }
199
228
 
200
229
  /**
@@ -206,11 +235,23 @@ class JSONResponse extends Helper {
206
235
  * I.seeResponseContainsKeys(['user']);
207
236
  * ```
208
237
  *
238
+ * If an array is received, check is performed for each element of array:
239
+ *
240
+ * ```js
241
+ * // response.data == [{ user: 'jon' }, { user: 'matt'}]
242
+ *
243
+ * I.seeResponseContainsKeys(['user']);
244
+ * ```
245
+ *
209
246
  * @param {array} keys
210
247
  */
211
248
  seeResponseContainsKeys(keys = []) {
212
249
  this._checkResponseReady();
213
- expect(this.response.data).to.include.keys(keys);
250
+ if (Array.isArray(this.response.data)) {
251
+ this.response.data.forEach(data => expect(data).to.include.keys(keys));
252
+ } else {
253
+ expect(this.response.data).to.include.keys(keys);
254
+ }
214
255
  }
215
256
 
216
257
  /**