codeceptjs 2.3.4 → 2.4.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 (269) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +28 -6
  3. package/bin/codecept.js +42 -0
  4. package/docs/advanced.md +45 -1
  5. package/docs/angular.md +3 -3
  6. package/docs/basics.md +162 -118
  7. package/docs/bdd.md +30 -5
  8. package/docs/best.md +8 -6
  9. package/docs/books.md +6 -1
  10. package/docs/build/Appium.js +95 -85
  11. package/docs/build/FileSystem.js +48 -3
  12. package/docs/build/GraphQL.js +3 -2
  13. package/docs/build/GraphQLDataFactory.js +1 -0
  14. package/docs/build/Mochawesome.js +3 -2
  15. package/docs/build/MockRequest.js +23 -5
  16. package/docs/build/Nightmare.js +87 -128
  17. package/docs/build/Protractor.js +107 -155
  18. package/docs/build/Puppeteer.js +190 -174
  19. package/docs/build/REST.js +13 -9
  20. package/docs/build/SeleniumWebdriver.js +0 -17
  21. package/docs/build/TestCafe.js +164 -158
  22. package/docs/build/WebDriver.js +236 -211
  23. package/docs/build/WebDriverIO.js +218 -187
  24. package/docs/changelog.md +57 -1
  25. package/docs/commands.md +41 -2
  26. package/docs/community-helpers.md +12 -1
  27. package/docs/configuration.md +5 -2
  28. package/docs/continuous-integration.md +22 -0
  29. package/docs/{helpers.md → custom-helpers.md} +16 -10
  30. package/docs/data.md +7 -6
  31. package/docs/detox.md +6 -6
  32. package/docs/email.md +4 -2
  33. package/docs/examples.md +22 -3
  34. package/docs/helpers/ApiDataFactory.md +15 -13
  35. package/docs/helpers/Appium.md +1011 -468
  36. package/docs/helpers/Detox.md +33 -26
  37. package/docs/helpers/FileSystem.md +43 -13
  38. package/docs/helpers/GraphQL.md +17 -15
  39. package/docs/helpers/GraphQLDataFactory.md +15 -13
  40. package/docs/helpers/Mochawesome.md +3 -1
  41. package/docs/helpers/MockRequest.md +37 -19
  42. package/docs/helpers/Nightmare.md +129 -240
  43. package/docs/helpers/Polly.md +1 -1
  44. package/docs/helpers/Protractor.md +157 -298
  45. package/docs/helpers/Puppeteer.md +216 -335
  46. package/docs/helpers/REST.md +29 -24
  47. package/docs/helpers/TestCafe.md +137 -235
  48. package/docs/helpers/WebDriver.md +250 -347
  49. package/docs/hooks.md +14 -10
  50. package/docs/index.md +112 -0
  51. package/docs/installation.md +3 -1
  52. package/docs/locators.md +19 -8
  53. package/docs/mobile-react-native-locators.md +2 -2
  54. package/docs/mobile.md +5 -3
  55. package/docs/nightmare.md +2 -1
  56. package/docs/pageobjects.md +4 -2
  57. package/docs/parallel.md +4 -2
  58. package/docs/plugins.md +41 -15
  59. package/docs/puppeteer.md +8 -6
  60. package/docs/quickstart.md +130 -0
  61. package/docs/react.md +4 -2
  62. package/docs/reports.md +6 -4
  63. package/docs/testcafe.md +10 -8
  64. package/docs/translation.md +4 -2
  65. package/docs/ui.md +56 -0
  66. package/docs/videos.md +11 -2
  67. package/docs/visual.md +7 -5
  68. package/docs/vue.md +121 -0
  69. package/docs/webapi/appendField.mustache +1 -1
  70. package/docs/webapi/attachFile.mustache +1 -1
  71. package/docs/webapi/checkOption.mustache +2 -2
  72. package/docs/webapi/clearCookie.mustache +1 -1
  73. package/docs/webapi/click.mustache +2 -2
  74. package/docs/webapi/clickLink.mustache +2 -2
  75. package/docs/webapi/dontSee.mustache +1 -2
  76. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +1 -1
  77. package/docs/webapi/dontSeeElement.mustache +1 -1
  78. package/docs/webapi/dontSeeElementInDOM.mustache +1 -1
  79. package/docs/webapi/dontSeeInField.mustache +1 -1
  80. package/docs/webapi/doubleClick.mustache +2 -2
  81. package/docs/webapi/downloadFile.mustache +1 -1
  82. package/docs/webapi/dragSlider.mustache +1 -1
  83. package/docs/webapi/executeAsyncScript.mustache +2 -1
  84. package/docs/webapi/executeScript.mustache +2 -1
  85. package/docs/webapi/fillField.mustache +1 -1
  86. package/docs/webapi/grabAttributeFrom.mustache +1 -1
  87. package/docs/webapi/grabBrowserLogs.mustache +1 -1
  88. package/docs/webapi/grabCookie.mustache +2 -2
  89. package/docs/webapi/grabCssPropertyFrom.mustache +1 -1
  90. package/docs/webapi/grabHTMLFrom.mustache +1 -1
  91. package/docs/webapi/grabNumberOfVisibleElements.mustache +1 -1
  92. package/docs/webapi/grabPageScrollPosition.mustache +1 -1
  93. package/docs/webapi/grabTextFrom.mustache +2 -2
  94. package/docs/webapi/grabValueFrom.mustache +1 -1
  95. package/docs/webapi/moveCursorTo.mustache +3 -3
  96. package/docs/webapi/pressKey.mustache +1 -1
  97. package/docs/webapi/pressKeyWithKeyNormalization.mustache +1 -1
  98. package/docs/webapi/rightClick.mustache +2 -2
  99. package/docs/webapi/saveScreenshot.mustache +1 -1
  100. package/docs/webapi/scrollIntoView.mustache +10 -0
  101. package/docs/webapi/scrollTo.mustache +3 -3
  102. package/docs/webapi/see.mustache +1 -1
  103. package/docs/webapi/seeAttributesOnElements.mustache +1 -1
  104. package/docs/webapi/seeCheckboxIsChecked.mustache +1 -1
  105. package/docs/webapi/seeCssPropertiesOnElements.mustache +1 -1
  106. package/docs/webapi/seeElement.mustache +1 -1
  107. package/docs/webapi/seeElementInDOM.mustache +1 -1
  108. package/docs/webapi/seeInField.mustache +1 -1
  109. package/docs/webapi/seeNumberOfElements.mustache +1 -1
  110. package/docs/webapi/seeNumberOfVisibleElements.mustache +1 -1
  111. package/docs/webapi/seeTextEquals.mustache +8 -0
  112. package/docs/webapi/selectOption.mustache +2 -2
  113. package/docs/webapi/switchTo.mustache +1 -1
  114. package/docs/webapi/uncheckOption.mustache +2 -2
  115. package/docs/webapi/waitForClickable.mustache +10 -0
  116. package/docs/webapi/waitForDetached.mustache +2 -2
  117. package/docs/webapi/waitForElement.mustache +2 -2
  118. package/docs/webapi/waitForEnabled.mustache +2 -2
  119. package/docs/webapi/waitForFunction.mustache +2 -2
  120. package/docs/webapi/waitForInvisible.mustache +2 -2
  121. package/docs/webapi/waitForText.mustache +2 -2
  122. package/docs/webapi/waitForValue.mustache +1 -1
  123. package/docs/webapi/waitForVisible.mustache +2 -2
  124. package/docs/webapi/waitInUrl.mustache +1 -1
  125. package/docs/webapi/waitNumberOfVisibleElements.mustache +2 -2
  126. package/docs/webapi/waitToHide.mustache +2 -2
  127. package/docs/webapi/waitUntil.mustache +3 -2
  128. package/docs/webapi/waitUrlEquals.mustache +1 -1
  129. package/docs/webdriver.md +20 -18
  130. package/docs/wiki/.git/FETCH_HEAD +1 -0
  131. package/docs/wiki/.git/HEAD +1 -0
  132. package/docs/wiki/.git/ORIG_HEAD +1 -0
  133. package/docs/wiki/.git/config +11 -0
  134. package/docs/wiki/.git/description +1 -0
  135. package/docs/wiki/.git/hooks/applypatch-msg.sample +15 -0
  136. package/docs/wiki/.git/hooks/commit-msg.sample +24 -0
  137. package/docs/wiki/.git/hooks/fsmonitor-watchman.sample +114 -0
  138. package/docs/wiki/.git/hooks/post-update.sample +8 -0
  139. package/docs/wiki/.git/hooks/pre-applypatch.sample +14 -0
  140. package/docs/wiki/.git/hooks/pre-commit.sample +49 -0
  141. package/docs/wiki/.git/hooks/pre-push.sample +53 -0
  142. package/docs/wiki/.git/hooks/pre-rebase.sample +169 -0
  143. package/docs/wiki/.git/hooks/pre-receive.sample +24 -0
  144. package/docs/wiki/.git/hooks/prepare-commit-msg.sample +42 -0
  145. package/docs/wiki/.git/hooks/update.sample +128 -0
  146. package/docs/wiki/.git/index +0 -0
  147. package/docs/wiki/.git/info/exclude +6 -0
  148. package/docs/wiki/.git/logs/HEAD +4 -0
  149. package/docs/wiki/.git/logs/refs/heads/master +4 -0
  150. package/docs/wiki/.git/logs/refs/remotes/origin/HEAD +1 -0
  151. package/docs/wiki/.git/logs/refs/remotes/origin/master +3 -0
  152. package/docs/wiki/.git/objects/00/d216b0774d15db2d0a2a0d4ce249b5251acc55 +3 -0
  153. package/docs/wiki/.git/objects/09/01d87c5241905fdfe3493cfe8f04df4a2685ea +0 -0
  154. package/docs/wiki/.git/objects/0d/bdd0c20c4deb6a8cc81dbbf32ecf8c09238983 +2 -0
  155. package/docs/wiki/.git/objects/1a/c29e4fa82422c52392f22f0f2b8d1a759535bf +0 -0
  156. package/docs/wiki/.git/objects/27/12f92898d3e8f68e229b6cda76570d6c66d781 +0 -0
  157. package/docs/wiki/.git/objects/2d/dbe22c257166b648928eeb9460ecfb71ba702d +0 -0
  158. package/docs/wiki/.git/objects/2f/c942ec3773efd2678d9ff98035c61fcded81a1 +0 -0
  159. package/docs/wiki/.git/objects/40/a2856342c67796b48911a256b764fb06888b94 +5 -0
  160. package/docs/wiki/.git/objects/47/53181844fc4dc563cf3aa5e80462243cb58d38 +0 -0
  161. package/docs/wiki/.git/objects/4e/24a95fb2e4f8ffef51f19b694451a205c06f10 +3 -0
  162. package/docs/wiki/.git/objects/73/31ebd96f3c7e08a9f63f05a25f939afa0d4de1 +0 -0
  163. package/docs/wiki/.git/objects/86/19cbb2289caa502e33fccf0ed14eecf6ba2ba0 +0 -0
  164. package/docs/wiki/.git/objects/a4/72f797d9d74b87c9f71a2b1539d75bb07d1e35 +0 -0
  165. package/docs/wiki/.git/objects/c9/9f3e4bd227d6b050b2e416f9876df49583dbf6 +0 -0
  166. package/docs/wiki/.git/objects/ca/e609b4ef3e0ef85fcbe0d68d1a58246584b915 +0 -0
  167. package/docs/wiki/.git/objects/d5/8386ca72f6d550548f3d71d74e3ac73d5ad488 +0 -0
  168. package/docs/wiki/.git/objects/d9/c6874a6de524bdafeb563a20d847f4fdd59a86 +0 -0
  169. package/docs/wiki/.git/objects/f1/c944675bb38b40ae553b0be36c14674c79af54 +0 -0
  170. package/docs/wiki/.git/objects/pack/pack-28da0fc7e6c08d4c5350717bfbb7b1c53e8198ad.idx +0 -0
  171. package/docs/wiki/.git/objects/pack/pack-28da0fc7e6c08d4c5350717bfbb7b1c53e8198ad.pack +0 -0
  172. package/docs/wiki/.git/packed-refs +2 -0
  173. package/docs/wiki/.git/refs/heads/master +1 -0
  174. package/docs/wiki/.git/refs/remotes/origin/HEAD +1 -0
  175. package/docs/wiki/.git/refs/remotes/origin/master +1 -0
  176. package/docs/wiki/Books-&-Posts.md +27 -0
  177. package/docs/wiki/Community-Helpers.md +41 -0
  178. package/docs/wiki/Examples.md +138 -0
  179. package/docs/wiki/Home.md +11 -0
  180. package/docs/wiki/Release-process.md +25 -0
  181. package/docs/wiki/Roadmap.md +23 -0
  182. package/docs/wiki/Videos.md +19 -0
  183. package/lib/actor.js +18 -1
  184. package/lib/assert/error.js +3 -3
  185. package/lib/codecept.js +9 -6
  186. package/lib/command/configMigrate.js +7 -6
  187. package/lib/command/definitions.js +98 -350
  188. package/lib/command/generate.js +22 -17
  189. package/lib/command/gherkin/init.js +2 -1
  190. package/lib/command/gherkin/snippets.js +6 -6
  191. package/lib/command/gherkin/steps.js +0 -1
  192. package/lib/command/info.js +40 -0
  193. package/lib/command/init.js +54 -41
  194. package/lib/command/run-multiple.js +5 -4
  195. package/lib/command/run-rerun.js +39 -0
  196. package/lib/command/run-workers.js +4 -6
  197. package/lib/command/run.js +8 -18
  198. package/lib/command/utils.js +23 -2
  199. package/lib/command/workers/runTests.js +1 -2
  200. package/lib/config.js +10 -4
  201. package/lib/container.js +31 -6
  202. package/lib/data/dataTableArgument.js +31 -0
  203. package/lib/data/table.js +4 -0
  204. package/lib/event.js +65 -1
  205. package/lib/helper/Appium.js +52 -38
  206. package/lib/helper/FileSystem.js +48 -3
  207. package/lib/helper/GraphQL.js +3 -2
  208. package/lib/helper/GraphQLDataFactory.js +1 -0
  209. package/lib/helper/Mochawesome.js +3 -2
  210. package/lib/helper/MockRequest.js +23 -5
  211. package/lib/helper/Nightmare.js +5 -6
  212. package/lib/helper/Protractor.js +7 -8
  213. package/lib/helper/Puppeteer.js +76 -20
  214. package/lib/helper/REST.js +13 -9
  215. package/lib/helper/SeleniumWebdriver.js +0 -17
  216. package/lib/helper/TestCafe.js +84 -36
  217. package/lib/helper/WebDriver.js +113 -59
  218. package/lib/helper/WebDriverIO.js +43 -59
  219. package/lib/helper/clientscripts/nightmare.js +66 -4
  220. package/lib/helper/scripts/isElementClickable.js +24 -0
  221. package/lib/helper.js +34 -10
  222. package/lib/history.js +1 -1
  223. package/lib/hooks.js +2 -1
  224. package/lib/index.js +19 -0
  225. package/lib/interfaces/bdd.js +4 -0
  226. package/lib/interfaces/featureConfig.js +10 -3
  227. package/lib/interfaces/gherkin.js +6 -2
  228. package/lib/interfaces/scenarioConfig.js +17 -6
  229. package/lib/listener/config.js +1 -1
  230. package/lib/listener/exit.js +6 -0
  231. package/lib/listener/steps.js +0 -1
  232. package/lib/listener/trace.js +0 -1
  233. package/lib/locator.js +67 -2
  234. package/lib/output.js +53 -0
  235. package/lib/parser.js +2 -71
  236. package/lib/pause.js +3 -2
  237. package/lib/plugin/allure.js +41 -22
  238. package/lib/plugin/autoLogin.js +4 -1
  239. package/lib/plugin/pauseOnFail.js +38 -0
  240. package/lib/plugin/puppeteerCoverage.js +8 -7
  241. package/lib/plugin/screenshotOnFail.js +13 -8
  242. package/lib/plugin/stepByStepReport.js +7 -6
  243. package/lib/plugin/wdio.js +2 -1
  244. package/lib/recorder.js +85 -7
  245. package/lib/rerun.js +81 -0
  246. package/lib/secret.js +6 -0
  247. package/lib/session.js +9 -2
  248. package/lib/step.js +37 -2
  249. package/lib/store.js +5 -1
  250. package/lib/ui.js +34 -8
  251. package/lib/utils.js +6 -13
  252. package/lib/within.js +5 -0
  253. package/package.json +49 -29
  254. package/typings/Mocha.d.ts +21 -0
  255. package/typings/Protractor.d.ts +16 -0
  256. package/typings/index.d.ts +169 -0
  257. package/typings/jsdoc.conf.js +34 -0
  258. package/typings/jsdoc.namespace.js +29 -0
  259. package/typings/types.d.ts +9827 -0
  260. package/typings/utils.d.ts +7 -0
  261. package/docs/acceptance.md +0 -409
  262. package/docs/api/codecept.md +0 -75
  263. package/docs/api/config.md +0 -49
  264. package/docs/api/container.md +0 -66
  265. package/docs/api/helper.md +0 -116
  266. package/docs/api/output.md +0 -67
  267. package/docs/api/recorder.md +0 -63
  268. package/docs/helpers/SeleniumWebdriver.md +0 -92
  269. package/docs/helpers/WebDriverIO.md +0 -1671
@@ -1,13 +1,14 @@
1
+ const colors = require('chalk');
2
+ const crypto = require('crypto');
3
+ const figures = require('figures');
4
+ const fs = require('fs');
5
+ const mkdirp = require('mkdirp');
6
+ const path = require('path');
7
+
1
8
  const Container = require('../container');
2
9
  const recorder = require('../recorder');
3
10
  const event = require('../event');
4
11
  const output = require('../output');
5
- const mkdirp = require('mkdirp');
6
- const fs = require('fs');
7
- const path = require('path');
8
- const figures = require('figures');
9
- const colors = require('chalk');
10
- const crypto = require('crypto');
11
12
  const { template, deleteDir } = require('../utils');
12
13
 
13
14
  const supportedHelpers = [
@@ -1,9 +1,10 @@
1
+ const debug = require('debug')('codeceptjs:plugin:wdio');
2
+
1
3
  const container = require('../container');
2
4
  const mainConfig = require('../config');
3
5
  const recorder = require('../recorder');
4
6
  const event = require('../event');
5
7
  const output = require('../output');
6
- const debug = require('debug')('codeceptjs:plugin:wdio');
7
8
 
8
9
  const defaultConfig = {
9
10
  services: [],
package/lib/recorder.js CHANGED
@@ -1,6 +1,7 @@
1
+ const debug = require('debug')('codeceptjs');
1
2
  const promiseRetry = require('promise-retry');
3
+
2
4
  const log = require('./output').log;
3
- const debug = require('debug')('codeceptjs');
4
5
 
5
6
  let promise;
6
7
  let running = false;
@@ -20,11 +21,14 @@ const defaultRetryOptions = {
20
21
 
21
22
  /**
22
23
  * Singleton object to record all test steps as promises and run them in chain.
24
+ * @alias recorder
25
+ * @interface
23
26
  */
24
27
  module.exports = {
25
28
 
26
29
  /**
27
- * @var retries Array[object]
30
+ * @type {Array<Object<string, *>>}
31
+ * @inner
28
32
  */
29
33
  retries: [],
30
34
 
@@ -32,6 +36,7 @@ module.exports = {
32
36
  * Start recording promises
33
37
  *
34
38
  * @api
39
+ * @inner
35
40
  */
36
41
  start() {
37
42
  running = true;
@@ -40,10 +45,18 @@ module.exports = {
40
45
  this.reset();
41
46
  },
42
47
 
48
+ /**
49
+ * @return {boolean}
50
+ * @inner
51
+ */
43
52
  isRunning() {
44
53
  return running;
45
54
  },
46
55
 
56
+ /**
57
+ * @return {void}
58
+ * @inner
59
+ */
47
60
  startUnlessRunning() {
48
61
  if (!this.isRunning()) {
49
62
  this.start();
@@ -54,7 +67,8 @@ module.exports = {
54
67
  * Add error handler to catch rejected promises
55
68
  *
56
69
  * @api
57
- * @param {*} fn
70
+ * @param {function} fn
71
+ * @inner
58
72
  */
59
73
  errHandler(fn) {
60
74
  errFn = fn;
@@ -65,6 +79,7 @@ module.exports = {
65
79
  * Resets recorder to initial state.
66
80
  *
67
81
  * @api
82
+ * @inner
68
83
  */
69
84
  reset() {
70
85
  if (promise && running) this.catch();
@@ -79,9 +94,27 @@ module.exports = {
79
94
  this.retries = [];
80
95
  },
81
96
 
97
+ /**
98
+ * @name CodeceptJS.recorder~session
99
+ * @type {CodeceptJS.RecorderSession}
100
+ * @inner
101
+ */
102
+
103
+ /**
104
+ * @alias RecorderSession
105
+ * @interface
106
+ */
82
107
  session: {
108
+ /**
109
+ * @type {boolean}
110
+ * @inner
111
+ */
83
112
  running: false,
84
113
 
114
+ /**
115
+ * @param {string} name
116
+ * @inner
117
+ */
85
118
  start(name) {
86
119
  log(`${currentQueue()}Starting <${name}> session`);
87
120
  tasks.push('--->');
@@ -91,6 +124,10 @@ module.exports = {
91
124
  promise = Promise.resolve();
92
125
  },
93
126
 
127
+ /**
128
+ * @param {string} name
129
+ * @inner
130
+ */
94
131
  restore(name) {
95
132
  tasks.push('<---');
96
133
  log(`${currentQueue()}Finalize <${name}> session`);
@@ -100,6 +137,10 @@ module.exports = {
100
137
  promise = promise.then(() => oldPromises.pop());
101
138
  },
102
139
 
140
+ /**
141
+ * @param {function} fn
142
+ * @inner
143
+ */
103
144
  catch(fn) {
104
145
  promise = promise.catch(fn);
105
146
  },
@@ -110,12 +151,14 @@ module.exports = {
110
151
  * Adds a promise to a chain.
111
152
  * Promise description should be passed as first parameter.
112
153
  *
113
- * @param {*} taskName
114
- * @param {*} fn
115
- * @param {*} force
116
- * @param {boolean} retry -
154
+ * @param {string} taskName
155
+ * @param {function} [fn]
156
+ * @param {boolean} [force=false]
157
+ * @param {boolean} [retry=true] -
117
158
  * true: it will retries if `retryOpts` set.
118
159
  * false: ignore `retryOpts` and won't retry.
160
+ * @return {Promise<*> | undefined}
161
+ * @inner
119
162
  */
120
163
  add(taskName, fn = undefined, force = false, retry = true) {
121
164
  if (typeof taskName === 'function') {
@@ -152,6 +195,11 @@ module.exports = {
152
195
  });
153
196
  },
154
197
 
198
+ /**
199
+ * @param {*} opts
200
+ * @return {*}
201
+ * @inner
202
+ */
155
203
  retry(opts) {
156
204
  if (!promise) return;
157
205
 
@@ -164,6 +212,11 @@ module.exports = {
164
212
  return this.add(() => this.retries.push(opts));
165
213
  },
166
214
 
215
+ /**
216
+ * @param {function} [customErrFn]
217
+ * @return {Promise<*>}
218
+ * @inner
219
+ */
167
220
  catch(customErrFn) {
168
221
  return promise = promise.catch((err) => {
169
222
  log(`${currentQueue()}Error | ${err}`);
@@ -179,6 +232,11 @@ module.exports = {
179
232
  });
180
233
  },
181
234
 
235
+ /**
236
+ * @param {function} customErrFn
237
+ * @return {Promise<*>}
238
+ * @inner
239
+ */
182
240
  catchWithoutStop(customErrFn) {
183
241
  return promise = promise.catch((err) => {
184
242
  log(`${currentQueue()}Error | ${err}`);
@@ -198,6 +256,7 @@ module.exports = {
198
256
  *
199
257
  * @api
200
258
  * @param {*} err
259
+ * @inner
201
260
  */
202
261
  throw(err) {
203
262
  return this.add(`throw error ${err}`, () => {
@@ -205,16 +264,28 @@ module.exports = {
205
264
  });
206
265
  },
207
266
 
267
+ /**
268
+ * @param {*} err
269
+ * @inner
270
+ */
208
271
  saveFirstAsyncError(err) {
209
272
  if (asyncErr === null) {
210
273
  asyncErr = err;
211
274
  }
212
275
  },
213
276
 
277
+ /**
278
+ * @return {*}
279
+ * @inner
280
+ */
214
281
  getAsyncErr() {
215
282
  return asyncErr;
216
283
  },
217
284
 
285
+ /**
286
+ * @return {void}
287
+ * @inner
288
+ */
218
289
  cleanAsyncErr() {
219
290
  asyncErr = null;
220
291
  },
@@ -222,6 +293,7 @@ module.exports = {
222
293
  /**
223
294
  * Stops recording promises
224
295
  * @api
296
+ * @inner
225
297
  */
226
298
  stop() {
227
299
  debug(this.toString());
@@ -234,6 +306,8 @@ module.exports = {
234
306
  * Get latest promise in chain.
235
307
  *
236
308
  * @api
309
+ * @return {Promise<*>}
310
+ * @inner
237
311
  */
238
312
  promise() {
239
313
  return promise;
@@ -241,6 +315,8 @@ module.exports = {
241
315
 
242
316
  /**
243
317
  * Get a list of all chained tasks
318
+ * @return {string}
319
+ * @inner
244
320
  */
245
321
  scheduled() {
246
322
  return tasks.join('\n');
@@ -248,6 +324,8 @@ module.exports = {
248
324
 
249
325
  /**
250
326
  * Get a state of current queue and tasks
327
+ * @return {string}
328
+ * @inner
251
329
  */
252
330
  toString() {
253
331
  return `Queue: ${currentQueue()}\n\nTasks: ${this.scheduled()}`;
package/lib/rerun.js ADDED
@@ -0,0 +1,81 @@
1
+ const fsPath = require('path');
2
+ const container = require('./container');
3
+ const event = require('./event');
4
+ const BaseCodecept = require('./codecept');
5
+ const output = require('./output');
6
+
7
+ class CodeceptRerunner extends BaseCodecept {
8
+ runOnce(test) {
9
+ return new Promise((resolve, reject) => {
10
+ // @ts-ignore
11
+ container.createMocha();
12
+ const mocha = container.mocha();
13
+ this.testFiles.forEach((file) => {
14
+ delete require.cache[file];
15
+ });
16
+ mocha.files = this.testFiles;
17
+ if (test) {
18
+ if (!fsPath.isAbsolute(test)) {
19
+ test = fsPath.join(global.codecept_dir, test);
20
+ }
21
+ mocha.files = mocha.files.filter(t => fsPath.basename(t, '.js') === test || t === test);
22
+ }
23
+ try {
24
+ mocha.run((failures) => {
25
+ if (failures === 0) {
26
+ resolve();
27
+ } else {
28
+ reject(new Error(`${failures} tests fail`));
29
+ }
30
+ });
31
+ } catch (e) {
32
+ reject(e);
33
+ }
34
+ });
35
+ }
36
+
37
+ async runTests(test) {
38
+ const configRerun = this.config.rerun || {};
39
+ const minSuccess = configRerun.minSuccess || 1;
40
+ const maxReruns = configRerun.maxReruns || 1;
41
+ if (minSuccess > maxReruns) throw new Error('minSuccess must be less than maxReruns');
42
+ if (maxReruns === 1) {
43
+ await this.runOnce(test);
44
+ return;
45
+ }
46
+ let successCounter = 0;
47
+ let rerunsCounter = 0;
48
+ while (rerunsCounter < maxReruns && successCounter < minSuccess) {
49
+ rerunsCounter++;
50
+ try {
51
+ await this.runOnce(test);
52
+ successCounter++;
53
+ output.success(`\nProcess run ${rerunsCounter} of max ${maxReruns}, success runs ${successCounter}/${minSuccess}\n`);
54
+ } catch (e) {
55
+ output.error(`\nFail run ${rerunsCounter} of max ${maxReruns}, success runs ${successCounter}/${minSuccess} \n`);
56
+ console.error(e);
57
+ }
58
+ }
59
+ if (successCounter < minSuccess) {
60
+ throw new Error(`Flaky tests detected! ${successCounter} success runs achieved instead of ${minSuccess} success runs expected`);
61
+ }
62
+ }
63
+
64
+ run(test) {
65
+ const done = () => {
66
+ event.emit(event.all.result, this);
67
+ event.emit(event.all.after, this);
68
+ };
69
+ event.emit(event.all.before, this);
70
+ return this.runTests(test)
71
+ .then(() => {
72
+ this.teardown(done);
73
+ })
74
+ .catch((e) => {
75
+ this.teardown(done);
76
+ throw e;
77
+ });
78
+ }
79
+ }
80
+
81
+ module.exports = CodeceptRerunner;
package/lib/secret.js CHANGED
@@ -1,12 +1,18 @@
1
+ /** @param {string} secret */
1
2
  class Secret {
2
3
  constructor(secret) {
3
4
  this._secret = secret;
4
5
  }
5
6
 
7
+ /** @returns {string} */
6
8
  toString() {
7
9
  return this._secret;
8
10
  }
9
11
 
12
+ /**
13
+ * @param {*} secret
14
+ * @returns {Secret}
15
+ */
10
16
  static secret(secret) {
11
17
  return new Secret(secret);
12
18
  }
package/lib/session.js CHANGED
@@ -15,6 +15,12 @@ const sessionColors = [
15
15
 
16
16
  const savedSessions = {};
17
17
 
18
+ /**
19
+ * @param {CodeceptJS.LocatorOrString} sessionName
20
+ * @param {Function | Object<string, *>} config
21
+ * @param {Function} [fn]
22
+ * @return {Promise<*> | undefined}
23
+ */
18
24
  function session(sessionName, config, fn) {
19
25
  if (typeof config === 'function') {
20
26
  if (typeof fn === 'function') {
@@ -34,12 +40,13 @@ function session(sessionName, config, fn) {
34
40
  if (!savedSessions[sessionName]) {
35
41
  for (const helper in helpers) {
36
42
  if (!helpers[helper]._session) continue;
37
- savedSessions[sessionName] = Object.assign({
43
+ savedSessions[sessionName] = {
38
44
  start: () => null,
39
45
  stop: () => null,
40
46
  loadVars: () => null,
41
47
  restoreVars: () => null,
42
- }, store.dryRun ? {} : helpers[helper]._session());
48
+ ...(store.dryRun ? {} : helpers[helper]._session()),
49
+ };
43
50
  break;
44
51
  }
45
52
 
package/lib/step.js CHANGED
@@ -1,3 +1,6 @@
1
+ // TODO: place MetaStep in other file, disable rule
2
+ /* eslint-disable max-classes-per-file */
3
+
1
4
  const store = require('./store');
2
5
  const Secret = require('./secret');
3
6
 
@@ -10,30 +13,52 @@ let support;
10
13
  /**
11
14
  * Each command in test executed through `I.` object is wrapped in Step.
12
15
  * Step allows logging executed commands and triggers hook before and after step execution.
16
+ * @param {CodeceptJS.Helper} helper
17
+ * @param {string} name
13
18
  */
14
19
  class Step {
15
20
  constructor(helper, name) {
21
+ /** @member {string} */
16
22
  this.actor = 'I'; // I = actor
23
+ /** @member {CodeceptJS.Helper} */
17
24
  this.helper = helper; // corresponding helper
25
+ /** @member {string} */
18
26
  this.name = name; // name of a step console
27
+ /** @member {string} */
19
28
  this.helperMethod = name; // helper method
29
+ /** @member {string} */
20
30
  this.status = 'pending';
31
+ /**
32
+ * @member {string} suffix
33
+ * @memberof CodeceptJS.Step#
34
+ */
35
+ /** @member {string} */
21
36
  this.prefix = this.suffix = '';
37
+ /** @member {string} */
22
38
  this.comment = '';
39
+ /** @member {Array<*>} */
23
40
  this.args = [];
41
+ /** @member {string} */
24
42
  this.stack = '';
25
43
  this.setTrace();
26
44
  }
27
45
 
46
+ /** @function */
28
47
  setTrace() {
29
48
  Error.captureStackTrace(this);
49
+ /** @member {MetaStep} */
30
50
  this.metaStep = detectMetaStep(this.stack.split('\n'));
31
51
  }
32
52
 
53
+ /** @param {Array<*>} args */
33
54
  setArguments(args) {
34
55
  this.args = args;
35
56
  }
36
57
 
58
+ /**
59
+ * @param {...any} args
60
+ * @return {*}
61
+ */
37
62
  run() {
38
63
  this.args = Array.prototype.slice.call(arguments);
39
64
  if (store.dryRun) {
@@ -51,11 +76,13 @@ class Step {
51
76
  return result;
52
77
  }
53
78
 
79
+ /** @param {string} status */
54
80
  setStatus(status) {
55
81
  this.status = status;
56
82
  if (this.metaStep) this.metaStep.setStatus(status);
57
83
  }
58
84
 
85
+ /** @return {string} */
59
86
  humanize() {
60
87
  return this.name
61
88
  // insert a space before all caps
@@ -66,11 +93,13 @@ class Step {
66
93
  .replace(/^(.)|\s(.)/g, $1 => $1.toLowerCase());
67
94
  }
68
95
 
96
+ /** @return {string} */
69
97
  humanizeArgs() {
70
98
  return this.args.map((arg) => {
71
99
  if (typeof arg === 'string') {
72
100
  return `"${arg}"`;
73
- } else if (Array.isArray(arg)) {
101
+ }
102
+ if (Array.isArray(arg)) {
74
103
  try {
75
104
  const res = JSON.stringify(arg);
76
105
  return res;
@@ -92,16 +121,19 @@ class Step {
92
121
  }).join(', ');
93
122
  }
94
123
 
124
+ /** @return {string} */
95
125
  line() {
96
126
  const lines = this.stack.split('\n');
97
127
  if (lines[STACK_LINE]) return lines[STACK_LINE].trim();
98
128
  return '';
99
129
  }
100
130
 
131
+ /** @return {string} */
101
132
  toString() {
102
133
  return `${this.prefix}${this.actor} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`;
103
134
  }
104
135
 
136
+ /** @return {string} */
105
137
  toCode() {
106
138
  return `${this.prefix}${this.actor}.${this.name}(${this.humanizeArgs()})${this.suffix}`;
107
139
  }
@@ -110,6 +142,7 @@ class Step {
110
142
  return this.constructor.name === 'MetaStep';
111
143
  }
112
144
 
145
+ /** @return {boolean} */
113
146
  hasBDDAncestor() {
114
147
  let hasBDD = false;
115
148
  let processingStep;
@@ -127,7 +160,7 @@ class Step {
127
160
  }
128
161
  }
129
162
 
130
-
163
+ /** @extends Step */
131
164
  class MetaStep extends Step {
132
165
  constructor(obj, method) {
133
166
  super(null, method);
@@ -141,10 +174,12 @@ class MetaStep extends Step {
141
174
  setTrace() {
142
175
  }
143
176
 
177
+ /** @return {void} */
144
178
  run() {
145
179
  }
146
180
  }
147
181
 
182
+ /** @type {Class<MetaStep>} */
148
183
  Step.MetaStep = MetaStep;
149
184
 
150
185
  module.exports = Step;
package/lib/store.js CHANGED
@@ -1,5 +1,9 @@
1
- // global values for current session
1
+ /**
2
+ * global values for current session
3
+ * @namespace
4
+ */
2
5
  const store = {
6
+ /** @type {boolean} */
3
7
  debugMode: false,
4
8
  };
5
9
 
package/lib/ui.js CHANGED
@@ -1,16 +1,12 @@
1
- /**
2
- * Module dependencies.
3
- */
4
-
1
+ const escapeRe = require('escape-string-regexp');
5
2
  const Suite = require('mocha/lib/suite');
6
3
  const Test = require('mocha/lib/test');
4
+
7
5
  const scenario = require('./scenario');
8
6
  const ScenarioConfig = require('./interfaces/scenarioConfig');
9
7
  const FeatureConfig = require('./interfaces/featureConfig');
10
- const escapeRe = require('escape-string-regexp');
11
8
  const addDataContext = require('./data/context');
12
9
 
13
-
14
10
  /**
15
11
  * Codecept-style interface:
16
12
  *
@@ -21,7 +17,8 @@ const addDataContext = require('./data/context');
21
17
  * I.see('Hello, '+data.login);
22
18
  * });
23
19
  *
24
- * @param {Suite} suite Root suite.
20
+ * @param {Mocha.Suite} suite Root suite.
21
+ * @ignore
25
22
  */
26
23
  module.exports = function (suite) {
27
24
  const suites = [suite];
@@ -47,7 +44,7 @@ module.exports = function (suite) {
47
44
  const test = new Test(title, fn);
48
45
  test.fullTitle = () => `${suite.title}: ${test.title}`;
49
46
 
50
- test.tags = (suite.tags || []).concat(title.match(/(\@[a-zA-Z0-9-_]+)/g)); // match tags from title
47
+ test.tags = (suite.tags || []).concat(title.match(/(\@[a-zA-Z0-9-_]+)/g) || []); // match tags from title
51
48
  test.file = file;
52
49
  if (!test.inject) {
53
50
  test.inject = {};
@@ -71,6 +68,10 @@ module.exports = function (suite) {
71
68
  * Describe a "suite" with the given `title`
72
69
  * and callback `fn` containing nested suites
73
70
  * and/or tests.
71
+ * @global
72
+ * @param {string} title
73
+ * @param {Object<string, *>} [opts]
74
+ * @returns {FeatureConfig}
74
75
  */
75
76
 
76
77
  context.Feature = function (title, opts) {
@@ -123,10 +124,12 @@ module.exports = function (suite) {
123
124
  * Describe a specification or test-case
124
125
  * with the given `title` and callback `fn`
125
126
  * acting as a thunk.
127
+ * @ignore
126
128
  */
127
129
  context.Scenario = addScenario;
128
130
  /**
129
131
  * Exclusive test-case.
132
+ * @ignore
130
133
  */
131
134
  context.Scenario.only = function (title, opts, fn, data) {
132
135
  const reString = `^${escapeRe(`${suites[0].title}: ${title}`.replace(/( \| {.+})?$/g, ''))}`;
@@ -136,11 +139,34 @@ module.exports = function (suite) {
136
139
 
137
140
  /**
138
141
  * Pending test case.
142
+ * @global
143
+ * @kind constant
144
+ * @type {CodeceptJS.IScenario}
139
145
  */
140
146
  context.xScenario = context.Scenario.skip = function (title) {
141
147
  return context.Scenario(title, {});
142
148
  };
143
149
 
150
+ /**
151
+ * Pending test case with message: 'Test not implemented!'.
152
+ * @global
153
+ * @kind constant
154
+ * @type {CodeceptJS.IScenario}
155
+ */
156
+ context.Scenario.todo = function (title, opts = {}, fn) {
157
+ if (typeof opts === 'function' && !fn) {
158
+ fn = opts;
159
+ opts = {};
160
+ }
161
+
162
+ const skipInfo = {
163
+ message: 'Test not implemented!',
164
+ description: fn ? fn.toString() : '',
165
+ };
166
+
167
+ return context.Scenario(title, { ...opts, skipInfo });
168
+ };
169
+
144
170
  addDataContext(context);
145
171
  });
146
172
 
package/lib/utils.js CHANGED
@@ -9,18 +9,6 @@ function isObject(item) {
9
9
  return item && typeof item === 'object' && !Array.isArray(item);
10
10
  }
11
11
 
12
- function flatTail(flatParams, params) {
13
- const res = [];
14
- for (const fp of flatParams) {
15
- for (const p of params) {
16
- res.push([p].concat(fp));
17
- }
18
- }
19
- return res;
20
- }
21
-
22
- module.exports.flatTail = flatTail;
23
-
24
12
  function deepMerge(target, source) {
25
13
  const merge = require('lodash.merge');
26
14
  return merge(target, source);
@@ -222,6 +210,7 @@ function toCamelCase(name) {
222
210
  return letter.toUpperCase();
223
211
  });
224
212
  }
213
+ module.exports.toCamelCase = toCamelCase;
225
214
 
226
215
  function convertFontWeightToNumber(name) {
227
216
  const fontWeightPatterns = [
@@ -282,13 +271,17 @@ module.exports.deleteDir = function (dir_path) {
282
271
  }
283
272
  };
284
273
 
274
+ /**
275
+ * Returns absolute filename to save screenshot.
276
+ * @param fileName {string} - filename.
277
+ */
285
278
  module.exports.screenshotOutputFolder = function (fileName) {
286
279
  const fileSep = path.sep;
287
280
 
288
281
  if (!fileName.includes(fileSep) || fileName.includes('record_')) {
289
282
  return path.join(global.output_dir, fileName);
290
283
  }
291
- return path.join(global.codecept_dir, fileName);
284
+ return path.resolve(global.codecept_dir, fileName);
292
285
  };
293
286
 
294
287
  module.exports.beautify = function (code) {
package/lib/within.js CHANGED
@@ -6,6 +6,11 @@ const event = require('./event');
6
6
  const Step = require('./step');
7
7
  const { isAsyncFunction } = require('./utils');
8
8
 
9
+ /**
10
+ * @param {CodeceptJS.LocatorOrString} context
11
+ * @param {Function} fn
12
+ * @return {Promise<*> | undefined}
13
+ */
9
14
  function within(context, fn) {
10
15
  const helpers = store.dryRun ? {} : container.helpers();
11
16
  const locator = typeof context === 'object' ? JSON.stringify(context) : context;