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,14 +1,16 @@
1
- const { print, success, error } = require('../output');
2
1
  const colors = require('chalk');
3
2
  const fs = require('fs');
3
+ const inquirer = require('inquirer');
4
+ const mkdirp = require('mkdirp');
4
5
  const path = require('path');
6
+ const { inspect } = require('util');
7
+
8
+ const { print, success, error } = require('../output');
5
9
  const { fileExists, beautify } = require('../utils');
6
- const inquirer = require('inquirer');
7
10
  const { getTestRoot } = require('./utils');
8
11
  const generateDefinitions = require('./definitions');
12
+ const { test: generateTest } = require('./generate');
9
13
  const isLocal = require('../utils').installedLocally();
10
- const mkdirp = require('mkdirp');
11
- const { inspect } = require('util');
12
14
 
13
15
  const defaultConfig = {
14
16
  tests: './*_test.js',
@@ -27,8 +29,15 @@ translations.unshift(noTranslation);
27
29
 
28
30
  let packages;
29
31
 
30
- const defaultActor = `
31
- // in this file you can append custom step methods to 'I' object
32
+ const configHeader = `const { setHeadlessWhen } = require('@codeceptjs/configure');
33
+
34
+ // turn on headless mode when running with HEADLESS=true environment variable
35
+ // HEADLESS=true npx codecept run
36
+ setHeadlessWhen(process.env.HEADLESS);
37
+
38
+ `;
39
+
40
+ const defaultActor = `// in this file you can append custom step methods to 'I' object
32
41
 
33
42
  module.exports = function() {
34
43
  return actor({
@@ -88,21 +97,6 @@ module.exports = function (initPath) {
88
97
  default: './output',
89
98
  message: 'Where should logs, screenshots, and reports to be stored?',
90
99
  },
91
- {
92
- name: 'steps',
93
- type: 'confirm',
94
- message: 'Would you like to extend the "I" object with custom steps?',
95
- default: true,
96
- },
97
- {
98
- name: 'steps_file',
99
- type: 'input',
100
- message: 'Where would you like to place custom steps?',
101
- default: './steps_file.js',
102
- when(answers) {
103
- return answers.steps;
104
- },
105
- },
106
100
  {
107
101
  name: 'translation',
108
102
  type: 'list',
@@ -124,7 +118,7 @@ module.exports = function (initPath) {
124
118
  // append file mask to the end of tests
125
119
  if (!config.tests.match(/\*(.*?)$/)) {
126
120
  config.tests = `${config.tests.replace(/\/+$/, '')}/*_test.js`;
127
- console.print(`Adding default test mask: ${config.tests}`);
121
+ print(`Adding default test mask: ${config.tests}`);
128
122
  }
129
123
 
130
124
  if (result.translation !== noTranslation) config.translation = result.translation;
@@ -152,17 +146,29 @@ module.exports = function (initPath) {
152
146
  }
153
147
 
154
148
  const finish = () => {
155
- if (result.steps_file) {
156
- const stepFile = path.join(testsPath, result.steps_file);
157
- if (!fileExists(path.dirname(stepFile))) {
158
- mkdirp.sync(path.dirname(stepFile));
159
- }
160
- fs.writeFileSync(stepFile, defaultActor);
161
- config.include.I = result.steps_file;
162
- print(`Steps file created at ${stepFile}`);
149
+ // create steps file by default
150
+ const stepFile = './steps_file.js';
151
+ fs.writeFileSync(path.join(testsPath, stepFile), defaultActor);
152
+ config.include.I = stepFile;
153
+ print(`Steps file created at ${stepFile}`);
154
+
155
+ config.plugins = {
156
+ retryFailedStep: {
157
+ enabled: true,
158
+ },
159
+ screenshotOnFail: {
160
+ enabled: true,
161
+ },
162
+ };
163
+
164
+ let configSource = beautify(`exports.config = ${inspect(config, false, 4, false)}`);
165
+
166
+ if (require.resolve('@codeceptjs/configure') && isLocal && !initPath) {
167
+ // prepend @codeceptjs/configure only when this module can be required in config
168
+ configSource = configHeader + configSource;
163
169
  }
164
170
 
165
- fs.writeFileSync(configFile, beautify(`exports.config = ${inspect(config, false, 4, false)}`), 'utf-8');
171
+ fs.writeFileSync(configFile, configSource, 'utf-8');
166
172
  print(`Config created at ${configFile}`);
167
173
 
168
174
  if (config.output) {
@@ -174,7 +180,6 @@ module.exports = function (initPath) {
174
180
  }
175
181
  }
176
182
 
177
-
178
183
  const jsconfig = {
179
184
  compilerOption: {
180
185
  allowJs: true,
@@ -183,7 +188,7 @@ module.exports = function (initPath) {
183
188
  const jsconfigJson = beautify(JSON.stringify(jsconfig));
184
189
  const jsconfigFile = path.join(testsPath, 'jsconfig.json');
185
190
  if (fileExists(jsconfigFile)) {
186
- print(`jsconfig.json has already exists at ${jsconfigFile}`);
191
+ print(`jsconfig.json already exists at ${jsconfigFile}`);
187
192
  } else {
188
193
  fs.writeFileSync(jsconfigFile, jsconfigJson);
189
194
  print(`Intellisense enabled in ${jsconfigFile}`);
@@ -192,17 +197,25 @@ module.exports = function (initPath) {
192
197
  generateDefinitions(testsPath, {});
193
198
 
194
199
  print('');
195
- success(' Almost done! Next step:');
196
- success(' Create your first test by executing `npx codeceptjs gt` command ');
200
+ success(' Almost ready... Next step:');
201
+
197
202
 
198
- if (packages) {
203
+ const generatedTest = generateTest(testsPath);
204
+ if (!generatedTest) return;
205
+ generatedTest.then(() => {
199
206
  print('\n--');
200
- if (isLocal) {
201
- success(`Please install dependent packages locally: ${colors.bold(`npm install --save-dev ${packages.join(' ')}`)}`);
202
- } else {
203
- success(`Please install dependent packages globally: [sudo] ${colors.bold(`npm install -g ${packages.join(' ')}`)}`);
207
+ print(colors.bold.green('CodeceptJS Installed! Enjoy supercharged testing! 🤩'));
208
+ print(colors.bold.magenta('Find more information at https://codecept.io'));
209
+ print();
210
+ if (packages) {
211
+ print('\n--');
212
+ if (isLocal) {
213
+ success(`Please install dependent packages locally: ${colors.bold(`npm install --save-dev ${packages.join(' ')}`)}`);
214
+ } else {
215
+ success(`Please install dependent packages globally: [sudo] ${colors.bold(`npm install -g ${packages.join(' ')}`)}`);
216
+ }
204
217
  }
205
- }
218
+ });
206
219
  };
207
220
 
208
221
  print('Configure helpers...');
@@ -1,14 +1,15 @@
1
- const {
2
- getConfig, getTestRoot, fail,
3
- } = require('./utils');
4
1
  const fork = require('child_process').fork;
5
2
  const path = require('path');
6
3
  const crypto = require('crypto');
4
+
7
5
  const runHook = require('../hooks');
8
6
  const event = require('../event');
9
7
  const collection = require('./run-multiple/collection');
10
8
  const clearString = require('../utils').clearString;
11
9
  const replaceValueDeep = require('../utils').replaceValueDeep;
10
+ const {
11
+ getConfig, getTestRoot, fail,
12
+ } = require('./utils');
12
13
 
13
14
  const runner = path.join(__dirname, '/../../bin/codecept');
14
15
  let config;
@@ -113,7 +114,7 @@ module.exports = function (selectedRuns, options) {
113
114
 
114
115
  function executeRun(runName, runConfig) {
115
116
  // clone config
116
- let overriddenConfig = Object.assign({}, config);
117
+ let overriddenConfig = { ...config };
117
118
 
118
119
  // get configuration
119
120
  const browserConfig = runConfig.browser;
@@ -0,0 +1,39 @@
1
+ const getConfig = require('./utils').getConfig;
2
+ const getTestRoot = require('./utils').getTestRoot;
3
+ const printError = require('./utils').printError;
4
+ const createOutputDir = require('./utils').createOutputDir;
5
+ const Config = require('../config');
6
+ const Codecept = require('../rerun');
7
+
8
+ module.exports = function (test, options) {
9
+ // registering options globally to use in config
10
+ process.profile = options.profile;
11
+ const configFile = options.config;
12
+ let codecept;
13
+
14
+ let config = getConfig(configFile);
15
+ if (options.override) {
16
+ config = Config.append(JSON.parse(options.override));
17
+ }
18
+ const testRoot = getTestRoot(configFile);
19
+ createOutputDir(config, testRoot);
20
+
21
+ function processError(err) {
22
+ printError(err);
23
+ process.exit(1);
24
+ }
25
+
26
+ try {
27
+ codecept = new Codecept(config, options);
28
+ codecept.init(testRoot);
29
+
30
+ codecept.runBootstrap((err) => {
31
+ if (err) throw new Error(`Error while running bootstrap file :${err}`);
32
+
33
+ codecept.loadTests();
34
+ codecept.run(test).catch(processError);
35
+ });
36
+ } catch (err) {
37
+ processError(err);
38
+ }
39
+ };
@@ -1,15 +1,15 @@
1
- const { satisfyNodeVersion, getConfig, getTestRoot } = require('./utils');
2
1
  // For Node version >=10.5.0, have to use experimental flag
3
2
 
4
- const ms = require('ms');
3
+ const { Suite, Test, reporters: { Base } } = require('mocha');
5
4
  const path = require('path');
5
+
6
+ const { satisfyNodeVersion, getConfig, getTestRoot } = require('./utils');
6
7
  const Codecept = require('../codecept');
7
8
  const Container = require('../container');
8
9
  const { tryOrDefault } = require('../utils');
9
10
  const output = require('../output');
10
11
  const event = require('../event');
11
12
  const runHook = require('../hooks');
12
- const { Suite, Test, reporters: { Base } } = require('mocha');
13
13
 
14
14
  const stats = {
15
15
  suites: 0,
@@ -46,8 +46,6 @@ module.exports = function (workers, options) {
46
46
  };
47
47
 
48
48
  const testRoot = getTestRoot(configPath);
49
- config.tests = path.resolve(testRoot, config.tests);
50
-
51
49
 
52
50
  const codecept = new Codecept(config, options);
53
51
  codecept.init(testRoot);
@@ -121,7 +119,7 @@ function printResults() {
121
119
  stats.end = new Date();
122
120
  stats.duration = stats.end - stats.start;
123
121
  output.print();
124
- if (stats.passes && !errors.length) {
122
+ if (stats.tests === 0 || (stats.passes && !errors.length)) {
125
123
  output.result(stats.passes, stats.failures, 0, `${stats.duration / 1000}s`);
126
124
  }
127
125
  if (stats.failures) {
@@ -1,32 +1,25 @@
1
+ const mkdirp = require('mkdirp');
2
+ const path = require('path');
3
+
1
4
  const getConfig = require('./utils').getConfig;
2
5
  const getTestRoot = require('./utils').getTestRoot;
3
- const fileExists = require('../utils').fileExists;
4
- const path = require('path');
5
- const mkdirp = require('mkdirp');
6
+ const printError = require('./utils').printError;
7
+ const createOutputDir = require('./utils').createOutputDir;
6
8
  const Config = require('../config');
7
9
  const Codecept = require('../codecept');
8
- const output = require('../output');
9
10
 
10
11
  module.exports = function (test, options) {
11
12
  // registering options globally to use in config
12
13
  process.profile = options.profile;
13
14
  const configFile = options.config;
14
15
  let codecept;
15
- let outputDir;
16
16
 
17
- const testRoot = getTestRoot(configFile);
18
17
  let config = getConfig(configFile);
19
18
  if (options.override) {
20
19
  config = Config.append(JSON.parse(options.override));
21
20
  }
22
-
23
- if (path.isAbsolute(config.output)) outputDir = config.output;
24
- else outputDir = path.join(testRoot, config.output);
25
-
26
- if (!fileExists(outputDir)) {
27
- output.print(`creating output directory: ${outputDir}`);
28
- mkdirp.sync(outputDir);
29
- }
21
+ const testRoot = getTestRoot(configFile);
22
+ createOutputDir(config, testRoot);
30
23
 
31
24
  try {
32
25
  codecept = new Codecept(config, options);
@@ -39,10 +32,7 @@ module.exports = function (test, options) {
39
32
  codecept.run(test);
40
33
  });
41
34
  } catch (err) {
42
- output.print('');
43
- output.error(err.message);
44
- output.print('');
45
- output.print(output.colors.grey(err.stack.replace(err.message, '')));
35
+ printError(err);
46
36
  process.exit(1);
47
37
  }
48
38
  };
@@ -1,9 +1,12 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const semver = require('semver');
4
+ const util = require('util');
5
+ const mkdirp = require('mkdirp');
6
+
3
7
  const output = require('../output');
4
8
  const { fileExists, beautify } = require('../utils');
5
- const util = require('util');
6
- const semver = require('semver');
9
+
7
10
 
8
11
  // alias to deep merge
9
12
  module.exports.deepMerge = require('../utils').deepMerge;
@@ -84,3 +87,21 @@ module.exports.captureStream = (stream) => {
84
87
  getData: () => buffer,
85
88
  };
86
89
  };
90
+
91
+ module.exports.printError = (err) => {
92
+ output.print('');
93
+ output.error(err.message);
94
+ output.print('');
95
+ output.print(output.colors.grey(err.stack.replace(err.message, '')));
96
+ };
97
+
98
+ module.exports.createOutputDir = (config, testRoot) => {
99
+ let outputDir;
100
+ if (path.isAbsolute(config.output)) outputDir = config.output;
101
+ else outputDir = path.join(testRoot, config.output);
102
+
103
+ if (!fileExists(outputDir)) {
104
+ output.print(`creating output directory: ${outputDir}`);
105
+ mkdirp.sync(outputDir);
106
+ }
107
+ };
@@ -20,7 +20,7 @@ const stderr = '';
20
20
 
21
21
 
22
22
  // Requiring of Codecept need to be after tty.getWindowSize is available.
23
- const Codecept = require('../../codecept');
23
+ const Codecept = require(process.env.CODECEPT_CLASS_PATH || '../../codecept');
24
24
 
25
25
  const {
26
26
  options, tests, testRoot, workerIndex,
@@ -30,7 +30,6 @@ const {
30
30
  if (!options.debug && !options.verbose) process.stdout.write = (string, encoding, fd) => { stdout += string; return true; };
31
31
 
32
32
  const config = getConfig(options.config || testRoot);
33
- config.tests = path.resolve(testRoot, config.tests);
34
33
 
35
34
  // Load test and run
36
35
  const codecept = new Codecept(config, options);
package/lib/config.js CHANGED
@@ -34,6 +34,7 @@ class Config {
34
34
  * Create a config with default options
35
35
  *
36
36
  * @param {*} newConfig
37
+ * @return {Object<string, *>}
37
38
  */
38
39
  static create(newConfig) {
39
40
  config = deepMerge(deepClone(defaultConfig), newConfig);
@@ -50,7 +51,8 @@ class Config {
50
51
  * * try to load `codecept.json` from it
51
52
  * If none of above: fail.
52
53
  *
53
- * @param {*} configFile
54
+ * @param {string} configFile
55
+ * @return {*}
54
56
  */
55
57
  static load(configFile) {
56
58
  configFile = path.resolve(configFile || '.');
@@ -81,6 +83,9 @@ class Config {
81
83
 
82
84
  /**
83
85
  * Get current config.
86
+ * @param {string} key
87
+ * @param {*} val
88
+ * @return {*}
84
89
  */
85
90
  static get(key, val) {
86
91
  if (key) {
@@ -96,7 +101,8 @@ class Config {
96
101
  /**
97
102
  * Appends values to current config
98
103
  *
99
- * @param {*} additionalConfig
104
+ * @param {Object<string, *>} additionalConfig
105
+ * @return {Object<string, *>}
100
106
  */
101
107
  static append(additionalConfig) {
102
108
  return config = deepMerge(config, additionalConfig);
@@ -104,10 +110,11 @@ class Config {
104
110
 
105
111
  /**
106
112
  * Resets config to default
113
+ * @return {Object<string, *>}
107
114
  */
108
115
  static reset() {
109
116
  hooks = [];
110
- return config = Object.assign({}, defaultConfig);
117
+ return config = { ...defaultConfig };
111
118
  }
112
119
  }
113
120
 
@@ -125,4 +132,3 @@ function loadConfigFile(configFile) {
125
132
  }
126
133
  throw new Error(`Config file ${configFile} can't be loaded`);
127
134
  }
128
-
package/lib/container.js CHANGED
@@ -1,4 +1,6 @@
1
+ const glob = require('glob');
1
2
  const path = require('path');
3
+
2
4
  const fileExists = require('./utils').fileExists;
3
5
  const Translation = require('./translation');
4
6
  const MochaFactory = require('./mochaFactory');
@@ -9,6 +11,10 @@ let container = {
9
11
  helpers: {},
10
12
  support: {},
11
13
  plugins: {},
14
+ /**
15
+ * @type {Mocha | {}}
16
+ * @ignore
17
+ */
12
18
  mocha: {},
13
19
  translation: {},
14
20
  };
@@ -29,7 +35,10 @@ class Container {
29
35
  if (config.grep && !opts.grep) {
30
36
  mochaConfig.grep = config.grep;
31
37
  }
32
- container.mocha = MochaFactory.create(mochaConfig, opts || {});
38
+ this.createMocha = () => {
39
+ container.mocha = MochaFactory.create(mochaConfig, opts || {});
40
+ };
41
+ this.createMocha();
33
42
  container.helpers = createHelpers(config.helpers || {});
34
43
  container.translation = loadTranslation(config.translation || null);
35
44
  container.support = createSupportObjects(config.include || {});
@@ -55,6 +64,7 @@ class Container {
55
64
  *
56
65
  * @api
57
66
  * @param {string} [name]
67
+ * @returns { * }
58
68
  */
59
69
  static support(name) {
60
70
  if (!name) {
@@ -89,6 +99,7 @@ class Container {
89
99
  * Get Mocha instance
90
100
  *
91
101
  * @api
102
+ * @returns {Mocha | {}}
92
103
  */
93
104
  static mocha() {
94
105
  return container.mocha;
@@ -98,6 +109,7 @@ class Container {
98
109
  * Append new services to container
99
110
  *
100
111
  * @api
112
+ * @param {Object<string, *>} newContainer
101
113
  */
102
114
  static append(newContainer) {
103
115
  const deepMerge = require('./utils').deepMerge;
@@ -107,8 +119,9 @@ class Container {
107
119
  /**
108
120
  * Clear container
109
121
  *
110
- * @param {*} newHelpers
111
- * @param {*} newSupport
122
+ * @param {Object<string, *>} newHelpers
123
+ * @param {Object<string, *>} newSupport
124
+ * @param {Object<string, *>} newPlugins
112
125
  */
113
126
  static clear(newHelpers, newSupport, newPlugins) {
114
127
  container.helpers = newHelpers || {};
@@ -278,8 +291,20 @@ function loadGherkinSteps(paths) {
278
291
  global.After = fn => event.dispatcher.on(event.test.finished, fn);
279
292
  global.Fail = fn => event.dispatcher.on(event.test.failed, fn);
280
293
 
281
- for (const path of paths) {
282
- loadSupportObject(path, `Step Definition from ${path}`);
294
+ // If gherkin.steps is string, then this will iterate through that folder and send all step def js files to loadSupportObject
295
+ // If gherkin.steps is Array, it will go the old way
296
+ // This is done so that we need not enter all Step Definition files under config.gherkin.steps
297
+ if (Array.isArray(paths)) {
298
+ for (const path of paths) {
299
+ loadSupportObject(path, `Step Definition from ${path}`);
300
+ }
301
+ } else {
302
+ const folderPath = paths.startsWith('.') ? path.join(global.codecept_dir, paths) : '';
303
+ if (folderPath !== '') {
304
+ glob.sync(folderPath).forEach((file) => {
305
+ loadSupportObject(file, `Step Definition from ${file}`);
306
+ });
307
+ }
283
308
  }
284
309
 
285
310
  delete global.Before;
@@ -339,7 +364,7 @@ function loadTranslation(translation) {
339
364
  if (require('../translations')[translation]) {
340
365
  vocabulary = require('../translations')[translation];
341
366
  return new Translation(vocabulary);
342
- } else if (fileExists(path.join(global.codecept_dir, translation))) {
367
+ } if (fileExists(path.join(global.codecept_dir, translation))) {
343
368
  // get from a provided file instead
344
369
  vocabulary = require(path.join(global.codecept_dir, translation));
345
370
  } else {
@@ -0,0 +1,31 @@
1
+ class DataTableArgument {
2
+ constructor(gherkinDataTable) {
3
+ this.rawData = gherkinDataTable.rows.map((row) => {
4
+ return row.cells.map((cell) => {
5
+ return cell.value;
6
+ });
7
+ });
8
+ }
9
+
10
+ raw() {
11
+ return this.rawData.slice(0);
12
+ }
13
+
14
+ rows() {
15
+ const copy = this.raw();
16
+ copy.shift();
17
+ return copy;
18
+ }
19
+
20
+ hashes() {
21
+ const copy = this.raw();
22
+ const header = copy.shift();
23
+ return copy.map((row) => {
24
+ const r = {};
25
+ row.forEach((cell, index) => r[header[index]] = cell);
26
+ return r;
27
+ });
28
+ }
29
+ }
30
+
31
+ module.exports = DataTableArgument;
package/lib/data/table.js CHANGED
@@ -2,11 +2,13 @@
2
2
  * Datatable class to provide data driven testing
3
3
  */
4
4
  class DataTable {
5
+ /** @param {Array<*>} array */
5
6
  constructor(array) {
6
7
  this.array = array;
7
8
  this.rows = new Array(0);
8
9
  }
9
10
 
11
+ /** @param {Array<*>} array */
10
12
  add(array) {
11
13
  if (array.length !== this.array.length) throw new Error(`There is too many elements in given data array. Please provide data in this format: ${this.array}`);
12
14
  const tempObj = {};
@@ -19,6 +21,7 @@ class DataTable {
19
21
  this.rows.push({ skip: false, data: tempObj });
20
22
  }
21
23
 
24
+ /** @param {Array<*>} array */
22
25
  xadd(array) {
23
26
  if (array.length !== this.array.length) throw new Error(`There is too many elements in given data array. Please provide data in this format: ${this.array}`);
24
27
  const tempObj = {};
@@ -31,6 +34,7 @@ class DataTable {
31
34
  this.rows.push({ skip: true, data: tempObj });
32
35
  }
33
36
 
37
+ /** @param {Function} func */
34
38
  filter(func) {
35
39
  return this.rows.filter(row => func(row.data));
36
40
  }