codeceptjs 3.3.0-beta.5 → 3.3.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 (139) hide show
  1. package/CHANGELOG.md +50 -1
  2. package/README.md +6 -1
  3. package/docs/api.md +45 -30
  4. package/docs/bdd.md +1 -0
  5. package/docs/best.md +1 -1
  6. package/docs/build/ApiDataFactory.js +4 -3
  7. package/docs/build/Appium.js +53 -48
  8. package/docs/build/GraphQL.js +4 -2
  9. package/docs/build/GraphQLDataFactory.js +3 -3
  10. package/docs/build/JSONResponse.js +1 -1
  11. package/docs/build/Nightmare.js +101 -72
  12. package/docs/build/Playwright.js +166 -113
  13. package/docs/build/Protractor.js +72 -34
  14. package/docs/build/Puppeteer.js +143 -100
  15. package/docs/build/REST.js +5 -2
  16. package/docs/build/TestCafe.js +97 -66
  17. package/docs/build/WebDriver.js +183 -135
  18. package/docs/changelog.md +99 -0
  19. package/docs/custom-helpers.md +1 -1
  20. package/docs/data.md +2 -2
  21. package/docs/email.md +5 -0
  22. package/docs/helpers/ApiDataFactory.md +7 -3
  23. package/docs/helpers/Appium.md +217 -175
  24. package/docs/helpers/GraphQL.md +6 -0
  25. package/docs/helpers/GraphQLDataFactory.md +3 -3
  26. package/docs/helpers/JSONResponse.md +1 -1
  27. package/docs/helpers/MockRequest.md +8 -6
  28. package/docs/helpers/Nightmare.md +98 -45
  29. package/docs/helpers/Playwright.md +151 -59
  30. package/docs/helpers/Puppeteer.md +103 -26
  31. package/docs/helpers/REST.md +1 -1
  32. package/docs/helpers/TestCafe.md +77 -22
  33. package/docs/helpers/WebDriver.md +150 -62
  34. package/docs/index.md +1 -1
  35. package/docs/locators.md +1 -1
  36. package/docs/videos.md +2 -2
  37. package/docs/webapi/amOnPage.mustache +2 -1
  38. package/docs/webapi/appendField.mustache +2 -1
  39. package/docs/webapi/attachFile.mustache +2 -1
  40. package/docs/webapi/checkOption.mustache +2 -1
  41. package/docs/webapi/clearCookie.mustache +2 -1
  42. package/docs/webapi/clearField.mustache +1 -0
  43. package/docs/webapi/click.mustache +2 -1
  44. package/docs/webapi/clickLink.mustache +2 -1
  45. package/docs/webapi/closeCurrentTab.mustache +6 -4
  46. package/docs/webapi/closeOtherTabs.mustache +6 -4
  47. package/docs/webapi/dontSee.mustache +1 -0
  48. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +1 -0
  49. package/docs/webapi/dontSeeCookie.mustache +2 -1
  50. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +2 -1
  51. package/docs/webapi/dontSeeElement.mustache +2 -1
  52. package/docs/webapi/dontSeeElementInDOM.mustache +2 -1
  53. package/docs/webapi/dontSeeInCurrentUrl.mustache +2 -1
  54. package/docs/webapi/dontSeeInField.mustache +2 -1
  55. package/docs/webapi/dontSeeInSource.mustache +1 -0
  56. package/docs/webapi/dontSeeInTitle.mustache +2 -1
  57. package/docs/webapi/doubleClick.mustache +1 -0
  58. package/docs/webapi/downloadFile.mustache +2 -1
  59. package/docs/webapi/dragAndDrop.mustache +1 -0
  60. package/docs/webapi/dragSlider.mustache +2 -1
  61. package/docs/webapi/executeAsyncScript.mustache +1 -1
  62. package/docs/webapi/executeScript.mustache +1 -1
  63. package/docs/webapi/fillField.mustache +1 -0
  64. package/docs/webapi/forceClick.mustache +1 -0
  65. package/docs/webapi/forceRightClick.mustache +1 -0
  66. package/docs/webapi/grabDataFromPerformanceTiming.mustache +2 -1
  67. package/docs/webapi/moveCursorTo.mustache +1 -0
  68. package/docs/webapi/openNewTab.mustache +6 -4
  69. package/docs/webapi/pressKey.mustache +2 -1
  70. package/docs/webapi/pressKeyDown.mustache +1 -0
  71. package/docs/webapi/pressKeyUp.mustache +1 -0
  72. package/docs/webapi/pressKeyWithKeyNormalization.mustache +1 -0
  73. package/docs/webapi/refreshPage.mustache +1 -0
  74. package/docs/webapi/resizeWindow.mustache +2 -1
  75. package/docs/webapi/rightClick.mustache +1 -0
  76. package/docs/webapi/saveElementScreenshot.mustache +1 -0
  77. package/docs/webapi/saveScreenshot.mustache +2 -1
  78. package/docs/webapi/say.mustache +2 -1
  79. package/docs/webapi/scrollIntoView.mustache +1 -0
  80. package/docs/webapi/scrollPageToBottom.mustache +1 -0
  81. package/docs/webapi/scrollPageToTop.mustache +1 -0
  82. package/docs/webapi/scrollTo.mustache +2 -1
  83. package/docs/webapi/see.mustache +2 -1
  84. package/docs/webapi/seeAttributesOnElements.mustache +2 -1
  85. package/docs/webapi/seeCheckboxIsChecked.mustache +1 -0
  86. package/docs/webapi/seeCookie.mustache +1 -0
  87. package/docs/webapi/seeCssPropertiesOnElements.mustache +2 -1
  88. package/docs/webapi/seeCurrentUrlEquals.mustache +2 -1
  89. package/docs/webapi/seeElement.mustache +2 -1
  90. package/docs/webapi/seeElementInDOM.mustache +1 -0
  91. package/docs/webapi/seeInCurrentUrl.mustache +2 -1
  92. package/docs/webapi/seeInField.mustache +1 -0
  93. package/docs/webapi/seeInPopup.mustache +1 -0
  94. package/docs/webapi/seeInSource.mustache +2 -1
  95. package/docs/webapi/seeInTitle.mustache +2 -1
  96. package/docs/webapi/seeNumberOfElements.mustache +1 -0
  97. package/docs/webapi/seeNumberOfVisibleElements.mustache +1 -0
  98. package/docs/webapi/seeTextEquals.mustache +2 -1
  99. package/docs/webapi/seeTitleEquals.mustache +6 -5
  100. package/docs/webapi/selectOption.mustache +1 -0
  101. package/docs/webapi/setCookie.mustache +1 -0
  102. package/docs/webapi/setGeoLocation.mustache +1 -0
  103. package/docs/webapi/switchTo.mustache +2 -1
  104. package/docs/webapi/switchToNextTab.mustache +8 -7
  105. package/docs/webapi/switchToPreviousTab.mustache +8 -7
  106. package/docs/webapi/type.mustache +1 -0
  107. package/docs/webapi/uncheckOption.mustache +2 -1
  108. package/docs/webapi/wait.mustache +2 -1
  109. package/docs/webapi/waitForClickable.mustache +2 -1
  110. package/docs/webapi/waitForDetached.mustache +2 -1
  111. package/docs/webapi/waitForElement.mustache +2 -1
  112. package/docs/webapi/waitForEnabled.mustache +2 -1
  113. package/docs/webapi/waitForFunction.mustache +1 -0
  114. package/docs/webapi/waitForInvisible.mustache +2 -1
  115. package/docs/webapi/waitForText.mustache +2 -1
  116. package/docs/webapi/waitForValue.mustache +1 -0
  117. package/docs/webapi/waitForVisible.mustache +1 -0
  118. package/docs/webapi/waitInUrl.mustache +2 -1
  119. package/docs/webapi/waitNumberOfVisibleElements.mustache +2 -1
  120. package/docs/webapi/waitToHide.mustache +2 -1
  121. package/docs/webapi/waitUrlEquals.mustache +2 -1
  122. package/lib/command/definitions.js +9 -0
  123. package/lib/command/run.js +2 -2
  124. package/lib/command/workers/runTests.js +40 -0
  125. package/lib/helper/ApiDataFactory.js +4 -3
  126. package/lib/helper/Appium.js +2 -7
  127. package/lib/helper/GraphQL.js +4 -2
  128. package/lib/helper/GraphQLDataFactory.js +3 -3
  129. package/lib/helper/JSONResponse.js +1 -1
  130. package/lib/helper/Playwright.js +28 -17
  131. package/lib/helper/REST.js +5 -2
  132. package/lib/helper/WebDriver.js +4 -0
  133. package/lib/interfaces/bdd.js +5 -0
  134. package/lib/listener/steps.js +1 -0
  135. package/lib/plugin/fakerTransform.js +1 -1
  136. package/lib/plugin/stepByStepReport.js +8 -6
  137. package/lib/workers.js +12 -0
  138. package/package.json +3 -3
  139. package/typings/types.d.ts +578 -109
@@ -4,4 +4,5 @@ Pauses execution for a number of seconds.
4
4
  I.wait(2); // wait 2 secs
5
5
  ```
6
6
 
7
- @param {number} sec number of second to wait.
7
+ @param {number} sec number of second to wait.
8
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -7,4 +7,5 @@ I.waitForClickable('.btn.continue', 5); // wait for 5 secs
7
7
  ```
8
8
 
9
9
  @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
10
- @param {number} [sec] (optional, `1` by default) time in seconds to wait
10
+ @param {number} [sec] (optional, `1` by default) time in seconds to wait
11
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -6,4 +6,5 @@ I.waitForDetached('#popup');
6
6
  ```
7
7
 
8
8
  @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
9
- @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
9
+ @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
10
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -7,4 +7,5 @@ I.waitForElement('.btn.continue', 5); // wait for 5 secs
7
7
  ```
8
8
 
9
9
  @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
10
- @param {number} [sec] (optional, `1` by default) time in seconds to wait
10
+ @param {number} [sec] (optional, `1` by default) time in seconds to wait
11
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -2,4 +2,5 @@ Waits for element to become enabled (by default waits for 1sec).
2
2
  Element can be located by CSS or XPath.
3
3
 
4
4
  @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
5
- @param {number} [sec=1] (optional) time in seconds to wait, 1 by default.
5
+ @param {number} [sec=1] (optional) time in seconds to wait, 1 by default.
6
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -14,3 +14,4 @@ I.waitForFunction((count) => window.requests == count, [3], 5) // pass args and
14
14
  @param {string|function} fn to be executed in browser context.
15
15
  @param {any[]|number} [argsOrSec] (optional, `1` by default) arguments for function or seconds.
16
16
  @param {number} [sec] (optional, `1` by default) time in seconds to wait
17
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -6,4 +6,5 @@ I.waitForInvisible('#popup');
6
6
  ```
7
7
 
8
8
  @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
9
- @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
9
+ @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
10
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -9,4 +9,5 @@ I.waitForText('Thank you, form has been submitted', 5, '#modal');
9
9
 
10
10
  @param {string }text to wait for.
11
11
  @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
12
- @param {CodeceptJS.LocatorOrString} [context] (optional) element located by CSS|XPath|strict locator.
12
+ @param {CodeceptJS.LocatorOrString} [context] (optional) element located by CSS|XPath|strict locator.
13
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -7,3 +7,4 @@ I.waitForValue('//input', "GoodValue");
7
7
  @param {LocatorOrString} field input field.
8
8
  @param {string }value expected value.
9
9
  @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
10
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -7,3 +7,4 @@ I.waitForVisible('#popup');
7
7
 
8
8
  @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
9
9
  @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
10
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -5,4 +5,5 @@ I.waitInUrl('/info', 2);
5
5
  ```
6
6
 
7
7
  @param {string} urlPart value to check.
8
- @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
8
+ @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
9
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -6,4 +6,5 @@ I.waitNumberOfVisibleElements('a', 3);
6
6
 
7
7
  @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
8
8
  @param {number} num number of elements.
9
- @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
9
+ @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
10
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -6,4 +6,5 @@ I.waitToHide('#popup');
6
6
  ```
7
7
 
8
8
  @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
9
- @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
9
+ @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
10
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -6,4 +6,5 @@ I.waitUrlEquals('http://127.0.0.1:8000/info');
6
6
  ```
7
7
 
8
8
  @param {string} urlPart value to check.
9
- @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
9
+ @param {number} [sec=1] (optional, `1` by default) time in seconds to wait
10
+ [!] returns a _promise_ which is synchronized internally by recorder
@@ -146,10 +146,19 @@ module.exports = function (genPath, options) {
146
146
  }
147
147
  }
148
148
 
149
+ let autoLogin;
150
+ if (config.plugins.autoLogin) {
151
+ autoLogin = config.plugins.autoLogin.inject;
152
+ }
153
+
149
154
  const supportObject = new Map();
150
155
  supportObject.set('I', 'I');
151
156
  supportObject.set('current', 'any');
152
157
 
158
+ if (autoLogin) {
159
+ supportObject.set(autoLogin, 'any');
160
+ }
161
+
153
162
  if (customHelpers.length > 0) {
154
163
  hasCustomHelper = true;
155
164
  }
@@ -23,8 +23,8 @@ module.exports = async function (test, options) {
23
23
  try {
24
24
  codecept.init(testRoot);
25
25
  await codecept.bootstrap();
26
- codecept.loadTests();
27
- await codecept.run(test);
26
+ codecept.loadTests(test);
27
+ await codecept.run();
28
28
  } catch (err) {
29
29
  printError(err);
30
30
  process.exitCode = 1;
@@ -115,6 +115,8 @@ function initializeListeners() {
115
115
  }
116
116
 
117
117
  return {
118
+ opts: test.opts || {},
119
+ tags: test.tags || [],
118
120
  id: test.id,
119
121
  workerIndex,
120
122
  retries: test._retries,
@@ -126,6 +128,38 @@ function initializeListeners() {
126
128
  };
127
129
  }
128
130
 
131
+ function simplifyStep(step, err = null) {
132
+ step = { ...step };
133
+
134
+ if (step.startTime && !step.duration) {
135
+ const end = new Date();
136
+ step.duration = end - step.startTime;
137
+ }
138
+
139
+ if (step.err) {
140
+ err = simplifyError(step.err);
141
+ step.status = 'failed';
142
+ } else if (err) {
143
+ err = simplifyError(err);
144
+ step.status = 'failed';
145
+ }
146
+
147
+ const parent = {};
148
+ if (step.metaStep) {
149
+ parent.title = step.metaStep.actor;
150
+ }
151
+ return {
152
+ opts: step.opts || {},
153
+ workerIndex,
154
+ title: step.name,
155
+ status: step.status,
156
+ duration: step.duration || 0,
157
+ err,
158
+ parent,
159
+ test: simplifyTest(step.test),
160
+ };
161
+ }
162
+
129
163
  collectStats();
130
164
  // suite
131
165
  event.dispatcher.on(event.suite.before, suite => sendToParentThread({ event: event.suite.before, workerIndex, data: simplifyTest(suite) }));
@@ -144,6 +178,12 @@ function initializeListeners() {
144
178
  event.dispatcher.on(event.test.started, test => sendToParentThread({ event: event.test.started, workerIndex, data: simplifyTest(test) }));
145
179
  event.dispatcher.on(event.test.skipped, test => sendToParentThread({ event: event.test.skipped, workerIndex, data: simplifyTest(test) }));
146
180
 
181
+ // steps
182
+ event.dispatcher.on(event.step.finished, step => sendToParentThread({ event: event.step.finished, workerIndex, data: simplifyStep(step) }));
183
+ event.dispatcher.on(event.step.started, step => sendToParentThread({ event: event.step.started, workerIndex, data: simplifyStep(step) }));
184
+ event.dispatcher.on(event.step.passed, step => sendToParentThread({ event: event.step.passed, workerIndex, data: simplifyStep(step) }));
185
+ event.dispatcher.on(event.step.failed, step => sendToParentThread({ event: event.step.failed, workerIndex, data: simplifyStep(step) }));
186
+
147
187
  event.dispatcher.on(event.hook.failed, (test, err) => sendToParentThread({ event: event.hook.failed, workerIndex, data: simplifyTest(test, err) }));
148
188
  event.dispatcher.on(event.hook.passed, (test, err) => sendToParentThread({ event: event.hook.passed, workerIndex, data: simplifyTest(test, err) }));
149
189
  event.dispatcher.on(event.all.failures, (data) => sendToParentThread({ event: event.all.failures, workerIndex, data }));
@@ -36,7 +36,7 @@ const REST = require('./REST');
36
36
  * Install [Rosie](https://github.com/rosiejs/rosie) and [Faker](https://www.npmjs.com/package/faker) libraries.
37
37
  *
38
38
  * ```sh
39
- * npm i rosie faker --save-dev
39
+ * npm i rosie @faker-js/faker --save-dev
40
40
  * ```
41
41
  *
42
42
  * Create a factory file for a resource.
@@ -46,8 +46,8 @@ const REST = require('./REST');
46
46
  * ```js
47
47
  * // tests/factories/posts.js
48
48
  *
49
- * var Factory = require('rosie').Factory;
50
- * var faker = require('faker');
49
+ * const Factory = require('rosie').Factory;
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
@@ -264,6 +264,7 @@ class ApiDataFactory extends Helper {
264
264
  * @param {*} factory factory to use
265
265
  * @param {*} params predefined parameters
266
266
  * @param {*} options options for programmatically generate the attributes
267
+ * @returns {Promise<*>}
267
268
  */
268
269
  have(factory, params, options) {
269
270
  const item = this._createItem(factory, params, options);
@@ -124,6 +124,7 @@ const webRoot = 'body';
124
124
  class Appium extends Webdriver {
125
125
  /**
126
126
  * Appium Special Methods for Mobile only
127
+ * @augments WebDriver
127
128
  */
128
129
 
129
130
  constructor(config) {
@@ -331,7 +332,6 @@ class Appium extends Webdriver {
331
332
  *
332
333
  * @param {*} caps
333
334
  * @param {*} fn
334
- * @return {Promise<any>}
335
335
  */
336
336
  async runOnIOS(caps, fn) {
337
337
  if (this.platform !== 'ios') return;
@@ -374,7 +374,6 @@ class Appium extends Webdriver {
374
374
  *
375
375
  * @param {*} caps
376
376
  * @param {*} fn
377
- * @return {Promise<any>}
378
377
  */
379
378
  async runOnAndroid(caps, fn) {
380
379
  if (this.platform !== 'android') return;
@@ -395,7 +394,6 @@ class Appium extends Webdriver {
395
394
  * ```
396
395
  *
397
396
  * @param {*} fn
398
- * @return {Promise<any>}
399
397
  */
400
398
  /* eslint-disable */
401
399
  async runInWeb(fn) {
@@ -599,7 +597,6 @@ class Appium extends Webdriver {
599
597
  * ```
600
598
  *
601
599
  * @param {'LANDSCAPE'|'PORTRAIT'} orientation LANDSCAPE or PORTRAIT
602
- * @return {Promise<any>}
603
600
  *
604
601
  * Appium: support Android and iOS
605
602
  */
@@ -728,7 +725,6 @@ class Appium extends Webdriver {
728
725
  * Switch to the specified context.
729
726
  *
730
727
  * @param {*} context the context to switch to
731
-
732
728
  */
733
729
  async _switchToContext(context) {
734
730
  return this.browser.switchContext(context);
@@ -774,7 +770,7 @@ class Appium extends Webdriver {
774
770
  * // or set context explicitly
775
771
  * I.switchToNative('SOME_OTHER_CONTEXT');
776
772
  * ```
777
- * @param {*} context
773
+ * @param {*} [context]
778
774
  * @return {Promise<void>}
779
775
  */
780
776
  async switchToNative(context = null) {
@@ -834,7 +830,6 @@ class Appium extends Webdriver {
834
830
  * ```
835
831
  *
836
832
  * @param {object} settings object
837
- * @return {Promise<any>}
838
833
  *
839
834
  * Appium: support Android and iOS
840
835
  */
@@ -112,15 +112,15 @@ class GraphQL extends Helper {
112
112
  *
113
113
  * @param {object} operation
114
114
  * @param {object} headers
115
+ * @return {object} graphQLRequest
115
116
  */
116
117
  _prepareGraphQLRequest(operation, headers) {
117
- const request = {
118
+ return {
118
119
  baseURL: this.options.endpoint,
119
120
  method: 'POST',
120
121
  data: operation,
121
122
  headers,
122
123
  };
123
- return request;
124
124
  }
125
125
 
126
126
  /**
@@ -142,6 +142,7 @@ class GraphQL extends Helper {
142
142
  * @param {object} variables that may go along with the query
143
143
  * @param {object} options are additional query options
144
144
  * @param {object} headers
145
+ * @return Promise<any>
145
146
  */
146
147
  async sendQuery(query, variables, options = {}, headers = {}) {
147
148
  if (typeof query !== 'string') {
@@ -181,6 +182,7 @@ class GraphQL extends Helper {
181
182
  * @param {object} variables that may go along with the mutation
182
183
  * @param {object} options are additional query options
183
184
  * @param {object} headers
185
+ * @return Promise<any>
184
186
  */
185
187
  async sendMutation(mutation, variables, options = {}, headers = {}) {
186
188
  if (typeof mutation !== 'string') {
@@ -36,7 +36,7 @@ const GraphQL = require('./GraphQL');
36
36
  * Install [Rosie](https://github.com/rosiejs/rosie) and [Faker](https://www.npmjs.com/package/faker) libraries.
37
37
  *
38
38
  * ```sh
39
- * npm i rosie faker --save-dev
39
+ * npm i rosie @faker-js/faker --save-dev
40
40
  * ```
41
41
  *
42
42
  * Create a factory file for a resource.
@@ -46,8 +46,8 @@ const GraphQL = require('./GraphQL');
46
46
  * ```js
47
47
  * // tests/factories/users.js
48
48
  *
49
- * var Factory = require('rosie').Factory;
50
- * var faker = require('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.
@@ -218,7 +218,7 @@ class JSONResponse extends Helper {
218
218
  * Use it to perform custom checks of response data
219
219
  *
220
220
  * ```js
221
- * I.seeResponseValidByCallback({ data, status, expect } => {
221
+ * I.seeResponseValidByCallback(({ data, status, expect }) => {
222
222
  * expect(status).to.eql(200);
223
223
  * expect(data).keys.to.include(['user', 'company']);
224
224
  * });
@@ -92,6 +92,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
92
92
  * * `waitForTimeout`: (optional) default wait* timeout in ms. Default: 1000.
93
93
  * * `basicAuth`: (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
94
94
  * * `windowSize`: (optional) default window size. Set a dimension like `640x480`.
95
+ * * `colorScheme`: (optional) default color scheme. Possible values: `dark` | `light` | `no-preference`.
95
96
  * * `userAgent`: (optional) user-agent string.
96
97
  * * `locale`: (optional) locale string. Example: 'en-GB', 'de-DE', 'fr-FR', ...
97
98
  * * `manualStart`: (optional, default: false) - do not start browser before a test, start it manually inside a helper with `this.helpers["Playwright"]._startBrowser()`.
@@ -212,7 +213,7 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
212
213
  * }
213
214
  * ```
214
215
  *
215
- * #### Example #7: Launch test with a specifc user locale
216
+ * #### Example #7: Launch test with a specific user locale
216
217
  *
217
218
  * ```js
218
219
  * {
@@ -225,6 +226,19 @@ const { createValueEngine, createDisabledEngine } = require('./extras/Playwright
225
226
  * }
226
227
  * ```
227
228
  *
229
+ * * #### Example #8: Launch test with a specific color scheme
230
+ *
231
+ * ```js
232
+ * {
233
+ * helpers: {
234
+ * Playwright : {
235
+ * url: "http://localhost",
236
+ * colorScheme: "dark",
237
+ * }
238
+ * }
239
+ * }
240
+ * ```
241
+ *
228
242
  * Note: When connecting to remote browser `show` and specific `chrome` options (e.g. `headless` or `devtools`) are ignored.
229
243
  *
230
244
  * ## Access From Helpers
@@ -273,7 +287,7 @@ class Playwright extends Helper {
273
287
  waitForAction: 100,
274
288
  waitForTimeout: 1000,
275
289
  pressKeyDelay: 10,
276
- timeout: 1000,
290
+ timeout: 5000,
277
291
  fullPageScreenshots: false,
278
292
  disableScreenshots: false,
279
293
  ignoreLog: ['warning', 'log'],
@@ -411,6 +425,7 @@ class Playwright extends Helper {
411
425
  if (this.storageState) contextOptions.storageState = this.storageState;
412
426
  if (this.options.userAgent) contextOptions.userAgent = this.options.userAgent;
413
427
  if (this.options.locale) contextOptions.locale = this.options.locale;
428
+ if (this.options.colorScheme) contextOptions.colorScheme = this.options.colorScheme;
414
429
  if (!this.browserContext || !restartsSession()) {
415
430
  this.browserContext = await this.browser.newContext(contextOptions); // Adding the HTTPSError ignore in the context so that we can ignore those errors
416
431
  }
@@ -538,7 +553,7 @@ class Playwright extends Helper {
538
553
  * ```
539
554
  *
540
555
  * @param {string} description used to show in logs.
541
- * @param {function} fn async function that executed with Playwright helper as argument
556
+ * @param {function} fn async function that executed with Playwright helper as argumen
542
557
  */
543
558
  usePlaywrightTo(description, fn) {
544
559
  return this._useTo(...arguments);
@@ -851,7 +866,7 @@ class Playwright extends Helper {
851
866
  /**
852
867
  * {{> dragAndDrop }}
853
868
  *
854
- * [Additional options](https://playwright.dev/docs/api/class-page#page-drag-and-drop) can be passed as 3rd argument.
869
+ * @param {any} [options] [Additional options](https://playwright.dev/docs/api/class-page#page-drag-and-drop) can be passed as 3rd argument.
855
870
  *
856
871
  * ```js
857
872
  * // specify coordinates for source position
@@ -886,7 +901,7 @@ class Playwright extends Helper {
886
901
  /**
887
902
  * {{> scrollPageToBottom }}
888
903
  */
889
- scrollPageToBottom() {
904
+ async scrollPageToBottom() {
890
905
  return this.executeScript(() => {
891
906
  const body = document.body;
892
907
  const html = document.documentElement;
@@ -972,8 +987,6 @@ class Playwright extends Helper {
972
987
  * ```js
973
988
  * const elements = await this.helpers['Playwright']._locate({name: 'password'});
974
989
  * ```
975
- *
976
- *
977
990
  */
978
991
  async _locate(locator) {
979
992
  const context = await this.context || await this._getContext();
@@ -1186,6 +1199,7 @@ class Playwright extends Helper {
1186
1199
  * ```
1187
1200
  *
1188
1201
  * @param {string} [fileName] set filename for downloaded file
1202
+ * @return {Promise<void>}
1189
1203
  */
1190
1204
  async handleDownloads(fileName = 'downloads') {
1191
1205
  this.page.waitForEvent('download').then(async (download) => {
@@ -1204,7 +1218,7 @@ class Playwright extends Helper {
1204
1218
  /**
1205
1219
  * {{> click }}
1206
1220
  *
1207
- * [Additional options](https://playwright.dev/docs/api/class-page#page-click) for click available as 3rd argument.
1221
+ * @param {any} [opts] [Additional options](https://playwright.dev/docs/api/class-page#page-click) for click available as 3rd argument.
1208
1222
  *
1209
1223
  * Examples:
1210
1224
  *
@@ -1669,7 +1683,6 @@ class Playwright extends Helper {
1669
1683
  *
1670
1684
  * @param {string|function} fn function to be executed in browser context.
1671
1685
  * @param {any} [arg] optional argument to pass to the function
1672
- * @return {Promise<any>}
1673
1686
  */
1674
1687
  async executeScript(fn, arg) {
1675
1688
  let context = this.page;
@@ -1992,7 +2005,7 @@ class Playwright extends Helper {
1992
2005
  test.artifacts = {};
1993
2006
  }
1994
2007
 
1995
- if (this.options.recordVideo && this.page.video()) {
2008
+ if (this.options.recordVideo && this.page && this.page.video()) {
1996
2009
  test.artifacts.video = await this.page.video().path();
1997
2010
  }
1998
2011
 
@@ -2004,7 +2017,7 @@ class Playwright extends Helper {
2004
2017
  }
2005
2018
 
2006
2019
  async _passed(test) {
2007
- if (this.options.recordVideo && this.page.video()) {
2020
+ if (this.options.recordVideo && this.page && this.page.video()) {
2008
2021
  if (this.options.keepVideoForPassedTests) {
2009
2022
  test.artifacts.video = await this.page.video().path();
2010
2023
  } else {
@@ -2427,9 +2440,8 @@ class Playwright extends Helper {
2427
2440
  * ```
2428
2441
  * This method allows intercepting and mocking requests & responses. [Learn more about it](https://playwright.dev/docs/network#handle-requests)
2429
2442
  *
2430
- * @param {string} [url] URL, regex or pattern for to match URL
2431
- * @param {function} [handler] a function to process request
2432
- *
2443
+ * @param {string|RegExp} [url] URL, regex or pattern for to match URL
2444
+ * @param {function} [handler] a function to process reques
2433
2445
  */
2434
2446
  async mockRoute(url, handler) {
2435
2447
  return this.browserContext.route(...arguments);
@@ -2444,9 +2456,8 @@ class Playwright extends Helper {
2444
2456
  * ```
2445
2457
  * If no handler is passed, all mock requests for the rote are disabled.
2446
2458
  *
2447
- * @param {string} [url] URL, regex or pattern for to match URL
2448
- * @param {function} [handler] a function to process request
2449
- *
2459
+ * @param {string|RegExp} [url] URL, regex or pattern for to match URL
2460
+ * @param {function} [handler] a function to process reques
2450
2461
  */
2451
2462
  async stopMockingRoute(url, handler) {
2452
2463
  return this.browserContext.unroute(...arguments);
@@ -87,7 +87,7 @@ class REST extends Helper {
87
87
  * @param {object} headers headers list
88
88
  */
89
89
  haveRequestHeaders(headers) {
90
- this.headers = { ...headers, ...this.headers };
90
+ this.headers = { ...this.headers, ...headers };
91
91
  }
92
92
 
93
93
  /**
@@ -98,7 +98,7 @@ class REST extends Helper {
98
98
  * I.amBearerAuthenticated(secret('heregoestoken'))
99
99
  * ```
100
100
  *
101
- * @param {string} accessToken Bearer access token
101
+ * @param {string | CodeceptJS.Secret} accessToken Bearer access token
102
102
  */
103
103
  amBearerAuthenticated(accessToken) {
104
104
  this.haveRequestHeaders({ Authorization: `Bearer ${accessToken}` });
@@ -112,6 +112,9 @@ class REST extends Helper {
112
112
  * @returns {Promise<*>} response
113
113
  */
114
114
  async _executeRequest(request) {
115
+ // Add custom headers. They can be set by amBearerAuthenticated() or haveRequestHeaders()
116
+ request.headers = { ...this.headers, ...request.headers };
117
+
115
118
  const _debugRequest = { ...request };
116
119
  this.axios.defaults.timeout = request.timeout || this.options.timeout;
117
120
 
@@ -2551,6 +2551,8 @@ class WebDriver extends Helper {
2551
2551
 
2552
2552
  /**
2553
2553
  * Placeholder for ~ locator only test case write once run on both Appium and WebDriver.
2554
+ * @param {*} caps
2555
+ * @param {*} fn
2554
2556
  */
2555
2557
  /* eslint-disable */
2556
2558
  runOnIOS(caps, fn) {
@@ -2558,6 +2560,8 @@ class WebDriver extends Helper {
2558
2560
 
2559
2561
  /**
2560
2562
  * Placeholder for ~ locator only test case write once run on both Appium and WebDriver.
2563
+ * @param {*} caps
2564
+ * @param {*} fn
2561
2565
  */
2562
2566
  runOnAndroid(caps, fn) {
2563
2567
  }
@@ -1,4 +1,5 @@
1
1
  const { CucumberExpression, ParameterTypeRegistry } = require('cucumber-expressions');
2
+ const Config = require('../config');
2
3
 
3
4
  let steps = {};
4
5
 
@@ -9,7 +10,11 @@ const STACK_POSITION = 2;
9
10
  * @param {*} fn
10
11
  */
11
12
  const addStep = (step, fn) => {
13
+ const avoidDuplicateSteps = Config.get('gherkin', {}).avoidDuplicateSteps || false;
12
14
  const stack = (new Error()).stack;
15
+ if (avoidDuplicateSteps && steps[step]) {
16
+ throw new Error(`Step '${step}' is already defined`);
17
+ }
13
18
  steps[step] = fn;
14
19
  fn.line = stack && stack.split('\n')[STACK_POSITION];
15
20
  if (fn.line) {
@@ -69,6 +69,7 @@ module.exports = function () {
69
69
  event.dispatcher.on(event.step.started, (step) => {
70
70
  if (store.debugMode) return;
71
71
  step.startedAt = +new Date();
72
+ step.test = currentTest;
72
73
  if (currentHook && Array.isArray(currentHook.steps)) {
73
74
  return currentHook.steps.push(step);
74
75
  }
@@ -1,4 +1,4 @@
1
- const faker = require('faker');
1
+ const faker = require('@faker-js/faker');
2
2
  const transform = require('../transform');
3
3
 
4
4
  /**
@@ -142,18 +142,20 @@ module.exports = function (config) {
142
142
  if (step.metaStep && step.metaStep.name === 'BeforeSuite') return;
143
143
 
144
144
  const fileName = `${pad.substring(0, pad.length - stepNum.toString().length) + stepNum.toString()}.png`;
145
+ if (step.status === 'failed') {
146
+ scenarioFailed = true;
147
+ }
148
+ stepNum++;
149
+ slides[fileName] = step;
145
150
  try {
146
- if (step.status === 'failed') {
147
- scenarioFailed = true;
148
- }
149
- stepNum++;
150
- slides[fileName] = step;
151
151
  await helper.saveScreenshot(path.relative(reportDir, path.join(dir, fileName)), config.fullPageScreenshots);
152
152
  } catch (err) {
153
153
  output.plugin(`Can't save step screenshot: ${err}`);
154
154
  error = err;
155
+ return;
156
+ } finally {
157
+ savedStep = step;
155
158
  }
156
- savedStep = step;
157
159
 
158
160
  if (!currentTest.artifacts.screenshots) currentTest.artifacts.screenshots = [];
159
161
  // added attachments to test
package/lib/workers.js CHANGED
@@ -358,6 +358,18 @@ class Workers extends EventEmitter {
358
358
  case event.test.after:
359
359
  this.emit(event.test.after, repackTest(message.data));
360
360
  break;
361
+ case event.step.finished:
362
+ this.emit(event.step.finished, message.data);
363
+ break;
364
+ case event.step.started:
365
+ this.emit(event.step.started, message.data);
366
+ break;
367
+ case event.step.passed:
368
+ this.emit(event.step.passed, message.data);
369
+ break;
370
+ case event.step.failed:
371
+ this.emit(event.step.failed, message.data);
372
+ break;
361
373
  }
362
374
  });
363
375