codeceptjs 3.3.8-beta.1 → 3.4.0-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 (63) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +31 -32
  3. package/docs/advanced.md +48 -24
  4. package/docs/basics.md +115 -40
  5. package/docs/best.md +2 -2
  6. package/docs/build/ApiDataFactory.js +6 -6
  7. package/docs/build/Appium.js +2 -19
  8. package/docs/build/FileSystem.js +2 -2
  9. package/docs/build/GraphQLDataFactory.js +2 -2
  10. package/docs/build/Playwright.js +3 -2
  11. package/docs/build/TestCafe.js +4 -4
  12. package/docs/build/WebDriver.js +29 -164
  13. package/docs/helpers/ApiDataFactory.md +6 -6
  14. package/docs/helpers/FileSystem.md +2 -2
  15. package/docs/helpers/GraphQLDataFactory.md +2 -2
  16. package/docs/helpers/Playwright.md +2 -1
  17. package/docs/index.md +1 -1
  18. package/docs/plugins.md +73 -48
  19. package/docs/reports.md +0 -56
  20. package/docs/typescript.md +2 -8
  21. package/lib/actor.js +2 -1
  22. package/lib/cli.js +3 -3
  23. package/lib/codecept.js +2 -1
  24. package/lib/command/generate.js +3 -1
  25. package/lib/command/gherkin/snippets.js +8 -4
  26. package/lib/command/init.js +0 -8
  27. package/lib/command/run-workers.js +3 -6
  28. package/lib/command/utils.js +0 -10
  29. package/lib/command/workers/runTests.js +2 -2
  30. package/lib/config.js +5 -1
  31. package/lib/helper/ApiDataFactory.js +7 -7
  32. package/lib/helper/Appium.js +2 -19
  33. package/lib/helper/FileSystem.js +3 -3
  34. package/lib/helper/GraphQL.js +1 -1
  35. package/lib/helper/GraphQLDataFactory.js +3 -3
  36. package/lib/helper/JSONResponse.js +1 -1
  37. package/lib/helper/Mochawesome.js +1 -1
  38. package/lib/helper/Nightmare.js +1 -1
  39. package/lib/helper/Playwright.js +4 -3
  40. package/lib/helper/Protractor.js +1 -1
  41. package/lib/helper/Puppeteer.js +1 -1
  42. package/lib/helper/REST.js +1 -1
  43. package/lib/helper/TestCafe.js +5 -5
  44. package/lib/helper/WebDriver.js +30 -165
  45. package/lib/helper.js +0 -2
  46. package/lib/interfaces/bdd.js +1 -1
  47. package/lib/interfaces/featureConfig.js +1 -0
  48. package/lib/interfaces/gherkin.js +38 -25
  49. package/lib/listener/exit.js +2 -2
  50. package/lib/listener/retry.js +67 -0
  51. package/lib/listener/steps.js +1 -1
  52. package/lib/listener/timeout.js +47 -10
  53. package/lib/mochaFactory.js +3 -3
  54. package/lib/plugin/allure.js +14 -323
  55. package/lib/plugin/fakerTransform.js +2 -2
  56. package/lib/recorder.js +1 -1
  57. package/lib/scenario.js +25 -18
  58. package/lib/utils.js +6 -0
  59. package/lib/workers.js +4 -7
  60. package/package.json +13 -17
  61. package/typings/index.d.ts +66 -1
  62. package/typings/promiseBasedTypes.d.ts +12 -12
  63. package/typings/types.d.ts +95 -262
package/CHANGELOG.md CHANGED
@@ -1,3 +1,50 @@
1
+ ## 3.4.0
2
+
3
+ * **Updated to latest mocha and modern Cucumber**
4
+ * **Allure plugin moved to [@codeceptjs/allure-legacy](https://github.com/codeceptjs/allure-legacy) package**. This happened because allure-commons package v1 was not updated and caused vulnarabilities. Fixes #3422. We don't plan to maintain allure v2 plugin so it's up to community to take this initiative. Current allure plugin will print a warning message without interfering the run, so it won't accidentally fail your builds.
5
+ * Added ability to **[retry Before](https://codecept.io/basics/#retry-before), BeforeSuite, After, AfterSuite** hooks by @davertmik:
6
+ ```js
7
+ Feature('flaky Before & BeforeSuite', { retryBefore: 2, retryBeforeSuite: 3 })
8
+ ```
9
+
10
+ * **Flexible [retries configuration](https://codecept.io/basics/#retry-configuration) introduced** by @davertmik:
11
+
12
+ ```js
13
+ retry: [
14
+ {
15
+ // enable this config only for flaky tests
16
+ grep: '@flaky',
17
+ Before: 3 // retry Before 3 times
18
+ Scenario: 3 // retry Scenario 3 times
19
+ },
20
+ {
21
+ // retry less when running slow tests
22
+ grep: '@slow'
23
+ Scenario: 1
24
+ Before: 1
25
+ }, {
26
+ // retry all BeforeSuite 3 times
27
+ BeforeSuite: 3
28
+ }
29
+ ]
30
+ ```
31
+ * **Flexible [timeout configuration](https://codecept.io/advanced/#timeout-configuration)** introduced by @davertmik:
32
+
33
+ ```js
34
+ timeout: [
35
+ 10, // default timeout is 10secs
36
+ { // but increase timeout for slow tests
37
+ grep: '@slow',
38
+ Feature: 50
39
+ },
40
+ ]
41
+ ```
42
+
43
+ * JsDoc: Removed promise from `I.say`. See #3535 by @danielrentz
44
+ * [Playwright] `handleDownloads` requires now a filename param. See #3511 by @PeterNgTr
45
+ * [WebDriver] Added support for v8, removed support for webdriverio v5 and lower. See #3578 by @PeterNgTr
46
+
47
+
1
48
  ## 3.3.7
2
49
 
3
50
  🛩️ Features
package/README.md CHANGED
@@ -101,8 +101,7 @@ npx codeceptjs def .
101
101
  Later you can even automagically update Type Definitions to include your own custom [helpers methods](docs/helpers.md).
102
102
 
103
103
  Note:
104
- - CodeceptJS requires Node.js version `8.9.1+` or later.
105
- - To use the parallel tests execution, requiring Node.js version `11.7` or later.
104
+ - CodeceptJS requires Node.js version `12+` or later.
106
105
 
107
106
  ## Usage
108
107
 
@@ -294,36 +293,36 @@ When using Typescript, replace `module.exports` with `export` for autocompletion
294
293
  Thanks all to those who are and will have contributing to this awesome project!
295
294
 
296
295
  [//]: contributor-faces
297
- <a href="https://github.com/DavertMik"><img src="https://avatars0.githubusercontent.com/u/220264?v=4" title="DavertMik" width="80" height="80"></a>
298
- <a href="https://github.com/PeterNgTr"><img src="https://avatars0.githubusercontent.com/u/7845001?v=4" title="PeterNgTr" width="80" height="80"></a>
299
- <a href="https://github.com/Vorobeyko"><img src="https://avatars3.githubusercontent.com/u/11293201?v=4" title="Vorobeyko" width="80" height="80"></a>
300
- <a href="https://github.com/APshenkin"><img src="https://avatars1.githubusercontent.com/u/14344430?v=4" title="APshenkin" width="80" height="80"></a>
301
- <a href="https://github.com/reubenmiller"><img src="https://avatars0.githubusercontent.com/u/3029781?v=4" title="reubenmiller" width="80" height="80"></a>
302
- <a href="https://github.com/fabioel"><img src="https://avatars1.githubusercontent.com/u/9824235?v=4" title="fabioel" width="80" height="80"></a>
303
- <a href="https://github.com/pablopaul"><img src="https://avatars1.githubusercontent.com/u/635526?v=4" title="pablopaul" width="80" height="80"></a>
304
- <a href="https://github.com/koushikmohan1996"><img src="https://avatars3.githubusercontent.com/u/24666922?v=4" title="koushikmohan1996" width="80" height="80"></a>
305
- <a href="https://github.com/Arhell"><img src="https://avatars2.githubusercontent.com/u/26163841?v=4" title="Arhell" width="80" height="80"></a>
306
- <a href="https://github.com/tsuemura"><img src="https://avatars1.githubusercontent.com/u/17092259?v=4" title="tsuemura" width="80" height="80"></a>
307
- <a href="https://github.com/VikalpP"><img src="https://avatars2.githubusercontent.com/u/11846339?v=4" title="VikalpP" width="80" height="80"></a>
308
- <a href="https://github.com/elukoyanov"><img src="https://avatars3.githubusercontent.com/u/11647141?v=4" title="elukoyanov" width="80" height="80"></a>
309
- <a href="https://github.com/MercifulCode"><img src="https://avatars2.githubusercontent.com/u/1740822?v=4" title="MercifulCode" width="80" height="80"></a>
310
- <a href="https://github.com/Georgegriff"><img src="https://avatars3.githubusercontent.com/u/9056958?v=4" title="Georgegriff" width="80" height="80"></a>
311
- <a href="https://github.com/hubidu"><img src="https://avatars2.githubusercontent.com/u/13134082?v=4" title="hubidu" width="80" height="80"></a>
312
- <a href="https://github.com/BorisOsipov"><img src="https://avatars0.githubusercontent.com/u/6514276?v=4" title="BorisOsipov" width="80" height="80"></a>
313
- <a href="https://github.com/jploskonka"><img src="https://avatars3.githubusercontent.com/u/669483?v=4" title="jploskonka" width="80" height="80"></a>
314
- <a href="https://github.com/martomo"><img src="https://avatars2.githubusercontent.com/u/1850135?v=4" title="martomo" width="80" height="80"></a>
315
- <a href="https://github.com/denis-sokolov"><img src="https://avatars0.githubusercontent.com/u/113721?v=4" title="denis-sokolov" width="80" height="80"></a>
316
- <a href="https://github.com/lennym"><img src="https://avatars3.githubusercontent.com/u/117398?v=4" title="lennym" width="80" height="80"></a>
317
- <a href="https://github.com/petehouston"><img src="https://avatars0.githubusercontent.com/u/9006720?v=4" title="petehouston" width="80" height="80"></a>
318
- <a href="https://github.com/Holorium"><img src="https://avatars1.githubusercontent.com/u/10815542?v=4" title="Holorium" width="80" height="80"></a>
319
- <a href="https://github.com/nitschSB"><img src="https://avatars0.githubusercontent.com/u/39341455?v=4" title="nitschSB" width="80" height="80"></a>
320
- <a href="https://github.com/johnyb"><img src="https://avatars2.githubusercontent.com/u/86358?v=4" title="johnyb" width="80" height="80"></a>
321
- <a href="https://github.com/jamesgeorge007"><img src="https://avatars2.githubusercontent.com/u/25279263?v=4" title="jamesgeorge007" width="80" height="80"></a>
322
- <a href="https://github.com/jinjorge"><img src="https://avatars3.githubusercontent.com/u/2208083?v=4" title="jinjorge" width="80" height="80"></a>
323
- <a href="https://github.com/gkushang"><img src="https://avatars1.githubusercontent.com/u/3663389?v=4" title="gkushang" width="80" height="80"></a>
324
- <a href="https://github.com/galkin"><img src="https://avatars3.githubusercontent.com/u/5930544?v=4" title="galkin" width="80" height="80"></a>
325
- <a href="https://github.com/orihomie"><img src="https://avatars2.githubusercontent.com/u/29889683?v=4" title="orihomie" width="80" height="80"></a>
326
- <a href="https://github.com/radhey1851"><img src="https://avatars2.githubusercontent.com/u/22446528?v=4" title="radhey1851" width="80" height="80"></a>
296
+ <a href="https://github.com/DavertMik"><img src="https://avatars.githubusercontent.com/u/220264?v=4" title="DavertMik" width="80" height="80"></a>
297
+ <a href="https://github.com/PeterNgTr"><img src="https://avatars.githubusercontent.com/u/7845001?v=4" title="PeterNgTr" width="80" height="80"></a>
298
+ <a href="https://github.com/Vorobeyko"><img src="https://avatars.githubusercontent.com/u/11293201?v=4" title="Vorobeyko" width="80" height="80"></a>
299
+ <a href="https://github.com/reubenmiller"><img src="https://avatars.githubusercontent.com/u/3029781?v=4" title="reubenmiller" width="80" height="80"></a>
300
+ <a href="https://github.com/Arhell"><img src="https://avatars.githubusercontent.com/u/26163841?v=4" title="Arhell" width="80" height="80"></a>
301
+ <a href="https://github.com/APshenkin"><img src="https://avatars.githubusercontent.com/u/14344430?v=4" title="APshenkin" width="80" height="80"></a>
302
+ <a href="https://github.com/fabioel"><img src="https://avatars.githubusercontent.com/u/9824235?v=4" title="fabioel" width="80" height="80"></a>
303
+ <a href="https://github.com/pablopaul"><img src="https://avatars.githubusercontent.com/u/635526?v=4" title="pablopaul" width="80" height="80"></a>
304
+ <a href="https://github.com/Georgegriff"><img src="https://avatars.githubusercontent.com/u/9056958?v=4" title="Georgegriff" width="80" height="80"></a>
305
+ <a href="https://github.com/mirao"><img src="https://avatars.githubusercontent.com/u/12584138?v=4" title="mirao" width="80" height="80"></a>
306
+ <a href="https://github.com/KMKoushik"><img src="https://avatars.githubusercontent.com/u/24666922?v=4" title="KMKoushik" width="80" height="80"></a>
307
+ <a href="https://github.com/nikocanvacom"><img src="https://avatars.githubusercontent.com/u/83254493?v=4" title="nikocanvacom" width="80" height="80"></a>
308
+ <a href="https://github.com/elukoyanov"><img src="https://avatars.githubusercontent.com/u/11647141?v=4" title="elukoyanov" width="80" height="80"></a>
309
+ <a href="https://github.com/gkushang"><img src="https://avatars.githubusercontent.com/u/3663389?v=4" title="gkushang" width="80" height="80"></a>
310
+ <a href="https://github.com/tsuemura"><img src="https://avatars.githubusercontent.com/u/17092259?v=4" title="tsuemura" width="80" height="80"></a>
311
+ <a href="https://github.com/VikalpP"><img src="https://avatars.githubusercontent.com/u/11846339?v=4" title="VikalpP" width="80" height="80"></a>
312
+ <a href="https://github.com/BorisOsipov"><img src="https://avatars.githubusercontent.com/u/6514276?v=4" title="BorisOsipov" width="80" height="80"></a>
313
+ <a href="https://github.com/elaichenkov"><img src="https://avatars.githubusercontent.com/u/29764053?v=4" title="elaichenkov" width="80" height="80"></a>
314
+ <a href="https://github.com/nitschSB"><img src="https://avatars.githubusercontent.com/u/39341455?v=4" title="nitschSB" width="80" height="80"></a>
315
+ <a href="https://github.com/hubidu"><img src="https://avatars.githubusercontent.com/u/13134082?v=4" title="hubidu" width="80" height="80"></a>
316
+ <a href="https://github.com/jploskonka"><img src="https://avatars.githubusercontent.com/u/669483?v=4" title="jploskonka" width="80" height="80"></a>
317
+ <a href="https://github.com/maojunxyz"><img src="https://avatars.githubusercontent.com/u/28778042?v=4" title="maojunxyz" width="80" height="80"></a>
318
+ <a href="https://github.com/abhimanyupandian"><img src="https://avatars.githubusercontent.com/u/36107381?v=4" title="abhimanyupandian" width="80" height="80"></a>
319
+ <a href="https://github.com/martomo"><img src="https://avatars.githubusercontent.com/u/1850135?v=4" title="martomo" width="80" height="80"></a>
320
+ <a href="https://github.com/denis-sokolov"><img src="https://avatars.githubusercontent.com/u/113721?v=4" title="denis-sokolov" width="80" height="80"></a>
321
+ <a href="https://github.com/lennym"><img src="https://avatars.githubusercontent.com/u/117398?v=4" title="lennym" width="80" height="80"></a>
322
+ <a href="https://github.com/petehouston"><img src="https://avatars.githubusercontent.com/u/9006720?v=4" title="petehouston" width="80" height="80"></a>
323
+ <a href="https://github.com/Holorium"><img src="https://avatars.githubusercontent.com/u/10815542?v=4" title="Holorium" width="80" height="80"></a>
324
+ <a href="https://github.com/jancorvus"><img src="https://avatars.githubusercontent.com/u/67001310?v=4" title="jancorvus" width="80" height="80"></a>
325
+ <a href="https://github.com/ngraf"><img src="https://avatars.githubusercontent.com/u/7094389?v=4" title="ngraf" width="80" height="80"></a>
327
326
 
328
327
  [//]: contributor-faces
329
328
 
package/docs/advanced.md CHANGED
@@ -186,7 +186,7 @@ You can use this options for build your own [plugins](https://codecept.io/hooks/
186
186
  });
187
187
  ```
188
188
 
189
- ## Timeout <Badge text="Updated in 3.2" type="warning"/>
189
+ ## Timeout
190
190
 
191
191
  Tests can get stuck due to various reasons such as network connection issues, crashed browser, etc.
192
192
  This can make tests process hang. To prevent these situations timeouts can be used. Timeouts can be set explicitly for flaky parts of code, or implicitly in a config.
@@ -236,38 +236,62 @@ A timeout for a group of tests can be set on Feature level via options.
236
236
  Feature('flaky tests', { timeout: 30 })
237
237
  ```
238
238
 
239
- ### Sum Up
239
+ ### Timeout Confguration
240
240
 
241
- Let's list all available timeout options.
241
+ <Badge text="Updated in 3.4" type="warning"/>
242
242
 
243
- Timeouts can be set globally in config:
243
+ Timeout rules can be set globally via config.
244
+
245
+ To set a timeout for all running tests provide a **number of seconds** to `timeout` config option:
244
246
 
245
- ```js
246
- // in codecept.confg.js:
247
- { // ...
248
- timeout: 30, // limit all tests in all suites to 30 secs
249
-
250
- plugins: {
251
- stepTimeout: {
252
- enabled: true,
253
- timeout: 10, // limit all steps except waiters to 10 secs
254
- }
255
- }
256
- }
257
247
 
248
+ ```js
249
+ // inside codecept.conf.js or codecept.conf.ts
250
+ timeout: 30, // limit all tests in all suites to 30 secs
258
251
  ```
259
252
 
260
- or inside a test file:
253
+ It is possible to tune this configuration for a different groups of tests passing options as array and using `grep` option to filter tests:
261
254
 
262
255
  ```js
263
- // limit all tests in this suite to 10 secs
264
- Feature('tests with timeout', { timeout: 10 });
256
+ // inside codecept.conf.js or codecept.conf.ts
265
257
 
266
- // limit this test to 20 secs
267
- Scenario('a test with timeout', { timeout: 20 }, ({ I }) => {
268
- // limit step to 5 seconds
269
- I.limitTime(5).click('Link');
270
- });
258
+ timeout: [
259
+ 10, // default timeout is 10secs
260
+
261
+ // but increase timeout for slow tests
262
+ {
263
+ grep: '@slow',
264
+ Feature: 50
265
+ },
266
+ ]
267
+ ```
268
+
269
+ > ℹ️ `grep` value can be string or regexp
270
+
271
+ It is possible to set a timeout for Scenario or Feature:
272
+
273
+ ```js
274
+ // inside codecept.conf.js or codecept.conf.ts
275
+ timeout: [
276
+
277
+ // timeout for Feature with @slow in title
278
+ {
279
+ grep: '@slow',
280
+ Feature: 50
281
+ },
282
+
283
+ // timeout for Scenario with 'flaky0' .. `flaky1` in title
284
+ {
285
+ // regexp can be passed to grep
286
+ grep: /flaky[0-9]/,
287
+ Scenario: 10
288
+ },
289
+
290
+ // timeout for all suites
291
+ {
292
+ Feature: 20
293
+ }
294
+ ]
271
295
  ```
272
296
 
273
297
  Global timeouts will be overridden by explicit timeouts of a test or steps.
package/docs/basics.md CHANGED
@@ -345,7 +345,7 @@ If you face that error please make sure that all async functions are called with
345
345
 
346
346
  ## Running Tests
347
347
 
348
- To launch tests use the `run` command, and to execute tests in [multiple browsers](/advanced/#multiple-browsers-execution) or [multiple threads](/advanced/#parallel-execution) use the `run-multiple` command.
348
+ To launch tests use the `run` command, and to execute tests in [multiple threads](/advanced/parallel) using `run-workers` command.
349
349
 
350
350
  ### Level of Detail
351
351
 
@@ -394,7 +394,7 @@ It is recommended to [filter tests by tags](/advanced/#tags).
394
394
 
395
395
  ### Parallel Run
396
396
 
397
- Since CodeceptJS 2.3, you can run tests in parallel by using NodeJS workers. This feature requires NodeJS >= 11.6. Use `run-workers` command with the number of workers (threads) to split tests.
397
+ Tests can be executed in parallel mode by using [NodeJS workers](https://nodejs.org/api/worker_threads.html). Use `run-workers` command with the number of workers (threads) to split tests into different workers.
398
398
 
399
399
  ```
400
400
  npx codeceptjs run-workers 3
@@ -532,13 +532,55 @@ This can be configured in [screenshotOnFail Plugin](/plugins/#screenshotonfail)
532
532
 
533
533
  To see how the test was executed, use [stepByStepReport Plugin](/plugins/#stepbystepreport). It saves a screenshot of each passed step and shows them in a nice slideshow.
534
534
 
535
+ ## Before
536
+
537
+ Common preparation steps like opening a web page or logging in a user, can be placed in the `Before` or `Background` hooks:
538
+
539
+ ```js
540
+ Feature('CodeceptJS Demonstration');
541
+
542
+ Before(({ I }) => { // or Background
543
+ I.amOnPage('/documentation');
544
+ });
545
+
546
+ Scenario('test some forms', ({ I }) => {
547
+ I.click('Create User');
548
+ I.see('User is valid');
549
+ I.dontSeeInCurrentUrl('/documentation');
550
+ });
551
+
552
+ Scenario('test title', ({ I }) => {
553
+ I.seeInTitle('Example application');
554
+ });
555
+ ```
556
+
557
+ Same as `Before` you can use `After` to run teardown for each scenario.
558
+
559
+ ## BeforeSuite
560
+
561
+ If you need to run complex a setup before all tests and have to teardown this afterwards, you can use the `BeforeSuite` and `AfterSuite` functions.
562
+ `BeforeSuite` and `AfterSuite` have access to the `I` object, but `BeforeSuite/AfterSuite` don't have any access to the browser, because it's not running at this moment.
563
+ You can use them to execute handlers that will setup your environment. `BeforeSuite/AfterSuite` will work only for the file it was declared in (so you can declare different setups for files)
564
+
565
+ ```js
566
+ BeforeSuite(({ I }) => {
567
+ I.syncDown('testfolder');
568
+ });
569
+
570
+ AfterSuite(({ I }) => {
571
+ I.syncUp('testfolder');
572
+ I.clearDir('testfolder');
573
+ });
574
+ ```
575
+
535
576
  ## Retries
536
577
 
537
578
  ### Auto Retry
538
579
 
539
- You can auto-retry a failed step by enabling [retryFailedStep Plugin](/plugins/#retryfailedstep).
580
+ Each failed step is auto-retried by default via [retryFailedStep Plugin](/plugins/#retryfailedstep).
581
+ If this is not expected, this plugin can be disabled in a config.
540
582
 
541
- > **[retryFailedStep plugin](/plugins/#retryfailedstep) is enabled by default** for new setups
583
+ > **[retryFailedStep plugin](/plugins/#retryfailedstep) is enabled by default** incide global configuration
542
584
 
543
585
  ### Retry Step
544
586
 
@@ -608,69 +650,102 @@ Scenario('Really complex', { retries: 2 },({ I }) => {});
608
650
  This scenario will be restarted two times on a failure.
609
651
  Unlike retry step, there is no `when` condition supported for retries on a scenario level.
610
652
 
653
+ ### Retry Before <Badge text="Since 3.4" type="warning"/>
654
+
655
+ To retry `Before`, `BeforeSuite`, `After`, `AfterSuite` hooks, add corresponding option to a `Feature`:
656
+
657
+ * `retryBefore`
658
+ * `retryBeforeSuite`
659
+ * `retryAfter`
660
+ * `retryAfterSuite`
661
+
662
+ For instance, to retry Before hook 3 times:
663
+
664
+ ```js
665
+ Feature('this have a flaky Befure', { retryBefore: 3 })
666
+ ```
667
+
668
+ Multiple options of different values can be set at the same time
669
+
611
670
  ### Retry Feature
612
671
 
613
672
  To set this option for all scenarios in a file, add `retry` to a feature:
614
673
 
615
674
  ```js
616
675
  Feature('Complex JS Stuff').retry(3);
676
+ // or
677
+ Feature('Complex JS Stuff', { retries: 3 })
617
678
  ```
618
679
 
619
680
  Every Scenario inside this feature will be rerun 3 times.
620
681
  You can make an exception for a specific scenario by passing the `retries` option to a Scenario.
621
682
 
622
- ### Retry Run
623
-
624
- On the highest level of the "retry pyramid" there is an option to retry a complete run multiple times.
625
- Even this is the slowest option of all, it can be helpful to detect flaky tests.
683
+ ### Retry Configuration <Badge text="Since 3.4" type="warning"/>
626
684
 
627
- [`run-rerun`](https://codecept.io/commands/#run-rerun) command will restart the run multiple times to values you provide. You can set minimal and maximal number of restarts in configuration file.
685
+ It is possible to set retry rules globally via `retry` config option. The configuration is flexible and allows multiple formats.
686
+ The simplest config would be:
628
687
 
688
+ ```js
689
+ // inside codecept.conf.js
690
+ retry: 3
629
691
  ```
630
- npx codeceptjs run-rerun
631
- ```
632
-
633
692
 
634
- ## Before
693
+ This will enable Feature Retry for all executed feature, retrying failing tests 3 times.
635
694
 
636
- Common preparation steps like opening a web page or logging in a user, can be placed in the `Before` or `Background` hooks:
695
+ An object can be used to tune retries of a Before/After hook, Scenario or Feature
637
696
 
638
697
  ```js
639
- Feature('CodeceptJS Demonstration');
698
+ // inside codecept.conf.js
699
+ retry: {
700
+ Feature: ...,
701
+ Scenario: ...,
702
+ Before: ...,
703
+ BeforeSuite: ...,
704
+ After: ...,
705
+ AfterSuite: ...,
706
+ }
707
+ ```
640
708
 
641
- Before(({ I }) => { // or Background
642
- I.amOnPage('/documentation');
643
- });
709
+ Multiple retry configs can be added via array. To use different retry configs for different subset of tests use `grep` option inside a retry config:
710
+
711
+ ```js
712
+ // inside codecept.conf.js
713
+ retry: [
714
+ {
715
+ // enable this config only for flaky tests
716
+ grep: '@flaky',
717
+ Before: 3
718
+ Scenario: 3
719
+ },
720
+ {
721
+ // retry less when running slow tests
722
+ grep: '@slow'
723
+ Scenario: 1
724
+ Before: 1
725
+ }, {
726
+ // retry all BeforeSuite
727
+ BeforeSuite: 3
728
+ }
729
+ ]
730
+ ```
644
731
 
645
- Scenario('test some forms', ({ I }) => {
646
- I.click('Create User');
647
- I.see('User is valid');
648
- I.dontSeeInCurrentUrl('/documentation');
649
- });
732
+ When using `grep` with `Before`, `After`, `BeforeSuite`, `AfterSuite`, a suite title will be checked for included value.
650
733
 
651
- Scenario('test title', ({ I }) => {
652
- I.seeInTitle('Example application');
653
- });
654
- ```
734
+ > ℹ️ `grep` value can be string or regexp
655
735
 
656
- Same as `Before` you can use `After` to run teardown for each scenario.
736
+ Rules are applied in the order of array element, so the last option will override a previous one. Global retries config can be overridden in a file as described previously.
657
737
 
658
- ## BeforeSuite
738
+ ### Retry Run
659
739
 
660
- If you need to run complex a setup before all tests and have to teardown this afterwards, you can use the `BeforeSuite` and `AfterSuite` functions.
661
- `BeforeSuite` and `AfterSuite` have access to the `I` object, but `BeforeSuite/AfterSuite` don't have any access to the browser, because it's not running at this moment.
662
- You can use them to execute handlers that will setup your environment. `BeforeSuite/AfterSuite` will work only for the file it was declared in (so you can declare different setups for files)
740
+ On the highest level of the "retry pyramid" there is an option to retry a complete run multiple times.
741
+ Even this is the slowest option of all, it can be helpful to detect flaky tests.
663
742
 
664
- ```js
665
- BeforeSuite(({ I }) => {
666
- I.syncDown('testfolder');
667
- });
743
+ [`run-rerun`](https://codecept.io/commands/#run-rerun) command will restart the run multiple times to values you provide. You can set minimal and maximal number of restarts in configuration file.
668
744
 
669
- AfterSuite(({ I }) => {
670
- I.syncUp('testfolder');
671
- I.clearDir('testfolder');
672
- });
673
745
  ```
746
+ npx codeceptjs run-rerun
747
+ ```
748
+
674
749
 
675
750
  [Here are some ideas](https://github.com/codeceptjs/CodeceptJS/pull/231#issuecomment-249554933) on where to use BeforeSuite hooks.
676
751
 
package/docs/best.md CHANGED
@@ -74,7 +74,7 @@ When a project is growing and more and more tests are required, it's time to thi
74
74
  Here is a recommended strategy what to store where:
75
75
 
76
76
  * Move site-wide actions into an **Actor** file (`custom_steps.js` file). Such actions like `login`, using site-wide common controls, like drop-downs, rich text editors, calendars.
77
- * Move page-based actions and selectors into **Page Object**. All acitivities made on that page can go into methods of page object. If you test Single Page Application a PageObject should represent a screen of your application.
77
+ * Move page-based actions and selectors into **Page Object**. All activities made on that page can go into methods of page object. If you test Single Page Application a PageObject should represent a screen of your application.
78
78
  * When site-wide widgets are used, interactions with them should be placed in **Page Fragments**. This should be applied to global navigation, modals, widgets.
79
79
  * A custom action that requires some low-level driver access, should be placed into a **Helper**. For instance, database connections, complex mouse actions, email testing, filesystem, services access.
80
80
 
@@ -215,7 +215,7 @@ include: {
215
215
  * When you need to customize access to API and go beyond what ApiDataFactory provides, implement DAO:
216
216
 
217
217
  ```js
218
- const faker = require('@faker-js/faker');
218
+ const { faker } = require('@faker-js/faker');
219
219
  const { I } = inject();
220
220
  const { output } = require('codeceptjs');
221
221
 
@@ -46,8 +46,8 @@ const REST = require('./REST');
46
46
  * ```js
47
47
  * // tests/factories/posts.js
48
48
  *
49
- * const Factory = require('rosie').Factory;
50
- * const faker = require('@faker-js/faker');
49
+ * const { Factory } = require('rosie');
50
+ * const { faker } = require('@faker-js/faker');
51
51
  *
52
52
  * module.exports = new Factory()
53
53
  * // no need to set id, it will be set by REST API
@@ -262,8 +262,8 @@ class ApiDataFactory extends Helper {
262
262
  * ```
263
263
  *
264
264
  * @param {*} factory factory to use
265
- * @param {*} params predefined parameters
266
- * @param {*} options options for programmatically generate the attributes
265
+ * @param {*} [params] predefined parameters
266
+ * @param {*} [options] options for programmatically generate the attributes
267
267
  * @returns {Promise<*>}
268
268
  */
269
269
  have(factory, params, options) {
@@ -288,8 +288,8 @@ class ApiDataFactory extends Helper {
288
288
  *
289
289
  * @param {*} factory
290
290
  * @param {*} times
291
- * @param {*} params
292
- * @param {*} options
291
+ * @param {*} [params]
292
+ * @param {*} [options]
293
293
  */
294
294
  haveMultiple(factory, times, params, options) {
295
295
  const promises = [];
@@ -1,5 +1,4 @@
1
1
  let webdriverio;
2
- let wdioV4;
3
2
 
4
3
  const fs = require('fs');
5
4
  const axios = require('axios').default;
@@ -131,6 +130,7 @@ class Appium extends Webdriver {
131
130
  * @augments WebDriver
132
131
  */
133
132
 
133
+ // @ts-ignore
134
134
  constructor(config) {
135
135
  super(config);
136
136
 
@@ -138,7 +138,6 @@ class Appium extends Webdriver {
138
138
  this.axios = axios.create();
139
139
 
140
140
  webdriverio = require('webdriverio');
141
- (!webdriverio.VERSION || webdriverio.VERSION.indexOf('4') !== 0) ? wdioV4 = false : wdioV4 = true;
142
141
  }
143
142
 
144
143
  _validateConfig(config) {
@@ -516,10 +515,6 @@ class Appium extends Webdriver {
516
515
  async removeApp(appId, bundleId) {
517
516
  onlyForApps.call(this, supportedPlatform.android);
518
517
 
519
- if (wdioV4) {
520
- return this.browser.removeApp(bundleId);
521
- }
522
-
523
518
  return this.axios({
524
519
  method: 'post',
525
520
  url: `${this._buildAppiumEndpoint()}/session/${this.browser.sessionId}/appium/device/remove_app`,
@@ -610,19 +605,13 @@ class Appium extends Webdriver {
610
605
  */
611
606
  async seeOrientationIs(orientation) {
612
607
  onlyForApps.call(this);
613
- let currentOrientation;
614
-
615
- if (wdioV4) {
616
- const res = await this.browser.orientation();
617
- currentOrientation = res;
618
- }
619
608
 
620
609
  const res = await this.axios({
621
610
  method: 'get',
622
611
  url: `${this._buildAppiumEndpoint()}/session/${this.browser.sessionId}/orientation`,
623
612
  });
624
613
 
625
- currentOrientation = res.data.value;
614
+ const currentOrientation = res.data.value;
626
615
  return truth('orientation', `to be ${orientation}`).assert(currentOrientation === orientation);
627
616
  }
628
617
 
@@ -640,9 +629,6 @@ class Appium extends Webdriver {
640
629
  */
641
630
  async setOrientation(orientation) {
642
631
  onlyForApps.call(this);
643
- if (wdioV4) {
644
- return this.browser.setOrientation(orientation);
645
- }
646
632
 
647
633
  return this.axios({
648
634
  method: 'post',
@@ -916,9 +902,6 @@ class Appium extends Webdriver {
916
902
  */
917
903
  async sendDeviceKeyEvent(keyValue) {
918
904
  onlyForApps.call(this, supportedPlatform.android);
919
- if (wdioV4) {
920
- return this.browser.sendKeyEvent(keyValue);
921
- }
922
905
  return this.browser.pressKeyCode(keyValue);
923
906
  }
924
907
 
@@ -71,10 +71,10 @@ class FileSystem extends Helper {
71
71
  }
72
72
 
73
73
  /**
74
- * Waits for file to be present in current directory.
74
+ * Waits for the file to be present in the current directory.
75
75
  *
76
76
  * ```js
77
- * I.handleDownloads();
77
+ * I.handleDownloads('downloads/largeFilesName.txt');
78
78
  * I.click('Download large File');
79
79
  * I.amInPath('output/downloads');
80
80
  * I.waitForFile('largeFilesName.txt', 10); // wait 10 seconds for file
@@ -46,8 +46,8 @@ const GraphQL = require('./GraphQL');
46
46
  * ```js
47
47
  * // tests/factories/users.js
48
48
  *
49
- * const Factory = require('rosie').Factory;
50
- * const faker = require('@faker-js/faker');
49
+ * const { Factory } = require('rosie').Factory;
50
+ * const { faker } = require('@faker-js/faker');
51
51
  *
52
52
  * // Used with a constructor function passed to Factory, so that the final build
53
53
  * // object matches the necessary pattern to be sent as the variables object.
@@ -66,6 +66,7 @@ const pathSeparator = path.sep;
66
66
  * @prop {boolean} [video=false] - enables video recording for failed tests; videos are saved into `output/videos` folder
67
67
  * @prop {boolean} [keepVideoForPassedTests=false] - save videos for passed tests; videos are saved into `output/videos` folder
68
68
  * @prop {boolean} [trace=false] - record [tracing information](https://playwright.dev/docs/trace-viewer) with screenshots and snapshots.
69
+ * @prop {boolean} [keepTraceForPassedTests=false] - save trace for passed tests.
69
70
  * @prop {boolean} [fullPageScreenshots=false] - make full page screenshots on failure.
70
71
  * @prop {boolean} [uniqueScreenshotNames=false] - option to prevent screenshot override if you have scenarios with the same name in different suites.
71
72
  * @prop {boolean} [keepBrowserState=false] - keep browser state between tests when `restart` is set to 'session'.
@@ -1413,7 +1414,7 @@ class Playwright extends Helper {
1413
1414
  *
1414
1415
  * ```
1415
1416
  *
1416
- * @param {string} [fileName] set filename for downloaded file
1417
+ * @param {string} fileName set filename for downloaded file
1417
1418
  * @return {Promise<void>}
1418
1419
  */
1419
1420
  async handleDownloads(fileName) {
@@ -3968,7 +3969,7 @@ async function refreshContextSession() {
3968
3969
 
3969
3970
  async function saveVideoForPage(page, name) {
3970
3971
  if (!page.video()) return null;
3971
- const fileName = `${global.output_dir}${pathSeparator}videos${pathSeparator}${Date.now()}_${clearString(name).slice(0, 245)}.webm`;
3972
+ const fileName = `${`${global.output_dir}${pathSeparator}videos${pathSeparator}${Date.now()}_${clearString(name)}`.slice(0, 245)}.webm`;
3972
3973
  page.video().saveAs(fileName).then(() => {
3973
3974
  if (!page) return;
3974
3975
  page.video().delete().catch(e => {});