codeceptjs 4.0.0-beta.2 → 4.0.0-beta.4

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 (152) hide show
  1. package/README.md +2 -2
  2. package/bin/codecept.js +84 -81
  3. package/lib/actor.js +13 -13
  4. package/lib/ai.js +10 -13
  5. package/lib/assert/empty.js +20 -21
  6. package/lib/assert/equal.js +37 -39
  7. package/lib/assert/error.js +14 -14
  8. package/lib/assert/include.js +46 -47
  9. package/lib/assert/throws.js +13 -11
  10. package/lib/assert/truth.js +19 -22
  11. package/lib/assert.js +4 -2
  12. package/lib/cli.js +56 -49
  13. package/lib/codecept.js +145 -155
  14. package/lib/colorUtils.js +3 -3
  15. package/lib/command/configMigrate.js +58 -52
  16. package/lib/command/definitions.js +88 -89
  17. package/lib/command/dryRun.js +79 -81
  18. package/lib/command/generate.js +197 -188
  19. package/lib/command/gherkin/init.js +27 -16
  20. package/lib/command/gherkin/snippets.js +21 -21
  21. package/lib/command/gherkin/steps.js +8 -8
  22. package/lib/command/info.js +40 -38
  23. package/lib/command/init.js +290 -288
  24. package/lib/command/interactive.js +32 -32
  25. package/lib/command/list.js +26 -26
  26. package/lib/command/run-multiple/chunk.js +5 -5
  27. package/lib/command/run-multiple/collection.js +3 -3
  28. package/lib/command/run-multiple/run.js +6 -2
  29. package/lib/command/run-multiple.js +113 -93
  30. package/lib/command/run-rerun.js +20 -25
  31. package/lib/command/run-workers.js +64 -66
  32. package/lib/command/run.js +26 -29
  33. package/lib/command/utils.js +80 -65
  34. package/lib/command/workers/runTests.js +11 -12
  35. package/lib/config.js +10 -9
  36. package/lib/container.js +40 -48
  37. package/lib/data/context.js +60 -59
  38. package/lib/data/dataScenarioConfig.js +47 -47
  39. package/lib/data/dataTableArgument.js +29 -29
  40. package/lib/data/table.js +26 -20
  41. package/lib/event.js +163 -167
  42. package/lib/heal.js +14 -18
  43. package/lib/helper/AI.js +130 -41
  44. package/lib/helper/ApiDataFactory.js +74 -70
  45. package/lib/helper/Appium.js +416 -388
  46. package/lib/helper/ExpectHelper.js +40 -48
  47. package/lib/helper/FileSystem.js +80 -79
  48. package/lib/helper/GraphQL.js +44 -43
  49. package/lib/helper/GraphQLDataFactory.js +51 -51
  50. package/lib/helper/JSONResponse.js +65 -62
  51. package/lib/helper/Mochawesome.js +28 -28
  52. package/lib/helper/Nightmare.js +664 -571
  53. package/lib/helper/Playwright.js +1367 -1222
  54. package/lib/helper/Protractor.js +663 -635
  55. package/lib/helper/Puppeteer.js +1232 -1132
  56. package/lib/helper/REST.js +183 -68
  57. package/lib/helper/SoftExpectHelper.js +2 -2
  58. package/lib/helper/TestCafe.js +490 -486
  59. package/lib/helper/WebDriver.js +1246 -1297
  60. package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
  61. package/lib/helper/errors/ConnectionRefused.js +1 -1
  62. package/lib/helper/errors/ElementAssertion.js +2 -2
  63. package/lib/helper/errors/ElementNotFound.js +2 -2
  64. package/lib/helper/errors/RemoteBrowserConnectionRefused.js +1 -1
  65. package/lib/helper/extras/Console.js +1 -1
  66. package/lib/helper/extras/PlaywrightPropEngine.js +4 -4
  67. package/lib/helper/extras/PlaywrightReactVueLocator.js +1 -1
  68. package/lib/helper/extras/PlaywrightRestartOpts.js +21 -18
  69. package/lib/helper/extras/Popup.js +1 -1
  70. package/lib/helper/extras/React.js +3 -3
  71. package/lib/helper/network/actions.js +14 -7
  72. package/lib/helper/network/utils.js +4 -3
  73. package/lib/helper/scripts/blurElement.js +1 -1
  74. package/lib/helper/scripts/focusElement.js +1 -1
  75. package/lib/helper/scripts/highlightElement.js +1 -1
  76. package/lib/helper/scripts/isElementClickable.js +1 -1
  77. package/lib/helper/testcafe/testControllerHolder.js +1 -1
  78. package/lib/helper/testcafe/testcafe-utils.js +7 -8
  79. package/lib/helper.js +1 -3
  80. package/lib/history.js +6 -5
  81. package/lib/hooks.js +6 -6
  82. package/lib/html.js +7 -7
  83. package/lib/index.js +25 -41
  84. package/lib/interfaces/bdd.js +47 -64
  85. package/lib/interfaces/featureConfig.js +19 -19
  86. package/lib/interfaces/gherkin.js +124 -118
  87. package/lib/interfaces/scenarioConfig.js +29 -29
  88. package/lib/listener/artifacts.js +9 -9
  89. package/lib/listener/config.js +24 -24
  90. package/lib/listener/exit.js +12 -12
  91. package/lib/listener/helpers.js +42 -42
  92. package/lib/listener/mocha.js +11 -11
  93. package/lib/listener/retry.js +32 -30
  94. package/lib/listener/steps.js +50 -53
  95. package/lib/listener/timeout.js +54 -54
  96. package/lib/locator.js +7 -11
  97. package/lib/mochaFactory.js +18 -15
  98. package/lib/output.js +19 -15
  99. package/lib/parser.js +15 -12
  100. package/lib/pause.js +45 -38
  101. package/lib/plugin/allure.js +15 -15
  102. package/lib/plugin/autoDelay.js +29 -37
  103. package/lib/plugin/autoLogin.js +70 -65
  104. package/lib/plugin/commentStep.js +18 -18
  105. package/lib/plugin/coverage.js +112 -67
  106. package/lib/plugin/customLocator.js +21 -20
  107. package/lib/plugin/debugErrors.js +24 -24
  108. package/lib/plugin/eachElement.js +38 -38
  109. package/lib/plugin/fakerTransform.js +6 -6
  110. package/lib/plugin/heal.js +67 -108
  111. package/lib/plugin/pauseOnFail.js +11 -11
  112. package/lib/plugin/retryFailedStep.js +32 -39
  113. package/lib/plugin/retryTo.js +46 -40
  114. package/lib/plugin/screenshotOnFail.js +109 -87
  115. package/lib/plugin/selenoid.js +131 -118
  116. package/lib/plugin/standardActingHelpers.js +2 -8
  117. package/lib/plugin/stepByStepReport.js +110 -91
  118. package/lib/plugin/stepTimeout.js +24 -23
  119. package/lib/plugin/subtitles.js +34 -35
  120. package/lib/plugin/tryTo.js +40 -30
  121. package/lib/plugin/wdio.js +78 -75
  122. package/lib/recorder.js +14 -17
  123. package/lib/rerun.js +11 -10
  124. package/lib/scenario.js +25 -23
  125. package/lib/secret.js +4 -3
  126. package/lib/session.js +10 -10
  127. package/lib/step.js +12 -9
  128. package/lib/store.js +2 -3
  129. package/lib/transform.js +1 -1
  130. package/lib/translation.js +7 -8
  131. package/lib/ui.js +12 -14
  132. package/lib/utils.js +70 -72
  133. package/lib/within.js +10 -10
  134. package/lib/workerStorage.js +27 -25
  135. package/lib/workers.js +29 -33
  136. package/package.json +67 -68
  137. package/translations/de-DE.js +2 -1
  138. package/translations/fr-FR.js +2 -2
  139. package/translations/index.js +9 -13
  140. package/translations/it-IT.js +1 -1
  141. package/translations/ja-JP.js +1 -1
  142. package/translations/pl-PL.js +1 -1
  143. package/translations/pt-BR.js +1 -1
  144. package/translations/ru-RU.js +1 -1
  145. package/translations/zh-CN.js +1 -1
  146. package/translations/zh-TW.js +1 -1
  147. package/typings/index.d.ts +423 -65
  148. package/typings/promiseBasedTypes.d.ts +41 -172
  149. package/typings/types.d.ts +43 -178
  150. package/lib/dirname.js +0 -5
  151. package/lib/helper/Expect.js +0 -425
  152. package/lib/helper/MockServer.js +0 -223
@@ -1,12 +1,11 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { getConfig, getTestRoot } from './utils.js';
4
- import Codecept from '../codecept.js';
5
- import container from '../container.js';
6
- import * as output from '../output.js';
7
- import plugin from '../plugin/standardActingHelpers.js';
1
+ const fs = require('fs')
2
+ const path = require('path')
8
3
 
9
- const actingHelpers = [...(plugin), 'REST'];
4
+ const { getConfig, getTestRoot } = require('./utils')
5
+ const Codecept = require('../codecept')
6
+ const container = require('../container')
7
+ const output = require('../output')
8
+ const actingHelpers = [...require('../plugin/standardActingHelpers'), 'REST']
10
9
 
11
10
  /**
12
11
  * Prepare data and generate content of definitions file
@@ -30,32 +29,27 @@ const getDefinitionsFileContent = ({
30
29
  importPaths,
31
30
  translations,
32
31
  }) => {
33
- const getHelperListFragment = ({
34
- hasCustomHelper,
35
- hasCustomStepsFile,
36
- }) => {
32
+ const getHelperListFragment = ({ hasCustomHelper, hasCustomStepsFile }) => {
37
33
  if (hasCustomHelper && hasCustomStepsFile) {
38
- return `${['ReturnType<steps_file>', 'WithTranslation<Methods>'].join(', ')}`;
34
+ return `${['ReturnType<steps_file>', 'WithTranslation<Methods>'].join(', ')}`
39
35
  }
40
36
 
41
37
  if (hasCustomStepsFile) {
42
- return 'ReturnType<steps_file>';
38
+ return 'ReturnType<steps_file>'
43
39
  }
44
40
 
45
- return 'WithTranslation<Methods>';
46
- };
41
+ return 'WithTranslation<Methods>'
42
+ }
47
43
 
48
44
  const helpersListFragment = getHelperListFragment({
49
45
  hasCustomHelper,
50
46
  hasCustomStepsFile,
51
- });
47
+ })
52
48
 
53
- const importPathsFragment = importPaths.join('\n');
54
- const supportObjectsTypeFragment = convertMapToType(supportObject);
55
- const methodsTypeFragment = helperNames.length > 0
56
- ? `interface Methods extends ${helperNames.join(', ')} {}`
57
- : '';
58
- const translatedActionsFragment = JSON.stringify(translations.vocabulary.actions, null, 2);
49
+ const importPathsFragment = importPaths.join('\n')
50
+ const supportObjectsTypeFragment = convertMapToType(supportObject)
51
+ const methodsTypeFragment = helperNames.length > 0 ? `interface Methods extends ${helperNames.join(', ')} {}` : ''
52
+ const translatedActionsFragment = JSON.stringify(translations.vocabulary.actions, null, 2)
59
53
 
60
54
  return generateDefinitionsContent({
61
55
  helpersListFragment,
@@ -63,8 +57,8 @@ const getDefinitionsFileContent = ({
63
57
  supportObjectsTypeFragment,
64
58
  methodsTypeFragment,
65
59
  translatedActionsFragment,
66
- });
67
- };
60
+ })
61
+ }
68
62
 
69
63
  /**
70
64
  * Generate content for definitions file from fragments
@@ -97,83 +91,83 @@ declare namespace CodeceptJS {
97
91
  interface Actions ${translatedActionsFragment}
98
92
  }
99
93
  }
100
- `;
101
- };
94
+ `
95
+ }
102
96
 
103
97
  /** @type {Array<string>} */
104
- const helperNames = [];
98
+ const helperNames = []
105
99
  /** @type {Array<string>} */
106
- const customHelpers = [];
100
+ const customHelpers = []
107
101
 
108
- export default function (genPath, options) {
109
- const configFile = options.config || genPath;
102
+ module.exports = function (genPath, options) {
103
+ const configFile = options.config || genPath
110
104
  /** @type {string} */
111
- const testsPath = getTestRoot(configFile);
112
- const config = getConfig(configFile);
113
- if (!config) return;
105
+ const testsPath = getTestRoot(configFile)
106
+ const config = getConfig(configFile)
107
+ if (!config) return
114
108
 
115
109
  /** @type {Object<string, string>} */
116
- const helperPaths = {};
110
+ const helperPaths = {}
117
111
  /** @type {Object<string, string>} */
118
- const supportPaths = {};
112
+ const supportPaths = {}
119
113
  /** @type {boolean} */
120
- let hasCustomStepsFile = false;
114
+ let hasCustomStepsFile = false
121
115
  /** @type {boolean} */
122
- let hasCustomHelper = false;
116
+ let hasCustomHelper = false
123
117
 
124
118
  /** @type {string} */
125
- const targetFolderPath = options.output && getTestRoot(options.output) || testsPath;
119
+ const targetFolderPath = (options.output && getTestRoot(options.output)) || testsPath
126
120
 
127
- const codecept = new Codecept(config, {});
128
- codecept.init(testsPath);
121
+ const codecept = new Codecept(config, {})
122
+ codecept.init(testsPath)
129
123
 
130
- const helpers = container.helpers();
131
- const translations = container.translation();
124
+ const helpers = container.helpers()
125
+ const translations = container.translation()
132
126
  for (const name in helpers) {
133
- const require = codecept.config.helpers[name].require;
127
+ const require = codecept.config.helpers[name].require
134
128
  if (require) {
135
- helperPaths[name] = require;
136
- helperNames.push(name);
129
+ helperPaths[name] = require
130
+ helperNames.push(name)
137
131
  } else {
138
- const fullBasedPromised = codecept.config.fullPromiseBased;
139
- helperNames.push(fullBasedPromised === true ? `${name}Ts` : name);
132
+ const fullBasedPromised = codecept.config.fullPromiseBased
133
+ helperNames.push(fullBasedPromised === true ? `${name}Ts` : name)
140
134
  }
141
135
 
142
136
  if (!actingHelpers.includes(name)) {
143
- customHelpers.push(name);
137
+ customHelpers.push(name)
144
138
  }
145
139
  }
146
140
 
147
- let autoLogin;
141
+ let autoLogin
148
142
  if (config.plugins.autoLogin) {
149
- autoLogin = config.plugins.autoLogin.inject;
143
+ autoLogin = config.plugins.autoLogin.inject
150
144
  }
151
145
 
152
- const supportObject = new Map();
153
- supportObject.set('I', 'I');
154
- supportObject.set('current', 'any');
146
+ const supportObject = new Map()
147
+ supportObject.set('I', 'I')
148
+ supportObject.set('current', 'any')
155
149
 
156
150
  if (translations.loaded) {
157
- supportObject.set(translations.I, translations.I);
151
+ supportObject.set(translations.I, translations.I)
158
152
  }
159
153
 
160
154
  if (autoLogin) {
161
- supportObject.set(autoLogin, 'any');
155
+ supportObject.set(autoLogin, 'any')
162
156
  }
163
157
 
164
158
  if (customHelpers.length > 0) {
165
- hasCustomHelper = true;
159
+ hasCustomHelper = true
166
160
  }
167
161
 
168
162
  for (const name in codecept.config.include) {
169
- const includePath = codecept.config.include[name];
163
+ const includePath = codecept.config.include[name]
170
164
  if (name === 'I' || name === translations.I) {
171
- hasCustomStepsFile = true;
172
- supportPaths.steps_file = includePath;
173
- continue;
165
+ hasCustomStepsFile = true
166
+ supportPaths.steps_file = includePath
167
+ continue
174
168
  }
175
- supportPaths[name] = includePath;
176
- supportObject.set(name, name);
169
+ supportPaths[name] = includePath
170
+ supportObject.set(name, name)
177
171
  }
178
172
 
179
173
  let definitionsFileContent = getDefinitionsFileContent({
@@ -183,30 +177,33 @@ export default function (genPath, options) {
183
177
  translations,
184
178
  hasCustomStepsFile,
185
179
  hasCustomHelper,
186
- });
180
+ })
187
181
 
188
182
  // add aliases for translations
189
183
  if (translations.loaded) {
190
- const namespaceTranslationAliases = [];
191
- namespaceTranslationAliases.push(`interface ${translations.vocabulary.I} extends WithTranslation<Methods> {}`);
184
+ const namespaceTranslationAliases = []
185
+ namespaceTranslationAliases.push(`interface ${translations.vocabulary.I} extends WithTranslation<Methods> {}`)
192
186
 
193
- namespaceTranslationAliases.push(' namespace Translation {');
194
- definitionsFileContent = definitionsFileContent.replace('namespace Translation {', namespaceTranslationAliases.join('\n'));
187
+ namespaceTranslationAliases.push(' namespace Translation {')
188
+ definitionsFileContent = definitionsFileContent.replace(
189
+ 'namespace Translation {',
190
+ namespaceTranslationAliases.join('\n'),
191
+ )
195
192
 
196
- const translationAliases = [];
193
+ const translationAliases = []
197
194
 
198
195
  if (translations.vocabulary.contexts) {
199
- Object.keys(translations.vocabulary.contexts).forEach(k => {
200
- translationAliases.push(`declare const ${translations.vocabulary.contexts[k]}: typeof ${k};`);
201
- });
196
+ Object.keys(translations.vocabulary.contexts).forEach((k) => {
197
+ translationAliases.push(`declare const ${translations.vocabulary.contexts[k]}: typeof ${k};`)
198
+ })
202
199
  }
203
200
 
204
- definitionsFileContent += `\n${translationAliases.join('\n')}`;
201
+ definitionsFileContent += `\n${translationAliases.join('\n')}`
205
202
  }
206
203
 
207
- fs.writeFileSync(path.join(targetFolderPath, 'steps.d.ts'), definitionsFileContent);
208
- output.print('TypeScript Definitions provide autocompletion in Visual Studio Code and other IDEs');
209
- output.print('Definitions were generated in steps.d.ts');
204
+ fs.writeFileSync(path.join(targetFolderPath, 'steps.d.ts'), definitionsFileContent)
205
+ output.print('TypeScript Definitions provide autocompletion in Visual Studio Code and other IDEs')
206
+ output.print('Definitions were generated in steps.d.ts')
210
207
  }
211
208
 
212
209
  /**
@@ -216,13 +213,13 @@ export default function (genPath, options) {
216
213
  * @param {string} testsPath
217
214
  */
218
215
  function getPath(originalPath, targetFolderPath, testsPath) {
219
- const parsedPath = path.parse(originalPath);
216
+ const parsedPath = path.parse(originalPath)
220
217
 
221
218
  // Remove typescript extension if exists.
222
- if (parsedPath.base.endsWith('.d.ts')) parsedPath.base = parsedPath.base.substring(0, parsedPath.base.length - 5);
223
- else if (parsedPath.ext === '.ts') parsedPath.base = parsedPath.name;
219
+ if (parsedPath.base.endsWith('.d.ts')) parsedPath.base = parsedPath.base.substring(0, parsedPath.base.length - 5)
220
+ else if (parsedPath.ext === '.ts') parsedPath.base = parsedPath.name
224
221
 
225
- if (!parsedPath.dir.startsWith('.')) return path.posix.join(parsedPath.dir, parsedPath.base);
222
+ if (!parsedPath.dir.startsWith('.')) return path.posix.join(parsedPath.dir, parsedPath.base)
226
223
  const relativePath = path.posix.relative(
227
224
  targetFolderPath.split(path.sep).join(path.posix.sep),
228
225
  path.posix.join(
@@ -230,9 +227,9 @@ function getPath(originalPath, targetFolderPath, testsPath) {
230
227
  parsedPath.dir.split(path.sep).join(path.posix.sep),
231
228
  parsedPath.base.split(path.sep).join(path.posix.sep),
232
229
  ),
233
- );
230
+ )
234
231
 
235
- return relativePath.startsWith('.') ? relativePath : `./${relativePath}`;
232
+ return relativePath.startsWith('.') ? relativePath : `./${relativePath}`
236
233
  }
237
234
 
238
235
  /**
@@ -246,19 +243,19 @@ function getPath(originalPath, targetFolderPath, testsPath) {
246
243
  * @returns {Array<string>}
247
244
  */
248
245
  function getImportString(testsPath, targetFolderPath, pathsToType, pathsToValue) {
249
- const importStrings = [];
246
+ const importStrings = []
250
247
 
251
248
  for (const name in pathsToType) {
252
- const relativePath = getPath(pathsToType[name], targetFolderPath, testsPath);
253
- importStrings.push(`type ${name} = typeof import('${relativePath}');`);
249
+ const relativePath = getPath(pathsToType[name], targetFolderPath, testsPath)
250
+ importStrings.push(`type ${name} = typeof import('${relativePath}');`)
254
251
  }
255
252
 
256
253
  for (const name in pathsToValue) {
257
- const relativePath = getPath(pathsToValue[name], targetFolderPath, testsPath);
258
- importStrings.push(`type ${name} = import('${relativePath}');`);
254
+ const relativePath = getPath(pathsToValue[name], targetFolderPath, testsPath)
255
+ importStrings.push(`type ${name} = import('${relativePath}');`)
259
256
  }
260
257
 
261
- return importStrings;
258
+ return importStrings
262
259
  }
263
260
 
264
261
  /**
@@ -267,5 +264,7 @@ function getImportString(testsPath, targetFolderPath, pathsToType, pathsToValue)
267
264
  * @returns {string}
268
265
  */
269
266
  function convertMapToType(map) {
270
- return `{ ${Array.from(map).map(([key, value]) => `${key}: ${value}`).join(', ')} }`;
267
+ return `{ ${Array.from(map)
268
+ .map(([key, value]) => `${key}: ${value}`)
269
+ .join(', ')} }`
271
270
  }
@@ -1,119 +1,117 @@
1
- import { getConfig, getTestRoot } from './utils.js';
2
- import Config from '../config.js';
3
- import Codecept from '../codecept.js';
4
- import { output } from '../output.js';
5
- import * as event from '../event.js';
6
- import { store } from '../store.js';
7
- import container from '../container.js';
8
- import colors from "chalk";
9
- import figures from "figures";
10
-
11
- export default async function (test, options) {
12
- if (options.grep) process.env.grep = options.grep.toLowerCase();
13
- const configFile = options.config;
14
- let codecept;
15
-
16
- const testRoot = getTestRoot(configFile);
17
- let config = getConfig(configFile);
1
+ const { getConfig, getTestRoot } = require('./utils')
2
+ const Config = require('../config')
3
+ const Codecept = require('../codecept')
4
+ const output = require('../output')
5
+ const event = require('../event')
6
+ const store = require('../store')
7
+ const Container = require('../container')
8
+
9
+ module.exports = async function (test, options) {
10
+ if (options.grep) process.env.grep = options.grep
11
+ const configFile = options.config
12
+ let codecept
13
+
14
+ const testRoot = getTestRoot(configFile)
15
+ let config = getConfig(configFile)
18
16
  if (options.override) {
19
- config = Config.append(JSON.parse(options.override));
17
+ config = Config.append(JSON.parse(options.override))
20
18
  }
21
19
 
22
20
  if (config.plugins) {
23
21
  // disable all plugins by default, they can be enabled with -p option
24
22
  for (const plugin in config.plugins) {
25
23
  // if `-p all` is passed, then enabling all plugins, otherwise plugins could be enabled by `-p customLocator,commentStep,tryTo`
26
- config.plugins[plugin].enabled = options.plugins === 'all';
24
+ config.plugins[plugin].enabled = options.plugins === 'all'
27
25
  }
28
26
  }
29
27
 
30
28
  try {
31
- codecept = new Codecept(config, options);
32
- codecept.init(testRoot);
29
+ codecept = new Codecept(config, options)
30
+ codecept.init(testRoot)
33
31
 
34
- if (options.bootstrap) await codecept.bootstrap();
32
+ if (options.bootstrap) await codecept.bootstrap()
35
33
 
36
- codecept.loadTests();
37
- store.dryRun = true;
34
+ codecept.loadTests()
35
+ store.dryRun = true
38
36
 
39
37
  if (!options.steps && !options.verbose && !options.debug) {
40
- printTests(codecept.testFiles);
41
- return;
38
+ printTests(codecept.testFiles)
39
+ return
42
40
  }
43
- event.dispatcher.on(event.all.result, printFooter);
44
- codecept.run(test);
41
+ event.dispatcher.on(event.all.result, printFooter)
42
+ codecept.run(test)
45
43
  } catch (err) {
46
- console.error(err);
47
- process.exit(1);
44
+ console.error(err)
45
+ process.exit(1)
48
46
  }
49
47
  }
50
48
 
51
49
  function printTests(files) {
52
- output.print(output.styles.debug(`Tests from ${global.codecept_dir}:`));
53
- output.print();
50
+ const figures = require('figures')
51
+ const colors = require('chalk')
54
52
 
55
- const mocha = container.mocha();
56
- mocha.files = files;
57
- mocha.loadFiles();
53
+ output.print(output.styles.debug(`Tests from ${global.codecept_dir}:`))
54
+ output.print()
58
55
 
59
- let numOfTests = 0;
60
- let numOfSuites = 0;
61
- let outputString = '';
62
- const filterBy = process.env.grep ? process.env.grep.toLowerCase() : undefined;
56
+ const mocha = Container.mocha()
57
+ mocha.files = files
58
+ mocha.loadFiles()
63
59
 
60
+ let numOfTests = 0
61
+ let numOfSuites = 0
62
+ let outputString = ''
63
+ const filterBy = process.env.grep
64
+
65
+ let filterRegex
64
66
  if (filterBy) {
65
- for (const suite of mocha.suite.suites) {
66
- const currentSuite = suite.title;
67
- if (suite.title.toLowerCase().includes(filterBy)) {
68
- outputString += `${colors.white.bold(suite.title)} -- ${output.styles.log(suite.file || '')} -- ${mocha.suite.suites.length} tests\n`;
69
- numOfSuites++;
70
- }
67
+ try {
68
+ filterRegex = new RegExp(filterBy, 'i') // Case-insensitive matching
69
+ } catch (err) {
70
+ console.error(`Invalid grep pattern: ${filterBy}`)
71
+ process.exit(1)
72
+ }
73
+ }
71
74
 
72
- for (const test of suite.tests) {
73
- if (test.title.toLowerCase().includes(filterBy)) {
74
- numOfTests++;
75
- outputString += `${colors.white.bold(test.parent.title)} -- ${output.styles.log(test.parent.file || '')} -- ${mocha.suite.suites.length} tests\n`;
76
- outputString += ` ${output.styles.scenario(figures.checkboxOff)} ${test.title}\n`;
77
- }
78
- }
75
+ for (const suite of mocha.suite.suites) {
76
+ const suiteMatches = filterRegex ? filterRegex.test(suite.title) : true
77
+ let suiteHasMatchingTests = false
78
+
79
+ if (suiteMatches) {
80
+ outputString += `${colors.white.bold(suite.title)} -- ${output.styles.log(suite.file || '')}\n`
81
+ suiteHasMatchingTests = true
82
+ numOfSuites++
79
83
  }
80
- numOfSuites = countSuites(outputString);
81
- } else {
82
- for (const suite of mocha.suite.suites) {
83
- output.print(`${colors.white.bold(suite.title)} -- ${output.styles.log(suite.file || '')} -- ${mocha.suite.suites.length} tests`);
84
- numOfSuites++;
85
-
86
- for (const test of suite.tests) {
87
- numOfTests++;
88
- output.print(` ${output.styles.scenario(figures.checkboxOff)} ${test.title}`);
84
+
85
+ for (const test of suite.tests) {
86
+ const testMatches = filterRegex ? filterRegex.test(test.title) : true
87
+
88
+ if (testMatches) {
89
+ if (!suiteMatches && !suiteHasMatchingTests) {
90
+ outputString += `${colors.white.bold(suite.title)} -- ${output.styles.log(suite.file || '')}\n`
91
+ suiteHasMatchingTests = true
92
+ numOfSuites++
93
+ }
94
+
95
+ numOfTests++
96
+ outputString += ` ${output.styles.scenario(figures.checkboxOff)} ${test.title}\n`
89
97
  }
90
98
  }
91
99
  }
92
100
 
93
- output.print(removeDuplicates(outputString));
94
- output.print('');
95
- output.success(` Total: ${numOfSuites} suites | ${numOfTests} tests `);
96
- printFooter();
97
- process.exit(0);
101
+ output.print(removeDuplicates(outputString))
102
+ output.print('')
103
+ output.success(` Total: ${numOfSuites} suites | ${numOfTests} tests `)
104
+ printFooter()
105
+ process.exit(0)
98
106
  }
99
107
 
100
108
  function printFooter() {
101
- output.print();
102
- output.print('--- DRY MODE: No tests were executed ---');
109
+ output.print()
110
+ output.print('--- DRY MODE: No tests were executed ---')
103
111
  }
104
112
 
105
113
  function removeDuplicates(inputString) {
106
- const array = inputString.split('\n');
107
- const uniqueLines = [...new Set(array)];
108
- const resultString = uniqueLines.join('\n');
109
-
110
- return resultString;
111
- }
112
-
113
- function countSuites(inputString) {
114
- const array = inputString.split('\n');
115
-
116
- const uniqueLines = [...new Set(array)];
117
- const res = uniqueLines.filter(item => item.includes('-- '));
118
- return res.length;
114
+ const array = inputString.split('\n')
115
+ const uniqueLines = [...new Set(array)]
116
+ return uniqueLines.join('\n')
119
117
  }