codeceptjs 3.1.2 → 3.2.2

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 (67) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +2 -3
  3. package/bin/codecept.js +1 -0
  4. package/docs/advanced.md +94 -60
  5. package/docs/basics.md +27 -2
  6. package/docs/bdd.md +57 -3
  7. package/docs/build/Appium.js +8 -4
  8. package/docs/build/FileSystem.js +1 -0
  9. package/docs/build/Playwright.js +39 -30
  10. package/docs/build/Protractor.js +9 -24
  11. package/docs/build/Puppeteer.js +10 -28
  12. package/docs/build/REST.js +1 -0
  13. package/docs/build/WebDriver.js +3 -25
  14. package/docs/changelog.md +103 -0
  15. package/docs/commands.md +21 -7
  16. package/docs/custom-helpers.md +1 -36
  17. package/docs/helpers/Appium.md +34 -30
  18. package/docs/helpers/FileSystem.md +1 -1
  19. package/docs/helpers/Playwright.md +16 -18
  20. package/docs/helpers/Puppeteer.md +1 -17
  21. package/docs/helpers/REST.md +3 -1
  22. package/docs/helpers/WebDriver.md +1 -17
  23. package/docs/mobile-react-native-locators.md +3 -0
  24. package/docs/pageobjects.md +2 -0
  25. package/docs/playwright.md +16 -33
  26. package/docs/plugins.md +128 -3
  27. package/docs/reports.md +23 -5
  28. package/lib/actor.js +20 -2
  29. package/lib/codecept.js +2 -0
  30. package/lib/command/info.js +1 -1
  31. package/lib/config.js +13 -1
  32. package/lib/container.js +3 -1
  33. package/lib/data/dataTableArgument.js +35 -0
  34. package/lib/helper/Appium.js +8 -4
  35. package/lib/helper/FileSystem.js +1 -0
  36. package/lib/helper/Playwright.js +39 -20
  37. package/lib/helper/Protractor.js +2 -14
  38. package/lib/helper/Puppeteer.js +3 -18
  39. package/lib/helper/REST.js +1 -0
  40. package/lib/helper/WebDriver.js +3 -15
  41. package/lib/index.js +2 -0
  42. package/lib/interfaces/featureConfig.js +3 -0
  43. package/lib/interfaces/gherkin.js +7 -1
  44. package/lib/interfaces/scenarioConfig.js +4 -0
  45. package/lib/listener/helpers.js +1 -0
  46. package/lib/listener/steps.js +21 -3
  47. package/lib/listener/timeout.js +72 -0
  48. package/lib/locator.js +3 -0
  49. package/lib/mochaFactory.js +2 -3
  50. package/lib/plugin/allure.js +6 -1
  51. package/lib/plugin/coverage.js +1 -1
  52. package/lib/plugin/retryFailedStep.js +4 -3
  53. package/lib/plugin/retryTo.js +130 -0
  54. package/lib/plugin/screenshotOnFail.js +1 -0
  55. package/lib/plugin/stepByStepReport.js +7 -0
  56. package/lib/plugin/stepTimeout.js +91 -0
  57. package/lib/recorder.js +23 -9
  58. package/lib/step.js +58 -0
  59. package/lib/store.js +2 -0
  60. package/lib/ui.js +2 -2
  61. package/package.json +4 -6
  62. package/typings/index.d.ts +8 -1
  63. package/typings/types.d.ts +103 -70
  64. package/docs/angular.md +0 -325
  65. package/docs/helpers/Protractor.md +0 -1658
  66. package/docs/webapi/waitUntil.mustache +0 -11
  67. package/typings/Protractor.d.ts +0 -16
@@ -245,10 +245,12 @@ Remove an app from the device.
245
245
  I.removeApp('appName', 'com.example.android.apis');
246
246
  ```
247
247
 
248
+ Appium: support only Android
249
+
248
250
  #### Parameters
249
251
 
250
252
  - `appId` **[string][4]**
251
- - `bundleId` **[string][4]** String ID of bundleAppium: support only Android
253
+ - `bundleId` **[string][4]?** ID of bundle
252
254
 
253
255
  ### seeCurrentActivityIs
254
256
 
@@ -473,10 +475,12 @@ I.hideDeviceKeyboard('tapOutside');
473
475
  I.hideDeviceKeyboard('pressKey', 'Done');
474
476
  ```
475
477
 
478
+ Appium: support Android and iOS
479
+
476
480
  #### Parameters
477
481
 
478
- - `strategy` **(`"tapOutside"` \| `"pressKey"`)** desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’)Appium: support Android and iOS
479
- - `key`
482
+ - `strategy` **(`"tapOutside"` \| `"pressKey"`)?** Desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’)
483
+ - `key` **[string][4]?** Optional key
480
484
 
481
485
  ### sendDeviceKeyEvent
482
486
 
@@ -685,7 +689,7 @@ Appium: support Android and iOS
685
689
 
686
690
  #### Parameters
687
691
 
688
- - `actions`
692
+ - `actions` **[Array][11]** Array of touch actions
689
693
 
690
694
  ### pullFile
691
695
 
@@ -722,7 +726,7 @@ Perform a rotation gesture centered on the specified element.
722
726
  I.rotate(120, 120)
723
727
  ```
724
728
 
725
- See corresponding [webdriverio reference][11].
729
+ See corresponding [webdriverio reference][12].
726
730
 
727
731
  Appium: support only iOS
728
732
 
@@ -739,7 +743,7 @@ Appium: support only iOS
739
743
 
740
744
  Set immediate value in app.
741
745
 
742
- See corresponding [webdriverio reference][12].
746
+ See corresponding [webdriverio reference][13].
743
747
 
744
748
  Appium: support only iOS
745
749
 
@@ -926,7 +930,7 @@ let pins = await I.grabTextFromAll('#pin li');
926
930
 
927
931
  - `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator.
928
932
 
929
- Returns **[Promise][13]<[Array][14]<[string][4]>>** attribute value
933
+ Returns **[Promise][14]<[Array][11]<[string][4]>>** attribute value
930
934
 
931
935
  ### grabTextFrom
932
936
 
@@ -943,7 +947,7 @@ If multiple elements found returns first element.
943
947
 
944
948
  - `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator.
945
949
 
946
- Returns **[Promise][13]<[string][4]>** attribute value
950
+ Returns **[Promise][14]<[string][4]>** attribute value
947
951
 
948
952
  ### grabNumberOfVisibleElements
949
953
 
@@ -958,7 +962,7 @@ let numOfElements = await I.grabNumberOfVisibleElements('p');
958
962
 
959
963
  - `locator` **([string][4] \| [object][6])** located by CSS|XPath|strict locator.
960
964
 
961
- Returns **[Promise][13]<[number][8]>** number of visible elements
965
+ Returns **[Promise][14]<[number][8]>** number of visible elements
962
966
 
963
967
  ### grabAttributeFrom
964
968
 
@@ -977,7 +981,7 @@ let hint = await I.grabAttributeFrom('#tooltip', 'title');
977
981
  - `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator.
978
982
  - `attr` **[string][4]** attribute name.
979
983
 
980
- Returns **[Promise][13]<[string][4]>** attribute value
984
+ Returns **[Promise][14]<[string][4]>** attribute value
981
985
 
982
986
  ### grabAttributeFromAll
983
987
 
@@ -994,7 +998,7 @@ let hints = await I.grabAttributeFromAll('.tooltip', 'title');
994
998
  - `locator` **([string][4] \| [object][6])** element located by CSS|XPath|strict locator.
995
999
  - `attr` **[string][4]** attribute name.
996
1000
 
997
- Returns **[Promise][13]<[Array][14]<[string][4]>>** attribute value
1001
+ Returns **[Promise][14]<[Array][11]<[string][4]>>** attribute value
998
1002
 
999
1003
  ### grabValueFromAll
1000
1004
 
@@ -1009,7 +1013,7 @@ let inputs = await I.grabValueFromAll('//form/input');
1009
1013
 
1010
1014
  - `locator` **([string][4] \| [object][6])** field located by label|name|CSS|XPath|strict locator.
1011
1015
 
1012
- Returns **[Promise][13]<[Array][14]<[string][4]>>** attribute value
1016
+ Returns **[Promise][14]<[Array][11]<[string][4]>>** attribute value
1013
1017
 
1014
1018
  ### grabValueFrom
1015
1019
 
@@ -1025,7 +1029,7 @@ let email = await I.grabValueFrom('input[name=email]');
1025
1029
 
1026
1030
  - `locator` **([string][4] \| [object][6])** field located by label|name|CSS|XPath|strict locator.
1027
1031
 
1028
- Returns **[Promise][13]<[string][4]>** attribute value
1032
+ Returns **[Promise][14]<[string][4]>** attribute value
1029
1033
 
1030
1034
  ### saveScreenshot
1031
1035
 
@@ -1139,7 +1143,7 @@ I.selectOption('Which OS do you use?', ['Android', 'iOS']);
1139
1143
  #### Parameters
1140
1144
 
1141
1145
  - `select` **([string][4] \| [object][6])** field located by label|name|CSS|XPath|strict locator.
1142
- - `option` **([string][4] \| [Array][14]<any>)** visible text or value of option.Supported only for web testing
1146
+ - `option` **([string][4] \| [Array][11]<any>)** visible text or value of option.Supported only for web testing
1143
1147
 
1144
1148
  ### waitForElement
1145
1149
 
@@ -1311,7 +1315,7 @@ I.defineTimeout({ implicit: 10000, pageLoad: 10000, script: 5000 });
1311
1315
 
1312
1316
  #### Parameters
1313
1317
 
1314
- - `timeouts` **WebdriverIO.Timeouts** WebDriver timeouts object.
1318
+ - `timeouts` **any** WebDriver timeouts object.
1315
1319
 
1316
1320
  ### amOnPage
1317
1321
 
@@ -1482,7 +1486,7 @@ let postHTMLs = await I.grabHTMLFromAll('.post');
1482
1486
  - `locator`
1483
1487
  - `element` **([string][4] \| [object][6])** located by CSS|XPath|strict locator.
1484
1488
 
1485
- Returns **[Promise][13]<[Array][14]<[string][4]>>** HTML code for an element
1489
+ Returns **[Promise][14]<[Array][11]<[string][4]>>** HTML code for an element
1486
1490
 
1487
1491
  ### grabHTMLFrom
1488
1492
 
@@ -1499,7 +1503,7 @@ let postHTML = await I.grabHTMLFrom('#post');
1499
1503
  - `locator`
1500
1504
  - `element` **([string][4] \| [object][6])** located by CSS|XPath|strict locator.
1501
1505
 
1502
- Returns **[Promise][13]<[string][4]>** HTML code for an element
1506
+ Returns **[Promise][14]<[string][4]>** HTML code for an element
1503
1507
 
1504
1508
  ### seeTextEquals
1505
1509
 
@@ -1560,7 +1564,7 @@ Resumes test execution, so **should be used inside async function with `await`**
1560
1564
  let pageSource = await I.grabSource();
1561
1565
  ```
1562
1566
 
1563
- Returns **[Promise][13]<[string][4]>** source code
1567
+ Returns **[Promise][14]<[string][4]>** source code
1564
1568
 
1565
1569
  ### grabBrowserLogs
1566
1570
 
@@ -1572,7 +1576,7 @@ let logs = await I.grabBrowserLogs();
1572
1576
  console.log(JSON.stringify(logs))
1573
1577
  ```
1574
1578
 
1575
- Returns **([Promise][13]<[Array][14]<[object][6]>> | [undefined][19])** all browser logs
1579
+ Returns **([Promise][14]<[Array][11]<[object][6]>> | [undefined][19])** all browser logs
1576
1580
 
1577
1581
  ### dontSeeInSource
1578
1582
 
@@ -1697,7 +1701,7 @@ I.type(['T', 'E', 'X', 'T']);
1697
1701
 
1698
1702
  - `keys`
1699
1703
  - `delay` **[number][8]?** (optional) delay in ms between key presses (optional, default `null`)
1700
- - `key` **([string][4] \| [Array][14]<[string][4]>)** or array of keys to type.
1704
+ - `key` **([string][4] \| [Array][11]<[string][4]>)** or array of keys to type.
1701
1705
 
1702
1706
  ### dragAndDrop
1703
1707
 
@@ -1736,7 +1740,7 @@ Useful for referencing a specific handle when calling `I.switchToWindow(handle)`
1736
1740
  const windows = await I.grabAllWindowHandles();
1737
1741
  ```
1738
1742
 
1739
- Returns **[Promise][13]<[Array][14]<[string][4]>>**
1743
+ Returns **[Promise][14]<[Array][11]<[string][4]>>**
1740
1744
 
1741
1745
  ### grabCurrentWindowHandle
1742
1746
 
@@ -1747,7 +1751,7 @@ Useful for referencing it when calling `I.switchToWindow(handle)`
1747
1751
  const window = await I.grabCurrentWindowHandle();
1748
1752
  ```
1749
1753
 
1750
- Returns **[Promise][13]<[string][4]>**
1754
+ Returns **[Promise][14]<[string][4]>**
1751
1755
 
1752
1756
  ### switchToWindow
1753
1757
 
@@ -1797,7 +1801,7 @@ Resumes test execution, so **should be used inside async function with `await`**
1797
1801
  let tabs = await I.grabNumberOfOpenTabs();
1798
1802
  ```
1799
1803
 
1800
- Returns **[Promise][13]<[number][8]>** number of open tabs
1804
+ Returns **[Promise][14]<[number][8]>** number of open tabs
1801
1805
 
1802
1806
  ### scrollPageToTop
1803
1807
 
@@ -1824,7 +1828,7 @@ Resumes test execution, so **should be used inside an async function with `await
1824
1828
  let { x, y } = await I.grabPageScrollPosition();
1825
1829
  ```
1826
1830
 
1827
- Returns **[Promise][13]<PageScrollPosition>** scroll position
1831
+ Returns **[Promise][14]<PageScrollPosition>** scroll position
1828
1832
 
1829
1833
  ### setGeoLocation
1830
1834
 
@@ -1850,7 +1854,7 @@ Resumes test execution, so **should be used inside async function with `await`**
1850
1854
  let geoLocation = await I.grabGeoLocation();
1851
1855
  ```
1852
1856
 
1853
- Returns **[Promise][13]<{latitude: [number][8], longitude: [number][8], altitude: [number][8]}>**
1857
+ Returns **[Promise][14]<{latitude: [number][8], longitude: [number][8], altitude: [number][8]}>**
1854
1858
 
1855
1859
  ### grabElementBoundingRect
1856
1860
 
@@ -1878,7 +1882,7 @@ const width = await I.grabElementBoundingRect('h3', 'width');
1878
1882
  - `prop`
1879
1883
  - `elementSize` **[string][4]?** x, y, width or height of the given element.
1880
1884
 
1881
- Returns **([Promise][13]<DOMRect> | [Promise][13]<[number][8]>)** Element bounding rectangle
1885
+ Returns **([Promise][14]<DOMRect> | [Promise][14]<[number][8]>)** Element bounding rectangle
1882
1886
 
1883
1887
  [1]: http://codecept.io/helpers/WebDriver/
1884
1888
 
@@ -1900,13 +1904,13 @@ Returns **([Promise][13]<DOMRect> | [Promise][13]<[number][8]>)** Element
1900
1904
 
1901
1905
  [10]: http://webdriver.io/api/mobile/swipe.html
1902
1906
 
1903
- [11]: http://webdriver.io/api/mobile/rotate.html
1907
+ [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
1904
1908
 
1905
- [12]: http://webdriver.io/api/mobile/setImmediateValue.html
1909
+ [12]: http://webdriver.io/api/mobile/rotate.html
1906
1910
 
1907
- [13]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
1911
+ [13]: http://webdriver.io/api/mobile/setImmediateValue.html
1908
1912
 
1909
- [14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
1913
+ [14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise
1910
1914
 
1911
1915
  [15]: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
1912
1916
 
@@ -101,7 +101,7 @@ I.seeFileNameMatching('.pdf');
101
101
 
102
102
  #### Parameters
103
103
 
104
- - `text`
104
+ - `text` **[string][1]**
105
105
 
106
106
  ### seeInThisFile
107
107
 
@@ -47,6 +47,7 @@ This helper should be configured in codecept.json or codecept.conf.js
47
47
  - `basicAuth`: (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
48
48
  - `windowSize`: (optional) default window size. Set a dimension like `640x480`.
49
49
  - `userAgent`: (optional) user-agent string.
50
+ - `locale`: (optional) locale string. Example: 'en-GB', 'de-DE', 'fr-FR', ...
50
51
  - `manualStart`: - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
51
52
  - `chromium`: (optional) pass additional chromium options
52
53
  - `electron`: (optional) pass additional electron options
@@ -162,6 +163,19 @@ const { devices } = require('playwright');
162
163
  }
163
164
  ```
164
165
 
166
+ #### Example #7: Launch test with a specifc user locale
167
+
168
+ ```js
169
+ {
170
+ helpers: {
171
+ Playwright : {
172
+ url: "http://localhost",
173
+ locale: "fr-FR",
174
+ }
175
+ }
176
+ }
177
+ ```
178
+
165
179
  Note: When connecting to remote browser `show` and specific `chrome` options (e.g. `headless` or `devtools`) are ignored.
166
180
 
167
181
  ## Access From Helpers
@@ -1821,11 +1835,11 @@ I.waitForRequest(request => request.url() === 'http://example.com' && request.me
1821
1835
 
1822
1836
  ### waitForResponse
1823
1837
 
1824
- Waits for a network request.
1838
+ Waits for a network response.
1825
1839
 
1826
1840
  ```js
1827
1841
  I.waitForResponse('http://example.com/resource');
1828
- I.waitForResponse(request => request.url() === 'http://example.com' && request.method() === 'GET');
1842
+ I.waitForResponse(response => response.url() === 'https://example.com' && response.status() === 200);
1829
1843
  ```
1830
1844
 
1831
1845
  #### Parameters
@@ -1919,22 +1933,6 @@ I.waitToHide('#popup');
1919
1933
  - `locator` **([string][9] | [object][7])** element located by CSS|XPath|strict locator.
1920
1934
  - `sec` **[number][10]** (optional, `1` by default) time in seconds to wait
1921
1935
 
1922
- ### waitUntil
1923
-
1924
- Waits for a function to return true (waits for 1sec by default).
1925
-
1926
- ```js
1927
- I.waitUntil(() => window.requests == 0);
1928
- I.waitUntil(() => window.requests == 0, 5);
1929
- ```
1930
-
1931
- #### Parameters
1932
-
1933
- - `fn` **([function][11] | [string][9])** function which is executed in browser context.
1934
- - `sec` **[number][10]** (optional, `1` by default) time in seconds to wait
1935
- - `timeoutMsg` **[string][9]** message to show in case of timeout fail.
1936
- - `interval` **[number][10]?**
1937
-
1938
1936
  ### waitUrlEquals
1939
1937
 
1940
1938
  Waits for the entire URL to match the expected
@@ -1614,7 +1614,7 @@ I.seeTitleEquals('Test title.');
1614
1614
 
1615
1615
  #### Parameters
1616
1616
 
1617
- - `text`
1617
+ - `text` **[string][8]** value to check.
1618
1618
 
1619
1619
  ### selectOption
1620
1620
 
@@ -1998,22 +1998,6 @@ I.waitToHide('#popup');
1998
1998
  - `locator` **([string][8] | [object][6])** element located by CSS|XPath|strict locator.
1999
1999
  - `sec` **[number][10]** (optional, `1` by default) time in seconds to wait
2000
2000
 
2001
- ### waitUntil
2002
-
2003
- Waits for a function to return true (waits for 1sec by default).
2004
-
2005
- ```js
2006
- I.waitUntil(() => window.requests == 0);
2007
- I.waitUntil(() => window.requests == 0, 5);
2008
- ```
2009
-
2010
- #### Parameters
2011
-
2012
- - `fn` **([function][12] | [string][8])** function which is executed in browser context.
2013
- - `sec` **[number][10]** (optional, `1` by default) time in seconds to wait
2014
- - `timeoutMsg` **[string][8]** message to show in case of timeout fail.
2015
- - `interval` **[number][10]?**
2016
-
2017
2001
  ### waitUrlEquals
2018
2002
 
2019
2003
  Waits for the entire URL to match the expected
@@ -168,7 +168,7 @@ I.setRequestTimeout(10000); // In milliseconds
168
168
 
169
169
  #### Parameters
170
170
 
171
- - `newTimeout`
171
+ - `newTimeout` **[number][5]** timeout in milliseconds
172
172
 
173
173
  [1]: https://github.com/axios/axios
174
174
 
@@ -177,3 +177,5 @@ I.setRequestTimeout(10000); // In milliseconds
177
177
  [3]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
178
178
 
179
179
  [4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
180
+
181
+ [5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
@@ -599,7 +599,7 @@ I.defineTimeout({ implicit: 10000, pageLoad: 10000, script: 5000 });
599
599
 
600
600
  #### Parameters
601
601
 
602
- - `timeouts` **WebdriverIO.Timeouts** WebDriver timeouts object.
602
+ - `timeouts` **any** WebDriver timeouts object.
603
603
 
604
604
  ### dontSee
605
605
 
@@ -2155,22 +2155,6 @@ I.waitToHide('#popup');
2155
2155
  - `locator` **([string][19] | [object][18])** element located by CSS|XPath|strict locator.
2156
2156
  - `sec` **[number][22]** (optional, `1` by default) time in seconds to wait
2157
2157
 
2158
- ### waitUntil
2159
-
2160
- Waits for a function to return true (waits for 1sec by default).
2161
-
2162
- ```js
2163
- I.waitUntil(() => window.requests == 0);
2164
- I.waitUntil(() => window.requests == 0, 5);
2165
- ```
2166
-
2167
- #### Parameters
2168
-
2169
- - `fn` **([function][24] | [string][19])** function which is executed in browser context.
2170
- - `sec` **[number][22]** (optional, `1` by default) time in seconds to wait
2171
- - `timeoutMsg` **[string][19]** message to show in case of timeout fail.
2172
- - `interval` **[number][22]?**
2173
-
2174
2158
  ### waitUrlEquals
2175
2159
 
2176
2160
  Waits for the entire URL to match the expected
@@ -1,6 +1,9 @@
1
1
  ## Automating React Native apps
2
2
 
3
3
  ### Problem
4
+
5
+ > ⚠️ **NOTE**: This problem is not actual starting from `react-native@0.65.x` [CHANGELOG](https://github.com/react-native-community/releases/blob/master/CHANGELOG.md#android-specific-9), [#381fb3](https://github.com/facebook/react-native/commit/381fb395ad9d2d48717a5d082aaedbecdd804554)
6
+
4
7
  Let's say we have a React Native app with component defined like this
5
8
  ```html
6
9
  <Button testID='someButton'>My button</Button>
@@ -191,6 +191,8 @@ module.exports = new AttachFile();
191
191
  module.exports.AttachFile = AttachFile;
192
192
  ```
193
193
 
194
+ > ⚠ While building complex page objects it is important to keep all `async` functions to be called with `await`. While CodeceptJS allows to run commands synchronously if async function has `I.grab*` or any custom function that returns a promise it must be called with `await`. If you see `UnhandledPromiseRejectionWarning` it might be caused by async page object function that was called without `await`.
195
+
194
196
  ## Page Fragments
195
197
 
196
198
  Similarly, CodeceptJS allows you to generate **PageFragments** and any other abstractions
@@ -406,6 +406,11 @@ When a test fails and video was enabled a video file is shown under the `artifac
406
406
 
407
407
  Open video and use it to debug a failed test case. Video helps when running tests on CI. Configure your CI system to enable artifacts storage for `output/video` and review videos of failed test case to understand failures.
408
408
 
409
+ It is recommended to enable [subtitles](https://codecept.io/plugins/#subtitles) plugin which will generate subtitles from steps in `.srt` format. Subtitles file will be saved into after a video file so video player (like VLC) would load them automatically:
410
+
411
+ ![](https://user-images.githubusercontent.com/220264/131644090-38d1ca55-1ba1-41fa-8fd1-7dea2b7ae995.png)
412
+
413
+
409
414
  ## Trace <Badge text="Since 3.1" type="warning"/>
410
415
 
411
416
  If video is not enough to descover why a test failed a [trace](https://playwright.dev/docs/trace-viewer/) can be recorded.
@@ -456,7 +461,7 @@ For instance, this is how you can read a trace for a failed test from an example
456
461
  npx playwright show-trace /home/davert/projects/codeceptjs/examples/output/trace/open.zip
457
462
  ```
458
463
 
459
- ## Capturing code coverage
464
+ ## Capturing Code Coverage
460
465
 
461
466
  Code coverage can be captured, by enabling the `coverage` plugin in `codecept.config.js`.
462
467
 
@@ -474,45 +479,23 @@ Once all the tests are completed, `codecept` will create and store coverage in `
474
479
 
475
480
  ![](https://user-images.githubusercontent.com/16587779/131362352-30ee9c51-705f-4098-b665-53035ea9275f.png)
476
481
 
477
- ### Converting `playwright` coverage to `istanbul` coverage
478
-
479
- To convert coverage generated from `playwright` to `istanbul` coverage, you first need to install
480
- - [`v8-to-istanbul`](https://www.npmjs.com/package/v8-to-istanbul)
481
-
482
- Once installed, convert the coverage to a format which `istanbul` can recognize, by writing a script as shown below.
483
-
484
- ```js
485
- const v8toIstanbul = require('v8-to-istanbul');
486
- // read all the coverage file from output/coverage folder
487
- const coverage = require('./output/coverage/Visit_Home_1630335005.coverage.json');
488
- const fs = require('fs/promises');
489
-
490
- (async () => {
491
- for (const entry of coverage) {
492
- // Used to get file name
493
- const file = entry.url.match(/(?:http(s)*:\/\/.*\/)(?<file>.*)/);
494
- const converter = new v8toIstanbul(file.groups.file, 0, {
495
- source: entry.source
496
- });
497
-
498
- await converter.load();
499
- converter.applyCoverage(entry.functions);
500
-
501
- // Store converted coverage file which can later be used to generate report
502
- await fs.writeFile('./coverage/final.json', JSON.stringify(converter.toIstanbul(), null, 2));
503
- }
504
- })();
505
- ```
482
+ Then you need to [convert code coverage from Playwright's format into Istanbul format](https://github.com/codeceptjs/CodeceptJS/wiki/Converting-Playwright-to-Istanbul-Coverage).
506
483
 
507
484
  Once the istanbul compatible coverage is generated, use [`nyc`](https://www.npmjs.com/package/nyc) to generate your coverage report in your desired format.
508
485
 
509
486
  ```
510
- npx nyc report --reporter text -t coverage
487
+ npx nyc report --reporter html -t coverage
511
488
  ```
512
489
 
513
- The above command will generate a text report like shown below.
490
+ The above command will generate will generate coverage in an interactive html format. It should generate `html` files in the directory where your code coverage is present, something like shown below.
491
+
492
+ ![](https://user-images.githubusercontent.com/16587779/131858419-cbc7df7d-0851-47b9-b086-b5e3b9165674.png)
493
+
494
+ Open `index.html` in your browser to view the full interactive coverage report.
495
+
496
+ ![](https://user-images.githubusercontent.com/16587779/131858993-87d1aafc-8ef1-4a82-867d-e64a13e36106.png)
514
497
 
515
- ![](https://user-images.githubusercontent.com/16587779/131363170-b03b4398-5e9a-4142-bc32-764a5f4a5e11.png)
498
+ ![](https://user-images.githubusercontent.com/16587779/131859006-c6f17d18-c603-44a5-9d59-0670177276cf.png)
516
499
  ## Extending Helper
517
500
 
518
501
  To create custom `I.*` commands using Playwright API you need to create a custom helper.
package/docs/plugins.md CHANGED
@@ -417,7 +417,7 @@ Dumps code coverage from Playwright/Puppeteer after every test.
417
417
 
418
418
  ```js
419
419
  plugins: {
420
- playwrightCoverage: {
420
+ coverage: {
421
421
  enabled: true
422
422
  }
423
423
  }
@@ -579,9 +579,9 @@ Run tests with plugin enabled:
579
579
 
580
580
  #### Configuration:
581
581
 
582
- - `retries` - number of retries (by default 5),
582
+ - `retries` - number of retries (by default 3),
583
583
  - `when` - function, when to perform a retry (accepts error as parameter)
584
- - `factor` - The exponential factor to use. Default is 2.
584
+ - `factor` - The exponential factor to use. Default is 1.5.
585
585
  - `minTimeout` - The number of milliseconds before starting the first retry. Default is 1000.
586
586
  - `maxTimeout` - The maximum number of milliseconds between two retries. Default is Infinity.
587
587
  - `randomize` - Randomizes the timeouts by multiplying with a factor between 1 to 2. Default is false.
@@ -626,6 +626,75 @@ Scenario('scenario tite', () => {
626
626
 
627
627
  - `config`
628
628
 
629
+ ## retryTo
630
+
631
+ Adds global `retryTo` which retries steps a few times before failing.
632
+
633
+ Enable this plugin in `codecept.conf.js` (enabled by default for new setups):
634
+
635
+ ```js
636
+ plugins: {
637
+ retryTo: {
638
+ enabled: true
639
+ }
640
+ }
641
+ ```
642
+
643
+ Use it in your tests:
644
+
645
+ ```js
646
+ // retry these steps 5 times before failing
647
+ await retryTo((tryNum) => {
648
+ I.switchTo('#editor frame');
649
+ I.click('Open');
650
+ I.see('Opened')
651
+ }, 5);
652
+ ```
653
+
654
+ Set polling interval as 3rd argument (200ms by default):
655
+
656
+ ```js
657
+ // retry these steps 5 times before failing
658
+ await retryTo((tryNum) => {
659
+ I.switchTo('#editor frame');
660
+ I.click('Open');
661
+ I.see('Opened')
662
+ }, 5, 100);
663
+ ```
664
+
665
+ Default polling interval can be changed in a config:
666
+
667
+ ```js
668
+ plugins: {
669
+ retryTo: {
670
+ enabled: true,
671
+ pollInterval: 500,
672
+ }
673
+ }
674
+ ```
675
+
676
+ Disables retryFailedStep plugin for steps inside a block;
677
+
678
+ Use this plugin if:
679
+
680
+ - you need repeat a set of actions in flaky tests
681
+ - iframe was not rendered and you need to retry switching to it
682
+
683
+ #### Configuration
684
+
685
+ - `pollInterval` - default interval between retries in ms. 200 by default.
686
+ - `registerGlobal` - to register `retryTo` function globally, true by default
687
+
688
+ If `registerGlobal` is false you can use retryTo from the plugin:
689
+
690
+ ```js
691
+ const retryTo = codeceptjs.container.plugins('retryTo');
692
+ ```
693
+
694
+ ### Parameters
695
+
696
+ - `config`
697
+
629
698
  ## screenshotOnFail
630
699
 
631
700
  Creates screenshot on failure. Screenshot is saved into `output` directory.
@@ -802,11 +871,67 @@ Possible config options:
802
871
  - `fullPageScreenshots`: should full page screenshots be used. Default: false.
803
872
  - `output`: a directory where reports should be stored. Default: `output`.
804
873
  - `screenshotsForAllureReport`: If Allure plugin is enabled this plugin attaches each saved screenshot to allure report. Default: false.
874
+ - \`disableScreenshotOnFail : Disables the capturing of screeshots after the failed step. Default: true.
805
875
 
806
876
  ### Parameters
807
877
 
808
878
  - `config` **any**
809
879
 
880
+ ## stepTimeout
881
+
882
+ Set timeout for test steps globally.
883
+
884
+ Add this plugin to config file:
885
+
886
+ ```js
887
+ plugins: {
888
+ stepTimeout: {
889
+ enabled: true
890
+ }
891
+ }
892
+ ```
893
+
894
+ Run tests with plugin enabled:
895
+
896
+ npx codeceptjs run --plugins stepTimeout
897
+
898
+ #### Configuration:
899
+
900
+ - `timeout` - global step timeout, default 150 seconds
901
+ - `overrideStepLimits` - whether to use timeouts set in plugin config to override step timeouts set in code with I.limitTime(x).action(...), default false
902
+ - `noTimeoutSteps` - an array of steps with no timeout. Default:
903
+
904
+ - `amOnPage`
905
+ - `wait*`
906
+
907
+ you could set your own noTimeoutSteps which would replace the default one.
908
+
909
+ - `customTimeoutSteps` - an array of step actions with custom timeout. Use it to override or extend noTimeoutSteps.
910
+ You can use step names or step prefixes ending with `*`. As such, `wait*` will match all steps starting with `wait`.
911
+
912
+ #### Example
913
+
914
+ ```js
915
+ plugins: {
916
+ stepTimeout: {
917
+ enabled: true,
918
+ overrideStepLimits: true,
919
+ noTimeoutSteps: [
920
+ 'scroll*', // ignore all scroll steps
921
+ /Cookie/, // ignore all steps with a Cookie in it (by regexp)
922
+ ],
923
+ customTimeoutSteps: [
924
+ ['myFlakyStep*', 1],
925
+ ['scrollWhichRequiresTimeout', 5],
926
+ ]
927
+ }
928
+ }
929
+ ```
930
+
931
+ ### Parameters
932
+
933
+ - `config`
934
+
810
935
  ## subtitles
811
936
 
812
937
  Automatically captures steps as subtitle, and saves it as an artifact when a video is found for a failed test