codeceptjs 3.4.1 → 3.5.1-2.beta.7

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 (281) hide show
  1. package/README.md +31 -30
  2. package/bin/codecept.js +1 -1
  3. package/lib/actor.js +6 -3
  4. package/lib/ai.js +180 -0
  5. package/lib/cli.js +13 -3
  6. package/lib/codecept.js +8 -0
  7. package/lib/colorUtils.js +10 -0
  8. package/lib/command/definitions.js +2 -7
  9. package/lib/command/dryRun.js +11 -2
  10. package/lib/command/generate.js +46 -3
  11. package/lib/command/info.js +24 -0
  12. package/lib/command/init.js +64 -6
  13. package/lib/command/interactive.js +15 -1
  14. package/lib/command/run-multiple/collection.js +17 -5
  15. package/lib/command/run-multiple.js +4 -2
  16. package/lib/command/run-workers.js +68 -5
  17. package/lib/command/run.js +7 -0
  18. package/lib/command/workers/runTests.js +39 -0
  19. package/lib/container.js +13 -3
  20. package/lib/data/context.js +14 -6
  21. package/lib/event.js +4 -0
  22. package/lib/helper/ApiDataFactory.js +2 -1
  23. package/lib/helper/Appium.js +116 -29
  24. package/lib/helper/Expect.js +422 -0
  25. package/lib/helper/FileSystem.js +1 -1
  26. package/lib/helper/GraphQL.js +25 -0
  27. package/lib/helper/JSONResponse.js +4 -4
  28. package/lib/helper/Nightmare.js +10 -5
  29. package/lib/helper/OpenAI.js +126 -0
  30. package/lib/helper/Playwright.js +1298 -229
  31. package/lib/helper/Protractor.js +12 -7
  32. package/lib/helper/Puppeteer.js +204 -64
  33. package/lib/helper/REST.js +15 -5
  34. package/lib/helper/TestCafe.js +45 -10
  35. package/lib/helper/WebDriver.js +252 -83
  36. package/lib/helper/errors/ElementNotFound.js +2 -1
  37. package/lib/helper/extras/PlaywrightReactVueLocator.js +38 -0
  38. package/lib/helper/scripts/blurElement.js +17 -0
  39. package/lib/helper/scripts/focusElement.js +17 -0
  40. package/lib/helper/scripts/highlightElement.js +20 -0
  41. package/lib/html.js +258 -0
  42. package/lib/interfaces/bdd.js +1 -1
  43. package/lib/interfaces/gherkin.js +37 -3
  44. package/lib/interfaces/scenarioConfig.js +1 -0
  45. package/lib/listener/retry.js +2 -1
  46. package/lib/locator.js +17 -4
  47. package/lib/mochaFactory.js +2 -1
  48. package/lib/output.js +1 -1
  49. package/lib/pause.js +78 -19
  50. package/lib/plugin/autoLogin.js +45 -10
  51. package/lib/plugin/debugErrors.js +67 -0
  52. package/lib/plugin/fakerTransform.js +4 -6
  53. package/lib/plugin/heal.js +209 -0
  54. package/lib/plugin/retryFailedStep.js +10 -1
  55. package/lib/plugin/retryTo.js +2 -4
  56. package/lib/plugin/screenshotOnFail.js +11 -2
  57. package/lib/plugin/selenoid.js +6 -1
  58. package/lib/plugin/standardActingHelpers.js +0 -2
  59. package/lib/plugin/stepByStepReport.js +2 -2
  60. package/lib/plugin/tryTo.js +5 -7
  61. package/lib/plugin/wdio.js +0 -1
  62. package/lib/recorder.js +22 -11
  63. package/lib/secret.js +5 -4
  64. package/lib/session.js +1 -1
  65. package/lib/step.js +36 -12
  66. package/lib/ui.js +5 -3
  67. package/lib/utils.js +22 -1
  68. package/lib/workers.js +83 -10
  69. package/package.json +117 -95
  70. package/translations/de-DE.js +5 -0
  71. package/translations/fr-FR.js +14 -1
  72. package/translations/it-IT.js +1 -0
  73. package/translations/ja-JP.js +14 -9
  74. package/translations/pl-PL.js +5 -0
  75. package/translations/pt-BR.js +1 -0
  76. package/translations/ru-RU.js +1 -0
  77. package/translations/zh-CN.js +5 -0
  78. package/translations/zh-TW.js +5 -0
  79. package/typings/index.d.ts +51 -15
  80. package/typings/promiseBasedTypes.d.ts +864 -802
  81. package/typings/types.d.ts +1339 -744
  82. package/CHANGELOG.md +0 -2427
  83. package/docs/advanced.md +0 -351
  84. package/docs/api.md +0 -323
  85. package/docs/basics.md +0 -980
  86. package/docs/bdd.md +0 -535
  87. package/docs/best.md +0 -237
  88. package/docs/books.md +0 -37
  89. package/docs/bootstrap.md +0 -135
  90. package/docs/build/ApiDataFactory.js +0 -409
  91. package/docs/build/Appium.js +0 -1938
  92. package/docs/build/FileSystem.js +0 -228
  93. package/docs/build/GraphQL.js +0 -204
  94. package/docs/build/GraphQLDataFactory.js +0 -309
  95. package/docs/build/JSONResponse.js +0 -338
  96. package/docs/build/Mochawesome.js +0 -71
  97. package/docs/build/Nightmare.js +0 -2145
  98. package/docs/build/Playwright.js +0 -3986
  99. package/docs/build/Polly.js +0 -42
  100. package/docs/build/Protractor.js +0 -2699
  101. package/docs/build/Puppeteer.js +0 -3710
  102. package/docs/build/REST.js +0 -334
  103. package/docs/build/SeleniumWebdriver.js +0 -76
  104. package/docs/build/TestCafe.js +0 -2057
  105. package/docs/build/WebDriver.js +0 -4017
  106. package/docs/changelog.md +0 -2436
  107. package/docs/commands.md +0 -254
  108. package/docs/community-helpers.md +0 -58
  109. package/docs/configuration.md +0 -157
  110. package/docs/continuous-integration.md +0 -22
  111. package/docs/custom-helpers.md +0 -306
  112. package/docs/data.md +0 -375
  113. package/docs/detox.md +0 -235
  114. package/docs/docker.md +0 -137
  115. package/docs/email.md +0 -183
  116. package/docs/examples.md +0 -149
  117. package/docs/helpers/ApiDataFactory.md +0 -266
  118. package/docs/helpers/Appium.md +0 -1312
  119. package/docs/helpers/Detox.md +0 -586
  120. package/docs/helpers/FileSystem.md +0 -152
  121. package/docs/helpers/GraphQL.md +0 -130
  122. package/docs/helpers/GraphQLDataFactory.md +0 -226
  123. package/docs/helpers/JSONResponse.md +0 -254
  124. package/docs/helpers/Mochawesome.md +0 -8
  125. package/docs/helpers/MockRequest.md +0 -377
  126. package/docs/helpers/Nightmare.md +0 -1256
  127. package/docs/helpers/Playwright.md +0 -2208
  128. package/docs/helpers/Polly.md +0 -44
  129. package/docs/helpers/Puppeteer-firefox.md +0 -86
  130. package/docs/helpers/Puppeteer.md +0 -2141
  131. package/docs/helpers/REST.md +0 -217
  132. package/docs/helpers/TestCafe.md +0 -1222
  133. package/docs/helpers/WebDriver.md +0 -2319
  134. package/docs/hooks.md +0 -340
  135. package/docs/index.md +0 -111
  136. package/docs/installation.md +0 -75
  137. package/docs/internal-api.md +0 -265
  138. package/docs/locators.md +0 -331
  139. package/docs/mobile-react-native-locators.md +0 -67
  140. package/docs/mobile.md +0 -297
  141. package/docs/nightmare.md +0 -223
  142. package/docs/pageobjects.md +0 -291
  143. package/docs/parallel.md +0 -232
  144. package/docs/playwright.md +0 -609
  145. package/docs/plugins.md +0 -1171
  146. package/docs/puppeteer.md +0 -316
  147. package/docs/quickstart.md +0 -163
  148. package/docs/react.md +0 -69
  149. package/docs/reports.md +0 -392
  150. package/docs/secrets.md +0 -30
  151. package/docs/shadow.md +0 -68
  152. package/docs/shared/keys.mustache +0 -31
  153. package/docs/shared/react.mustache +0 -1
  154. package/docs/testcafe.md +0 -174
  155. package/docs/translation.md +0 -247
  156. package/docs/tutorial.md +0 -271
  157. package/docs/typescript.md +0 -180
  158. package/docs/ui.md +0 -59
  159. package/docs/videos.md +0 -28
  160. package/docs/visual.md +0 -202
  161. package/docs/vue.md +0 -121
  162. package/docs/webapi/amOnPage.mustache +0 -11
  163. package/docs/webapi/appendField.mustache +0 -9
  164. package/docs/webapi/attachFile.mustache +0 -12
  165. package/docs/webapi/checkOption.mustache +0 -13
  166. package/docs/webapi/clearCookie.mustache +0 -10
  167. package/docs/webapi/clearField.mustache +0 -9
  168. package/docs/webapi/click.mustache +0 -25
  169. package/docs/webapi/clickLink.mustache +0 -8
  170. package/docs/webapi/closeCurrentTab.mustache +0 -7
  171. package/docs/webapi/closeOtherTabs.mustache +0 -8
  172. package/docs/webapi/dontSee.mustache +0 -11
  173. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
  174. package/docs/webapi/dontSeeCookie.mustache +0 -8
  175. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
  176. package/docs/webapi/dontSeeElement.mustache +0 -8
  177. package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
  178. package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
  179. package/docs/webapi/dontSeeInField.mustache +0 -11
  180. package/docs/webapi/dontSeeInSource.mustache +0 -8
  181. package/docs/webapi/dontSeeInTitle.mustache +0 -8
  182. package/docs/webapi/doubleClick.mustache +0 -13
  183. package/docs/webapi/downloadFile.mustache +0 -12
  184. package/docs/webapi/dragAndDrop.mustache +0 -9
  185. package/docs/webapi/dragSlider.mustache +0 -11
  186. package/docs/webapi/executeAsyncScript.mustache +0 -24
  187. package/docs/webapi/executeScript.mustache +0 -26
  188. package/docs/webapi/fillField.mustache +0 -16
  189. package/docs/webapi/forceClick.mustache +0 -28
  190. package/docs/webapi/forceRightClick.mustache +0 -18
  191. package/docs/webapi/grabAllWindowHandles.mustache +0 -7
  192. package/docs/webapi/grabAttributeFrom.mustache +0 -10
  193. package/docs/webapi/grabAttributeFromAll.mustache +0 -9
  194. package/docs/webapi/grabBrowserLogs.mustache +0 -9
  195. package/docs/webapi/grabCookie.mustache +0 -11
  196. package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
  197. package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
  198. package/docs/webapi/grabCurrentUrl.mustache +0 -9
  199. package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
  200. package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
  201. package/docs/webapi/grabElementBoundingRect.mustache +0 -20
  202. package/docs/webapi/grabGeoLocation.mustache +0 -8
  203. package/docs/webapi/grabHTMLFrom.mustache +0 -10
  204. package/docs/webapi/grabHTMLFromAll.mustache +0 -9
  205. package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
  206. package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
  207. package/docs/webapi/grabPageScrollPosition.mustache +0 -8
  208. package/docs/webapi/grabPopupText.mustache +0 -5
  209. package/docs/webapi/grabSource.mustache +0 -8
  210. package/docs/webapi/grabTextFrom.mustache +0 -10
  211. package/docs/webapi/grabTextFromAll.mustache +0 -9
  212. package/docs/webapi/grabTitle.mustache +0 -8
  213. package/docs/webapi/grabValueFrom.mustache +0 -9
  214. package/docs/webapi/grabValueFromAll.mustache +0 -8
  215. package/docs/webapi/moveCursorTo.mustache +0 -12
  216. package/docs/webapi/openNewTab.mustache +0 -7
  217. package/docs/webapi/pressKey.mustache +0 -12
  218. package/docs/webapi/pressKeyDown.mustache +0 -12
  219. package/docs/webapi/pressKeyUp.mustache +0 -12
  220. package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
  221. package/docs/webapi/refreshPage.mustache +0 -6
  222. package/docs/webapi/resizeWindow.mustache +0 -6
  223. package/docs/webapi/rightClick.mustache +0 -14
  224. package/docs/webapi/saveElementScreenshot.mustache +0 -10
  225. package/docs/webapi/saveScreenshot.mustache +0 -12
  226. package/docs/webapi/say.mustache +0 -10
  227. package/docs/webapi/scrollIntoView.mustache +0 -11
  228. package/docs/webapi/scrollPageToBottom.mustache +0 -6
  229. package/docs/webapi/scrollPageToTop.mustache +0 -6
  230. package/docs/webapi/scrollTo.mustache +0 -12
  231. package/docs/webapi/see.mustache +0 -11
  232. package/docs/webapi/seeAttributesOnElements.mustache +0 -9
  233. package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
  234. package/docs/webapi/seeCookie.mustache +0 -8
  235. package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
  236. package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
  237. package/docs/webapi/seeElement.mustache +0 -8
  238. package/docs/webapi/seeElementInDOM.mustache +0 -8
  239. package/docs/webapi/seeInCurrentUrl.mustache +0 -8
  240. package/docs/webapi/seeInField.mustache +0 -12
  241. package/docs/webapi/seeInPopup.mustache +0 -8
  242. package/docs/webapi/seeInSource.mustache +0 -7
  243. package/docs/webapi/seeInTitle.mustache +0 -8
  244. package/docs/webapi/seeNumberOfElements.mustache +0 -11
  245. package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
  246. package/docs/webapi/seeTextEquals.mustache +0 -9
  247. package/docs/webapi/seeTitleEquals.mustache +0 -8
  248. package/docs/webapi/selectOption.mustache +0 -21
  249. package/docs/webapi/setCookie.mustache +0 -16
  250. package/docs/webapi/setGeoLocation.mustache +0 -12
  251. package/docs/webapi/switchTo.mustache +0 -9
  252. package/docs/webapi/switchToNextTab.mustache +0 -10
  253. package/docs/webapi/switchToPreviousTab.mustache +0 -10
  254. package/docs/webapi/type.mustache +0 -18
  255. package/docs/webapi/uncheckOption.mustache +0 -13
  256. package/docs/webapi/wait.mustache +0 -8
  257. package/docs/webapi/waitForClickable.mustache +0 -11
  258. package/docs/webapi/waitForDetached.mustache +0 -10
  259. package/docs/webapi/waitForElement.mustache +0 -11
  260. package/docs/webapi/waitForEnabled.mustache +0 -6
  261. package/docs/webapi/waitForFunction.mustache +0 -17
  262. package/docs/webapi/waitForInvisible.mustache +0 -10
  263. package/docs/webapi/waitForText.mustache +0 -13
  264. package/docs/webapi/waitForValue.mustache +0 -10
  265. package/docs/webapi/waitForVisible.mustache +0 -10
  266. package/docs/webapi/waitInUrl.mustache +0 -9
  267. package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
  268. package/docs/webapi/waitToHide.mustache +0 -10
  269. package/docs/webapi/waitUrlEquals.mustache +0 -10
  270. package/docs/webdriver.md +0 -657
  271. package/docs/wiki/Books-&-Posts.md +0 -27
  272. package/docs/wiki/Community-Helpers-&-Plugins.md +0 -49
  273. package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -29
  274. package/docs/wiki/Examples.md +0 -139
  275. package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -68
  276. package/docs/wiki/Home.md +0 -16
  277. package/docs/wiki/Release-Process.md +0 -24
  278. package/docs/wiki/Roadmap.md +0 -23
  279. package/docs/wiki/Tests.md +0 -1393
  280. package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -153
  281. package/docs/wiki/Videos.md +0 -19
@@ -37,3 +37,27 @@ module.exports = async function (path) {
37
37
  output.print('Please copy environment info when you report issues on GitHub: https://github.com/Codeception/CodeceptJS/issues');
38
38
  output.print('***************************************');
39
39
  };
40
+
41
+ module.exports.getMachineInfo = async () => {
42
+ const info = {
43
+ nodeInfo: await envinfo.helpers.getNodeInfo(),
44
+ osInfo: await envinfo.helpers.getOSInfo(),
45
+ cpuInfo: await envinfo.helpers.getCPUInfo(),
46
+ chromeInfo: await envinfo.helpers.getChromeInfo(),
47
+ edgeInfo: await envinfo.helpers.getEdgeInfo(),
48
+ firefoxInfo: await envinfo.helpers.getFirefoxInfo(),
49
+ safariInfo: await envinfo.helpers.getSafariInfo(),
50
+ };
51
+
52
+ output.print('***************************************');
53
+ for (const [key, value] of Object.entries(info)) {
54
+ if (Array.isArray(value)) {
55
+ output.print(`${key}: ${value[1]}`);
56
+ } else {
57
+ output.print(`${key}: ${JSON.stringify(value, null, ' ')}`);
58
+ }
59
+ }
60
+ output.print('If you need more detailed info, just run this: npx codeceptjs info');
61
+ output.print('***************************************');
62
+ return info;
63
+ };
@@ -20,7 +20,7 @@ const defaultConfig = {
20
20
  include: {},
21
21
  };
22
22
 
23
- const helpers = ['Playwright', 'WebDriver', 'Puppeteer', 'REST', 'GraphQL', 'Appium', 'TestCafe', 'Nightmare'];
23
+ const helpers = ['Playwright', 'WebDriver', 'Puppeteer', 'REST', 'GraphQL', 'Appium', 'TestCafe'];
24
24
  const translations = Object.keys(require('../../translations'));
25
25
 
26
26
  const noTranslation = 'English (no localization)';
@@ -55,6 +55,18 @@ module.exports = function() {
55
55
  }
56
56
  `;
57
57
 
58
+ const defaultActorTs = `// in this file you can append custom step methods to 'I' object
59
+
60
+ export = function() {
61
+ return actor({
62
+
63
+ // Define custom steps here, use 'this' to access default methods of I.
64
+ // It is recommended to place a general 'login' function here.
65
+
66
+ });
67
+ }
68
+ `;
69
+
58
70
  module.exports = function (initPath) {
59
71
  const testsPath = getTestRoot(initPath);
60
72
 
@@ -188,8 +200,14 @@ module.exports = function (initPath) {
188
200
  // create steps file by default
189
201
  // no extra step file for typescript (as it doesn't match TS conventions)
190
202
  const stepFile = `./steps_file.${extension}`;
191
- fs.writeFileSync(path.join(testsPath, stepFile), defaultActor);
192
- config.include.I = isTypeScript === true ? './steps_file' : stepFile;
203
+ fs.writeFileSync(path.join(testsPath, stepFile), extension === 'ts' ? defaultActorTs : defaultActor);
204
+
205
+ if (isTypeScript) {
206
+ config.include = _actorTranslation('./steps_file', config.translation);
207
+ } else {
208
+ config.include = _actorTranslation(stepFile, config.translation);
209
+ }
210
+
193
211
  print(`Steps file created at ${stepFile}`);
194
212
 
195
213
  let configSource;
@@ -304,7 +322,17 @@ module.exports = function (initPath) {
304
322
  };
305
323
 
306
324
  print('Configure helpers...');
307
- inquirer.prompt(helperConfigs).then((helperResult) => {
325
+ inquirer.prompt(helperConfigs).then(async (helperResult) => {
326
+ if (helperResult.Playwright_browser === 'electron') {
327
+ delete helperResult.Playwright_url;
328
+ delete helperResult.Playwright_show;
329
+
330
+ helperResult.Playwright_electron = {
331
+ executablePath: '// require("electron") or require("electron-forge")',
332
+ args: ['path/to/your/main.js'],
333
+ };
334
+ }
335
+
308
336
  Object.keys(helperResult).forEach((key) => {
309
337
  const parts = key.split('_');
310
338
  const helperName = parts[0];
@@ -314,12 +342,12 @@ module.exports = function (initPath) {
314
342
  });
315
343
 
316
344
  print('');
317
- finish();
345
+ await finish();
318
346
  });
319
347
  });
320
348
  };
321
349
 
322
- function install(dependencies, verbose) {
350
+ function install(dependencies) {
323
351
  let command;
324
352
  let args;
325
353
 
@@ -352,9 +380,39 @@ function install(dependencies, verbose) {
352
380
  ].concat(dependencies);
353
381
  }
354
382
 
383
+ if (process.env._INIT_DRY_RUN_INSTALL) {
384
+ args.push('--dry-run');
385
+ }
386
+
355
387
  const { status } = spawn.sync(command, args, { stdio: 'inherit' });
356
388
  if (status !== 0) {
357
389
  throw new Error(`${command} ${args.join(' ')} failed`);
358
390
  }
359
391
  return true;
360
392
  }
393
+
394
+ function _actorTranslation(stepFile, translationSelected) {
395
+ let actor;
396
+
397
+ for (const translationAvailable of translations) {
398
+ if (actor) {
399
+ break;
400
+ }
401
+
402
+ if (translationSelected === translationAvailable) {
403
+ const nameOfActor = require('../../translations')[translationAvailable].I;
404
+
405
+ actor = {
406
+ [nameOfActor]: stepFile,
407
+ };
408
+ }
409
+ }
410
+
411
+ if (!actor) {
412
+ actor = {
413
+ I: stepFile,
414
+ };
415
+ }
416
+
417
+ return actor;
418
+ }
@@ -1,8 +1,10 @@
1
1
  const { getConfig, getTestRoot } = require('./utils');
2
2
  const recorder = require('../recorder');
3
3
  const Codecept = require('../codecept');
4
+ const Container = require('../container');
4
5
  const event = require('../event');
5
6
  const output = require('../output');
7
+ const webHelpers = require('../plugin/standardActingHelpers');
6
8
 
7
9
  module.exports = async function (path, options) {
8
10
  // Backward compatibility for --profile
@@ -29,9 +31,21 @@ module.exports = async function (path, options) {
29
31
  });
30
32
  event.emit(event.test.before, {
31
33
  title: '',
34
+ artifacts: {},
32
35
  });
36
+
37
+ const enabledHelpers = Container.helpers();
38
+ for (const helperName of Object.keys(enabledHelpers)) {
39
+ if (webHelpers.includes(helperName)) {
40
+ const I = enabledHelpers[helperName];
41
+ recorder.add(() => I.amOnPage('/'));
42
+ recorder.catchWithoutStop(e => output.print(`Error while loading home page: ${e.message}}`));
43
+ break;
44
+ }
45
+ }
33
46
  require('../pause')();
34
- recorder.add(() => event.emit(event.test.after));
47
+ // recorder.catchWithoutStop((err) => console.log(err.stack));
48
+ recorder.add(() => event.emit(event.test.after, {}));
35
49
  recorder.add(() => event.emit(event.suite.after, {}));
36
50
  recorder.add(() => event.emit(event.all.result, {}));
37
51
  recorder.add(() => codecept.teardown());
@@ -47,14 +47,26 @@ class Collection {
47
47
  */
48
48
  prepareRuns(selectedRuns, config) {
49
49
  selectedRuns.forEach((selectedRun) => {
50
- const [runName] = selectedRun.split(':');
51
- const runConfig = config.multiple[runName];
50
+ const runConfig = [];
51
+ const runName = [];
52
52
 
53
- if (!runConfig) {
54
- throw new Error(`run ${runName} was not configured in "multiple" section of config`);
53
+ if (selectedRun === 'all') {
54
+ Object.keys(config.multiple).forEach(name => {
55
+ runName.push(name);
56
+ runConfig.push(config.multiple[name]);
57
+ });
58
+ } else {
59
+ runName.push(selectedRun.split(':')[0]);
60
+ runConfig.push(config.multiple[runName[0]]);
55
61
  }
56
62
 
57
- this.addRun(createRun(runName, runConfig));
63
+ for (let i = 0; i < runConfig.length; i++) {
64
+ if (!runConfig[i]) {
65
+ throw new Error(`run ${runName[i]} was not configured in "multiple" section of config`);
66
+ }
67
+
68
+ this.addRun(createRun(runName[i], runConfig[i]));
69
+ }
58
70
  });
59
71
 
60
72
  return this;
@@ -28,7 +28,9 @@ let processesDone;
28
28
 
29
29
  module.exports = async function (selectedRuns, options) {
30
30
  // registering options globally to use in config
31
- process.env.profile = options.profile;
31
+ if (options.profile) {
32
+ process.env.profile = options.profile;
33
+ }
32
34
  const configFile = options.config;
33
35
 
34
36
  const testRoot = getTestRoot(configFile);
@@ -124,7 +126,7 @@ function executeRun(runName, runConfig) {
124
126
  if (browserConfig.outputName) {
125
127
  outputDir += typeof browserConfig.outputName === 'function' ? browserConfig.outputName() : browserConfig.outputName;
126
128
  } else {
127
- const hash = crypto.createHash('md5');
129
+ const hash = crypto.createHash('sha256');
128
130
  hash.update(JSON.stringify(browserConfig));
129
131
  outputDir += hash.digest('hex');
130
132
  }
@@ -4,9 +4,15 @@ const output = require('../output');
4
4
  const event = require('../event');
5
5
  const Workers = require('../workers');
6
6
 
7
- module.exports = async function (workerCount, options) {
7
+ module.exports = async function (workerCount, selectedRuns, options) {
8
8
  process.env.profile = options.profile;
9
9
 
10
+ const suiteArr = [];
11
+ const passedTestArr = [];
12
+ const failedTestArr = [];
13
+ const skippedTestArr = [];
14
+ const stepArr = [];
15
+
10
16
  const { config: testConfig, override = '' } = options;
11
17
  const overrideConfigs = tryOrDefault(() => JSON.parse(override), {});
12
18
  const by = options.suites ? 'suite' : 'test';
@@ -15,6 +21,7 @@ module.exports = async function (workerCount, options) {
15
21
  by,
16
22
  testConfig,
17
23
  options,
24
+ selectedRuns,
18
25
  };
19
26
 
20
27
  const numberOfWorkers = parseInt(workerCount, 10);
@@ -25,19 +32,75 @@ module.exports = async function (workerCount, options) {
25
32
 
26
33
  const workers = new Workers(numberOfWorkers, config);
27
34
  workers.overrideConfig(overrideConfigs);
28
- workers.on(event.test.failed, (failedTest) => {
29
- output.test.failed(failedTest);
35
+
36
+ workers.on(event.suite.before, (suite) => {
37
+ suiteArr.push(suite);
38
+ });
39
+
40
+ workers.on(event.step.passed, (step) => {
41
+ stepArr.push(step);
30
42
  });
31
43
 
32
- workers.on(event.test.passed, (successTest) => {
33
- output.test.passed(successTest);
44
+ workers.on(event.step.failed, (step) => {
45
+ stepArr.push(step);
46
+ });
47
+
48
+ workers.on(event.test.failed, (test) => {
49
+ failedTestArr.push(test);
50
+ output.test.failed(test);
51
+ });
52
+
53
+ workers.on(event.test.passed, (test) => {
54
+ passedTestArr.push(test);
55
+ output.test.passed(test);
56
+ });
57
+
58
+ workers.on(event.test.skipped, (test) => {
59
+ skippedTestArr.push(test);
60
+ output.test.skipped(test);
34
61
  });
35
62
 
36
63
  workers.on(event.all.result, () => {
64
+ // expose test stats after all workers finished their execution
65
+ function addStepsToTest(test, stepArr) {
66
+ stepArr.test.steps.forEach(step => {
67
+ if (test.steps.length === 0) {
68
+ test.steps.push(step);
69
+ }
70
+ });
71
+ }
72
+
73
+ stepArr.forEach(step => {
74
+ passedTestArr.forEach(test => {
75
+ if (step.test.title === test.title) {
76
+ addStepsToTest(test, step);
77
+ }
78
+ });
79
+
80
+ failedTestArr.forEach(test => {
81
+ if (step.test.title === test.title) {
82
+ addStepsToTest(test, step);
83
+ }
84
+ });
85
+ });
86
+
87
+ event.dispatcher.emit(event.workers.result, {
88
+ suites: suiteArr,
89
+ tests: {
90
+ passed: passedTestArr,
91
+ failed: failedTestArr,
92
+ skipped: skippedTestArr,
93
+ },
94
+ });
37
95
  workers.printResults();
38
96
  });
39
97
 
40
98
  try {
99
+ if (options.verbose) {
100
+ global.debugMode = true;
101
+ const { getMachineInfo } = require('./info');
102
+ await getMachineInfo();
103
+ }
41
104
  await workers.bootstrapAll();
42
105
  await workers.run();
43
106
  } catch (err) {
@@ -28,6 +28,13 @@ module.exports = async function (test, options) {
28
28
  codecept.init(testRoot);
29
29
  await codecept.bootstrap();
30
30
  codecept.loadTests(test);
31
+
32
+ if (options.verbose) {
33
+ global.debugMode = true;
34
+ const { getMachineInfo } = require('./info');
35
+ await getMachineInfo();
36
+ }
37
+
31
38
  await codecept.run();
32
39
  } catch (err) {
33
40
  printError(err);
@@ -132,9 +132,48 @@ function initializeListeners() {
132
132
  duration: test.duration || 0,
133
133
  err,
134
134
  parent,
135
+ steps: test.steps && test.steps.length > 0 ? simplifyStepsInTestObject(test.steps, err) : [],
135
136
  };
136
137
  }
137
138
 
139
+ function simplifyStepsInTestObject(steps, err) {
140
+ steps = [...steps];
141
+ const _steps = [];
142
+
143
+ for (step of steps) {
144
+ const _args = [];
145
+
146
+ if (step.args) {
147
+ for (const arg of step.args) {
148
+ // check if arg is a JOI object
149
+ if (arg && arg.$_root) {
150
+ _args.push(JSON.stringify(arg).slice(0, 300));
151
+ // check if arg is a function
152
+ } else if (arg && typeof arg === 'function') {
153
+ _args.push(arg.name);
154
+ } else {
155
+ _args.push(arg);
156
+ }
157
+ }
158
+ }
159
+
160
+ _steps.push({
161
+ actor: step.actor,
162
+ name: step.name,
163
+ status: step.status,
164
+ args: _args,
165
+ startedAt: step.startedAt,
166
+ startTime: step.startTime,
167
+ endTime: step.endTime,
168
+ finishedAt: step.finishedAt,
169
+ duration: step.duration,
170
+ err,
171
+ });
172
+ }
173
+
174
+ return _steps;
175
+ }
176
+
138
177
  function simplifyStep(step, err = null) {
139
178
  step = { ...step };
140
179
 
package/lib/container.js CHANGED
@@ -165,7 +165,17 @@ function createHelpers(config) {
165
165
  } else {
166
166
  moduleName = `./helper/${helperName}`; // built-in helper
167
167
  }
168
- const HelperClass = require(moduleName);
168
+
169
+ // @ts-ignore
170
+ let HelperClass;
171
+ // check if the helper is the built-in, use the require() syntax.
172
+ if (moduleName.startsWith('./helper/')) {
173
+ HelperClass = require(moduleName);
174
+ } else {
175
+ // check if the new syntax export default HelperName is used and loads the Helper, otherwise loads the module that used old syntax export = HelperName.
176
+ HelperClass = require(moduleName).default || require(moduleName);
177
+ }
178
+
169
179
  if (HelperClass._checkRequirements) {
170
180
  const requirements = HelperClass._checkRequirements();
171
181
  if (requirements) {
@@ -351,8 +361,8 @@ function loadSupportObject(modulePath, supportObjectName) {
351
361
  }
352
362
  }
353
363
  if (typeof obj !== 'function'
354
- && Object.getPrototypeOf(obj) !== Object.prototype
355
- && !Array.isArray(obj)
364
+ && Object.getPrototypeOf(obj) !== Object.prototype
365
+ && !Array.isArray(obj)
356
366
  ) {
357
367
  const methods = getObjectMethods(obj);
358
368
  Object.keys(methods)
@@ -23,6 +23,7 @@ module.exports = function (context) {
23
23
  .inject({ current: dataRow.data }));
24
24
  }
25
25
  });
26
+ maskSecretInTitle(scenarios);
26
27
  return new DataScenarioConfig(scenarios);
27
28
  },
28
29
  only: {
@@ -42,6 +43,7 @@ module.exports = function (context) {
42
43
  .inject({ current: dataRow.data }));
43
44
  }
44
45
  });
46
+ maskSecretInTitle(scenarios);
45
47
  return new DataScenarioConfig(scenarios);
46
48
  },
47
49
  },
@@ -71,12 +73,6 @@ function replaceTitle(title, dataRow) {
71
73
  // it should be printed
72
74
  if (Object.prototype.toString.call(dataRow.data) === (Object()).toString()
73
75
  && dataRow.data.toString() !== (Object()).toString()) {
74
- Object.entries(dataRow.data).forEach(entry => {
75
- const [key, value] = entry;
76
- if (value instanceof Secret) {
77
- dataRow.data[key] = value.getMasked();
78
- }
79
- });
80
76
  return `${title} | ${dataRow.data}`;
81
77
  }
82
78
 
@@ -119,3 +115,15 @@ function detectDataType(dataTable) {
119
115
 
120
116
  throw new Error('Invalid data type. Data accepts either: DataTable || generator || Array || function');
121
117
  }
118
+
119
+ function maskSecretInTitle(scenarios) {
120
+ scenarios.forEach(scenario => {
121
+ const res = [];
122
+
123
+ scenario.test.title.split(',').forEach(item => {
124
+ res.push(item.replace(/{"_secret":"(.*)"}/, '"*****"'));
125
+ });
126
+
127
+ scenario.test.title = res.join(',');
128
+ });
129
+ }
package/lib/event.js CHANGED
@@ -91,6 +91,8 @@ module.exports = {
91
91
  bddStep: {
92
92
  before: 'bddStep.before',
93
93
  after: 'bddStep.after',
94
+ started: 'bddStep.started',
95
+ finished: 'bddStep.finished',
94
96
  },
95
97
  /**
96
98
  * @type {object}
@@ -125,10 +127,12 @@ module.exports = {
125
127
  * @inner
126
128
  * @property {'workers.before'} before
127
129
  * @property {'workers.after'} after
130
+ * @property {'workers.result'} result
128
131
  */
129
132
  workers: {
130
133
  before: 'workers.before',
131
134
  after: 'workers.after',
135
+ result: 'workers.result',
132
136
  },
133
137
 
134
138
  /**
@@ -309,7 +309,8 @@ class ApiDataFactory extends Helper {
309
309
  } catch (e) {
310
310
  modulePath = path.join(global.codecept_dir, modulePath);
311
311
  }
312
- const builder = require(modulePath);
312
+ // check if the new syntax `export default new Factory()` is used and loads the builder, otherwise loads the module that used old syntax `module.exports = new Factory()`.
313
+ const builder = require(modulePath).default || require(modulePath);
313
314
  return builder.build(data, options);
314
315
  } catch (err) {
315
316
  throw new Error(`Couldn't load factory file from ${modulePath}, check that