codeceptjs 4.0.0-beta.4 → 4.0.0-beta.6.esm-aria

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 (188) hide show
  1. package/README.md +89 -119
  2. package/bin/codecept.js +53 -54
  3. package/docs/webapi/clearCookie.mustache +1 -1
  4. package/lib/actor.js +70 -102
  5. package/lib/ai.js +131 -121
  6. package/lib/assert/empty.js +11 -12
  7. package/lib/assert/equal.js +16 -21
  8. package/lib/assert/error.js +2 -2
  9. package/lib/assert/include.js +11 -15
  10. package/lib/assert/throws.js +3 -5
  11. package/lib/assert/truth.js +10 -7
  12. package/lib/assert.js +18 -18
  13. package/lib/codecept.js +112 -101
  14. package/lib/colorUtils.js +48 -50
  15. package/lib/command/check.js +206 -0
  16. package/lib/command/configMigrate.js +13 -14
  17. package/lib/command/definitions.js +24 -36
  18. package/lib/command/dryRun.js +16 -16
  19. package/lib/command/generate.js +38 -39
  20. package/lib/command/gherkin/init.js +36 -38
  21. package/lib/command/gherkin/snippets.js +76 -74
  22. package/lib/command/gherkin/steps.js +21 -18
  23. package/lib/command/info.js +49 -15
  24. package/lib/command/init.js +41 -37
  25. package/lib/command/interactive.js +22 -13
  26. package/lib/command/list.js +11 -10
  27. package/lib/command/run-multiple/chunk.js +50 -47
  28. package/lib/command/run-multiple/collection.js +5 -5
  29. package/lib/command/run-multiple/run.js +3 -3
  30. package/lib/command/run-multiple.js +27 -47
  31. package/lib/command/run-rerun.js +6 -7
  32. package/lib/command/run-workers.js +15 -66
  33. package/lib/command/run.js +8 -8
  34. package/lib/command/utils.js +22 -21
  35. package/lib/command/workers/runTests.js +131 -241
  36. package/lib/config.js +111 -49
  37. package/lib/container.js +589 -244
  38. package/lib/data/context.js +16 -18
  39. package/lib/data/dataScenarioConfig.js +9 -9
  40. package/lib/data/dataTableArgument.js +7 -7
  41. package/lib/data/table.js +6 -12
  42. package/lib/effects.js +307 -0
  43. package/lib/els.js +160 -0
  44. package/lib/event.js +24 -19
  45. package/lib/globals.js +141 -0
  46. package/lib/heal.js +89 -81
  47. package/lib/helper/AI.js +3 -2
  48. package/lib/helper/ApiDataFactory.js +19 -19
  49. package/lib/helper/Appium.js +47 -51
  50. package/lib/helper/FileSystem.js +35 -15
  51. package/lib/helper/GraphQL.js +1 -1
  52. package/lib/helper/GraphQLDataFactory.js +4 -4
  53. package/lib/helper/JSONResponse.js +72 -45
  54. package/lib/helper/Mochawesome.js +14 -11
  55. package/lib/helper/Playwright.js +832 -434
  56. package/lib/helper/Puppeteer.js +393 -292
  57. package/lib/helper/REST.js +32 -27
  58. package/lib/helper/WebDriver.js +320 -219
  59. package/lib/helper/errors/ConnectionRefused.js +6 -6
  60. package/lib/helper/errors/ElementAssertion.js +11 -16
  61. package/lib/helper/errors/ElementNotFound.js +5 -9
  62. package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
  63. package/lib/helper/extras/Console.js +11 -11
  64. package/lib/helper/extras/PlaywrightLocator.js +110 -0
  65. package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
  66. package/lib/helper/extras/PlaywrightRestartOpts.js +23 -23
  67. package/lib/helper/extras/Popup.js +22 -22
  68. package/lib/helper/extras/React.js +29 -30
  69. package/lib/helper/network/actions.js +33 -48
  70. package/lib/helper/network/utils.js +76 -83
  71. package/lib/helper/scripts/blurElement.js +6 -6
  72. package/lib/helper/scripts/focusElement.js +6 -6
  73. package/lib/helper/scripts/highlightElement.js +9 -9
  74. package/lib/helper/scripts/isElementClickable.js +34 -34
  75. package/lib/helper.js +2 -1
  76. package/lib/history.js +23 -20
  77. package/lib/hooks.js +10 -10
  78. package/lib/html.js +90 -100
  79. package/lib/index.js +48 -21
  80. package/lib/listener/config.js +8 -9
  81. package/lib/listener/emptyRun.js +54 -0
  82. package/lib/listener/exit.js +10 -12
  83. package/lib/listener/{retry.js → globalRetry.js} +10 -10
  84. package/lib/listener/globalTimeout.js +166 -0
  85. package/lib/listener/helpers.js +43 -24
  86. package/lib/listener/mocha.js +4 -5
  87. package/lib/listener/result.js +11 -0
  88. package/lib/listener/steps.js +26 -23
  89. package/lib/listener/store.js +20 -0
  90. package/lib/locator.js +213 -192
  91. package/lib/mocha/asyncWrapper.js +264 -0
  92. package/lib/mocha/bdd.js +167 -0
  93. package/lib/mocha/cli.js +341 -0
  94. package/lib/mocha/factory.js +160 -0
  95. package/lib/{interfaces → mocha}/featureConfig.js +33 -13
  96. package/lib/{interfaces → mocha}/gherkin.js +75 -45
  97. package/lib/mocha/hooks.js +121 -0
  98. package/lib/mocha/index.js +21 -0
  99. package/lib/mocha/inject.js +46 -0
  100. package/lib/{interfaces → mocha}/scenarioConfig.js +32 -8
  101. package/lib/mocha/suite.js +89 -0
  102. package/lib/mocha/test.js +178 -0
  103. package/lib/mocha/types.d.ts +42 -0
  104. package/lib/mocha/ui.js +229 -0
  105. package/lib/output.js +86 -64
  106. package/lib/parser.js +44 -44
  107. package/lib/pause.js +160 -139
  108. package/lib/plugin/analyze.js +403 -0
  109. package/lib/plugin/{autoLogin.js → auth.js} +137 -43
  110. package/lib/plugin/autoDelay.js +19 -15
  111. package/lib/plugin/coverage.js +22 -27
  112. package/lib/plugin/customLocator.js +5 -5
  113. package/lib/plugin/customReporter.js +53 -0
  114. package/lib/plugin/heal.js +49 -17
  115. package/lib/plugin/pageInfo.js +140 -0
  116. package/lib/plugin/pauseOnFail.js +4 -3
  117. package/lib/plugin/retryFailedStep.js +60 -19
  118. package/lib/plugin/screenshotOnFail.js +80 -83
  119. package/lib/plugin/stepByStepReport.js +70 -31
  120. package/lib/plugin/stepTimeout.js +7 -13
  121. package/lib/plugin/subtitles.js +10 -9
  122. package/lib/recorder.js +167 -126
  123. package/lib/rerun.js +94 -50
  124. package/lib/result.js +161 -0
  125. package/lib/secret.js +18 -17
  126. package/lib/session.js +95 -89
  127. package/lib/step/base.js +239 -0
  128. package/lib/step/comment.js +10 -0
  129. package/lib/step/config.js +50 -0
  130. package/lib/step/func.js +46 -0
  131. package/lib/step/helper.js +50 -0
  132. package/lib/step/meta.js +99 -0
  133. package/lib/step/record.js +74 -0
  134. package/lib/step/retry.js +11 -0
  135. package/lib/step/section.js +55 -0
  136. package/lib/step.js +18 -332
  137. package/lib/steps.js +54 -0
  138. package/lib/store.js +37 -5
  139. package/lib/template/heal.js +2 -11
  140. package/lib/timeout.js +60 -0
  141. package/lib/transform.js +8 -8
  142. package/lib/translation.js +32 -18
  143. package/lib/utils.js +354 -250
  144. package/lib/workerStorage.js +16 -16
  145. package/lib/workers.js +366 -282
  146. package/package.json +107 -95
  147. package/translations/de-DE.js +5 -4
  148. package/translations/fr-FR.js +5 -4
  149. package/translations/index.js +23 -9
  150. package/translations/it-IT.js +5 -4
  151. package/translations/ja-JP.js +5 -4
  152. package/translations/nl-NL.js +76 -0
  153. package/translations/pl-PL.js +5 -4
  154. package/translations/pt-BR.js +5 -4
  155. package/translations/ru-RU.js +5 -4
  156. package/translations/utils.js +18 -0
  157. package/translations/zh-CN.js +5 -4
  158. package/translations/zh-TW.js +5 -4
  159. package/typings/index.d.ts +177 -186
  160. package/typings/promiseBasedTypes.d.ts +3573 -5941
  161. package/typings/types.d.ts +4042 -6370
  162. package/lib/cli.js +0 -256
  163. package/lib/helper/ExpectHelper.js +0 -391
  164. package/lib/helper/Nightmare.js +0 -1504
  165. package/lib/helper/Protractor.js +0 -1863
  166. package/lib/helper/SoftExpectHelper.js +0 -381
  167. package/lib/helper/TestCafe.js +0 -1414
  168. package/lib/helper/clientscripts/nightmare.js +0 -213
  169. package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -43
  170. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  171. package/lib/helper/testcafe/testcafe-utils.js +0 -62
  172. package/lib/interfaces/bdd.js +0 -81
  173. package/lib/listener/artifacts.js +0 -19
  174. package/lib/listener/timeout.js +0 -109
  175. package/lib/mochaFactory.js +0 -113
  176. package/lib/plugin/allure.js +0 -15
  177. package/lib/plugin/commentStep.js +0 -136
  178. package/lib/plugin/debugErrors.js +0 -67
  179. package/lib/plugin/eachElement.js +0 -127
  180. package/lib/plugin/fakerTransform.js +0 -49
  181. package/lib/plugin/retryTo.js +0 -127
  182. package/lib/plugin/selenoid.js +0 -384
  183. package/lib/plugin/standardActingHelpers.js +0 -3
  184. package/lib/plugin/tryTo.js +0 -115
  185. package/lib/plugin/wdio.js +0 -249
  186. package/lib/scenario.js +0 -224
  187. package/lib/ui.js +0 -236
  188. package/lib/within.js +0 -70
@@ -1,12 +1,12 @@
1
- const colors = require('chalk')
2
- const fs = require('fs')
3
- const inquirer = require('inquirer')
4
- const mkdirp = require('mkdirp')
5
- const path = require('path')
6
- const { fileExists, ucfirst, lcfirst, beautify } = require('../utils')
7
- const output = require('../output')
8
- const generateDefinitions = require('./definitions')
9
- const { getConfig, getTestRoot, safeFileWrite, readConfig } = require('./utils')
1
+ import colors from 'chalk'
2
+ import fs from 'fs'
3
+ import inquirer from 'inquirer'
4
+ import { mkdirp } from 'mkdirp'
5
+ import path from 'path'
6
+ import { fileExists, ucfirst, lcfirst, beautify } from '../utils.js'
7
+ import output from '../output.js'
8
+ import generateDefinitions from './definitions.js'
9
+ import { getConfig, getTestRoot, safeFileWrite, readConfig } from './utils.js'
10
10
 
11
11
  let extension = 'js'
12
12
 
@@ -18,10 +18,10 @@ Scenario('test something', async ({ {{actor}} }) => {
18
18
  `
19
19
 
20
20
  // generates empty test
21
- module.exports.test = function (genPath) {
21
+ export async function test(genPath) {
22
22
  const testsPath = getTestRoot(genPath)
23
23
  global.codecept_dir = testsPath
24
- const config = getConfig(testsPath)
24
+ const config = await getConfig(testsPath)
25
25
  if (!config) return
26
26
 
27
27
  output.print('Creating a new test...')
@@ -35,7 +35,7 @@ module.exports.test = function (genPath) {
35
35
  type: 'input',
36
36
  name: 'feature',
37
37
  message: 'Feature which is being tested (ex: account, login, etc)',
38
- validate: (val) => !!val,
38
+ validate: val => !!val,
39
39
  },
40
40
  {
41
41
  type: 'input',
@@ -46,7 +46,7 @@ module.exports.test = function (genPath) {
46
46
  },
47
47
  },
48
48
  ])
49
- .then((result) => {
49
+ .then(async result => {
50
50
  const testFilePath = path.dirname(path.join(testsPath, config.tests)).replace(/\*\*$/, '')
51
51
  let testFile = path.join(testFilePath, result.filename)
52
52
  const ext = path.extname(testFile)
@@ -55,17 +55,16 @@ module.exports.test = function (genPath) {
55
55
  if (!fileExists(dir)) mkdirp.sync(dir)
56
56
  let testContent = testTemplate.replace('{{feature}}', result.feature)
57
57
 
58
- const container = require('../container')
59
- container.create(config, {})
58
+ const containerModule = await import('../container.js')
59
+ const container = containerModule.default || containerModule
60
+ await container.create(config, {})
60
61
  // translate scenario test
61
62
  if (container.translation().loaded) {
62
63
  const vocabulary = container.translation().vocabulary
63
64
  testContent = testContent.replace('{{actor}}', container.translation().I)
64
65
  if (vocabulary.contexts.Feature) testContent = testContent.replace('Feature', vocabulary.contexts.Feature)
65
66
  if (vocabulary.contexts.Scenario) testContent = testContent.replace('Scenario', vocabulary.contexts.Scenario)
66
- output.print(
67
- `Test was created in ${colors.bold(config.translation)} localization. See: https://codecept.io/translation/`,
68
- )
67
+ output.print(`Test was created in ${colors.bold(config.translation)} localization. See: https://codecept.io/translation/`)
69
68
  } else {
70
69
  testContent = testContent.replace('{{actor}}', 'I')
71
70
  }
@@ -78,7 +77,7 @@ module.exports.test = function (genPath) {
78
77
 
79
78
  const pageObjectTemplate = `const { I } = inject();
80
79
 
81
- module.exports = {
80
+ export default {
82
81
 
83
82
  // insert your locators and methods here
84
83
  }
@@ -103,13 +102,13 @@ class {{name}} {
103
102
  }
104
103
 
105
104
  // For inheritance
106
- module.exports = new {{name}}();
107
- export = {{name}};
105
+ export default new {{name}}();
106
+ export { {{name}} };
108
107
  `
109
108
 
110
- module.exports.pageObject = function (genPath, opts) {
109
+ export async function pageObject(genPath, opts) {
111
110
  const testsPath = getTestRoot(genPath)
112
- const config = getConfig(testsPath)
111
+ const config = await getConfig(testsPath)
113
112
  const kind = opts.T || 'page'
114
113
  if (!config) return
115
114
 
@@ -128,13 +127,13 @@ module.exports.pageObject = function (genPath, opts) {
128
127
  type: 'input',
129
128
  name: 'name',
130
129
  message: `Name of a ${kind} object`,
131
- validate: (val) => !!val,
130
+ validate: val => !!val,
132
131
  },
133
132
  {
134
133
  type: 'input',
135
134
  name: 'filename',
136
135
  message: 'Where should it be stored',
137
- default: (answers) => `./${kind}s/${answers.name}.${extension}`,
136
+ default: answers => `./${kind}s/${answers.name}.${extension}`,
138
137
  },
139
138
  {
140
139
  type: 'list',
@@ -144,7 +143,7 @@ module.exports.pageObject = function (genPath, opts) {
144
143
  default: 'module',
145
144
  },
146
145
  ])
147
- .then((result) => {
146
+ .then(result => {
148
147
  const pageObjectFile = path.join(testsPath, result.filename)
149
148
  const dir = path.dirname(pageObjectFile)
150
149
  if (!fileExists(dir)) fs.mkdirSync(dir)
@@ -157,7 +156,7 @@ module.exports.pageObject = function (genPath, opts) {
157
156
  // relative path
158
157
  actorPath = path.relative(dir, path.dirname(path.join(testsPath, actorPath))) + actorPath.substring(1) // get an upper level
159
158
  }
160
- actor = `require('${actorPath}')`
159
+ actor = `import('${actorPath}')`
161
160
  }
162
161
 
163
162
  const name = lcfirst(result.name) + ucfirst(kind)
@@ -194,14 +193,12 @@ module.exports.pageObject = function (genPath, opts) {
194
193
  try {
195
194
  generateDefinitions(testsPath, {})
196
195
  } catch (_err) {
197
- output.print(
198
- `Run ${colors.green('npx codeceptjs def')} to update your types to get auto-completion for object.`,
199
- )
196
+ output.print(`Run ${colors.green('npx codeceptjs def')} to update your types to get auto-completion for object.`)
200
197
  }
201
198
  })
202
199
  }
203
200
 
204
- const helperTemplate = `const Helper = require('@codeceptjs/helper');
201
+ const helperTemplate = `import Helper from '@codeceptjs/helper';
205
202
 
206
203
  class {{name}} extends Helper {
207
204
 
@@ -226,10 +223,10 @@ class {{name}} extends Helper {
226
223
 
227
224
  }
228
225
 
229
- module.exports = {{name}};
226
+ export default {{name}};
230
227
  `
231
228
 
232
- module.exports.helper = function (genPath) {
229
+ export async function helper(genPath) {
233
230
  const testsPath = getTestRoot(genPath)
234
231
 
235
232
  output.print('Creating a new helper')
@@ -241,16 +238,16 @@ module.exports.helper = function (genPath) {
241
238
  type: 'input',
242
239
  name: 'name',
243
240
  message: 'Name of a Helper',
244
- validate: (val) => !!val,
241
+ validate: val => !!val,
245
242
  },
246
243
  {
247
244
  type: 'input',
248
245
  name: 'filename',
249
246
  message: 'Where should it be stored',
250
- default: (answers) => `./${answers.name.toLowerCase()}_helper.${extension}`,
247
+ default: answers => `./${answers.name.toLowerCase()}_helper.${extension}`,
251
248
  },
252
249
  ])
253
- .then((result) => {
250
+ .then(result => {
254
251
  const name = ucfirst(result.name)
255
252
  const helperFile = path.join(testsPath, result.filename)
256
253
  const dir = path.dirname(helperFile)
@@ -269,9 +266,11 @@ helpers: {
269
266
  })
270
267
  }
271
268
 
269
+ import { fileURLToPath } from 'url'
270
+ const __dirname = path.dirname(fileURLToPath(import.meta.url))
272
271
  const healTemplate = fs.readFileSync(path.join(__dirname, '../template/heal.js'), 'utf8').toString()
273
272
 
274
- module.exports.heal = function (genPath) {
273
+ export async function heal(genPath) {
275
274
  const testsPath = getTestRoot(genPath)
276
275
 
277
276
  let configFile = path.join(testsPath, `codecept.conf.${extension}`)
@@ -286,9 +285,9 @@ module.exports.heal = function (genPath) {
286
285
  output.print('Require this file in the config file and enable heal plugin:')
287
286
  output.print('--------------------------')
288
287
  output.print(`
289
- require('./heal')
288
+ import './heal.js'
290
289
 
291
- exports.config = {
290
+ export const config = {
292
291
  // ...
293
292
  plugins: {
294
293
  heal: {
@@ -1,11 +1,9 @@
1
- const path = require('path');
2
- const mkdirp = require('mkdirp');
1
+ import path from 'path'
2
+ import { mkdirp } from 'mkdirp'
3
3
 
4
- const output = require('../../output');
5
- const { fileExists } = require('../../utils');
6
- const {
7
- getConfig, getTestRoot, updateConfig, safeFileWrite, findConfigFile,
8
- } = require('../utils');
4
+ import output from '../../output.js'
5
+ import { fileExists } from '../../utils.js'
6
+ import { getConfig, getTestRoot, updateConfig, safeFileWrite, findConfigFile } from '../utils.js'
9
7
 
10
8
  const featureFile = `Feature: Business rules
11
9
  In order to achieve my goals
@@ -14,7 +12,7 @@ const featureFile = `Feature: Business rules
14
12
 
15
13
  Scenario: do something
16
14
  Given I have a defined step
17
- `;
15
+ `
18
16
 
19
17
  const stepsFile = `const { I } = inject();
20
18
  // Add in your custom step files
@@ -22,60 +20,60 @@ const stepsFile = `const { I } = inject();
22
20
  Given('I have a defined step', () => {
23
21
  // TODO: replace with your own step
24
22
  });
25
- `;
23
+ `
26
24
 
27
- module.exports = function (genPath) {
28
- const testsPath = getTestRoot(genPath);
29
- const configFile = findConfigFile(testsPath);
25
+ export default async function (genPath) {
26
+ const testsPath = getTestRoot(genPath)
27
+ const configFile = findConfigFile(testsPath)
30
28
 
31
29
  if (!configFile) {
32
- output.error(
33
- "Can't initialize Gherkin. This command must be run in an already initialized project.",
34
- );
35
- process.exit(1);
30
+ output.error("Can't initialize Gherkin. This command must be run in an already initialized project.")
31
+ process.exit(1)
36
32
  }
37
33
 
38
- const config = getConfig(testsPath);
39
- const extension = path.extname(configFile).substring(1);
34
+ const config = await getConfig(testsPath)
35
+ const extension = path.extname(configFile).substring(1)
40
36
 
41
- output.print('Initializing Gherkin (Cucumber BDD) for CodeceptJS');
42
- output.print('--------------------------');
37
+ output.print('Initializing Gherkin (Cucumber BDD) for CodeceptJS')
38
+ output.print('--------------------------')
43
39
 
44
40
  if (config.gherkin && config.gherkin.steps) {
45
- output.error('Gherkin is already initialized in this project. See `gherkin` section in the config');
46
- process.exit(1);
41
+ output.error('Gherkin is already initialized in this project. See `gherkin` section in the config')
42
+ process.exit(1)
47
43
  }
48
44
 
49
- let dir;
50
- dir = path.join(testsPath, 'features');
45
+ let dir
46
+ dir = path.join(testsPath, 'features')
51
47
  if (!fileExists(dir)) {
52
- mkdirp.sync(dir);
53
- output.success(`Created ${dir}, place your *.feature files in it`);
48
+ mkdirp.sync(dir)
49
+ // Use relative path for output
50
+ const relativeDir = path.relative(process.cwd(), dir)
51
+ output.success(`Created ${relativeDir}, place your *.feature files in it`)
54
52
  }
55
53
 
56
54
  if (safeFileWrite(path.join(dir, 'basic.feature'), featureFile)) {
57
- output.success('Created sample feature file: features/basic.feature');
55
+ output.success('Created sample feature file: features/basic.feature')
58
56
  }
59
57
 
60
- dir = path.join(testsPath, 'step_definitions');
58
+ dir = path.join(testsPath, 'step_definitions')
61
59
  if (!fileExists(dir)) {
62
- mkdirp.sync(dir);
63
- output.success(`Created ${dir}, place step definitions into it`);
60
+ mkdirp.sync(dir)
61
+ // Use relative path for output
62
+ const relativeDir = path.relative(process.cwd(), dir)
63
+ output.success(`Created ${relativeDir}, place step definitions into it`)
64
64
  }
65
65
 
66
66
  if (safeFileWrite(path.join(dir, `steps.${extension}`), stepsFile)) {
67
- output.success(
68
- `Created sample steps file: step_definitions/steps.${extension}`,
69
- );
67
+ output.success(`Created sample steps file: step_definitions/steps.${extension}`)
70
68
  }
71
69
 
72
70
  config.gherkin = {
73
71
  features: './features/*.feature',
74
72
  steps: [`./step_definitions/steps.${extension}`],
75
- };
73
+ }
76
74
 
77
- updateConfig(testsPath, config, extension);
75
+ updateConfig(testsPath, config, extension)
78
76
 
79
- output.success('Gherkin setup is done.');
80
- output.success('Start writing feature files and implement corresponding steps.');
81
- };
77
+ output.success('Gherkin setup is done.')
78
+ output.success('Start writing feature files and implement corresponding steps.')
79
+ }
@@ -1,132 +1,134 @@
1
- const escapeStringRegexp = require('escape-string-regexp');
2
- const fs = require('fs');
3
- const Gherkin = require('@cucumber/gherkin');
4
- const Messages = require('@cucumber/messages');
5
- const glob = require('glob');
6
- const fsPath = require('path');
1
+ import escapeStringRegexp from 'escape-string-regexp'
2
+ import fs from 'fs'
3
+ import Gherkin from '@cucumber/gherkin'
4
+ import { IdGenerator } from '@cucumber/messages'
5
+ import { globSync } from 'glob'
6
+ import fsPath from 'path'
7
7
 
8
- const { getConfig, getTestRoot } = require('../utils');
9
- const Codecept = require('../../codecept');
10
- const output = require('../../output');
11
- const { matchStep } = require('../../interfaces/bdd');
8
+ import { getConfig, getTestRoot } from '../utils.js'
9
+ import Codecept from '../../codecept.js'
10
+ import output from '../../output.js'
11
+ import { matchStep } from '../../mocha/bdd.js'
12
12
 
13
- const uuidFn = Messages.IdGenerator.uuid();
14
- const builder = new Gherkin.AstBuilder(uuidFn);
15
- const matcher = new Gherkin.GherkinClassicTokenMatcher();
16
- const parser = new Gherkin.Parser(builder, matcher);
17
- parser.stopAtFirstError = false;
13
+ const uuidFn = IdGenerator.uuid()
14
+ const builder = new Gherkin.AstBuilder(uuidFn)
15
+ const matcher = new Gherkin.GherkinClassicTokenMatcher()
16
+ const parser = new Gherkin.Parser(builder, matcher)
17
+ parser.stopAtFirstError = false
18
18
 
19
- module.exports = function (genPath, options) {
20
- const configFile = options.config || genPath;
21
- const testsPath = getTestRoot(configFile);
22
- const config = getConfig(configFile);
23
- if (!config) return;
19
+ export default async function (genPath, options) {
20
+ const configFile = options.config || genPath
21
+ const testsPath = getTestRoot(configFile)
22
+ const config = await getConfig(configFile)
23
+ if (!config) return
24
24
 
25
- const codecept = new Codecept(config, {});
26
- codecept.init(testsPath);
25
+ const codecept = new Codecept(config, {})
26
+ await codecept.init(testsPath)
27
27
 
28
28
  if (!config.gherkin) {
29
- output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it');
30
- process.exit(1);
29
+ output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it')
30
+ process.exit(1)
31
31
  }
32
32
  if (!config.gherkin.steps || !config.gherkin.steps[0]) {
33
- output.error('No gherkin steps defined in config. Exiting');
34
- process.exit(1);
33
+ output.error('No gherkin steps defined in config. Exiting')
34
+ process.exit(1)
35
35
  }
36
36
  if (!options.feature && !config.gherkin.features) {
37
- output.error('No gherkin features defined in config. Exiting');
38
- process.exit(1);
37
+ output.error('No gherkin features defined in config. Exiting')
38
+ process.exit(1)
39
39
  }
40
40
  if (options.path && !config.gherkin.steps.includes(options.path)) {
41
- output.error(`You must include ${options.path} to the gherkin steps in your config file`);
42
- process.exit(1);
41
+ output.error(`You must include ${options.path} to the gherkin steps in your config file`)
42
+ process.exit(1)
43
43
  }
44
44
 
45
- const files = [];
46
- glob.sync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }).forEach((file) => {
45
+ const files = []
46
+ globSync(options.feature || config.gherkin.features, { cwd: options.feature ? '.' : global.codecept_dir }).forEach(file => {
47
47
  if (!fsPath.isAbsolute(file)) {
48
- file = fsPath.join(global.codecept_dir, file);
48
+ file = fsPath.join(global.codecept_dir, file)
49
49
  }
50
- files.push(fsPath.resolve(file));
51
- });
52
- output.print(`Loaded ${files.length} files`);
50
+ files.push(fsPath.resolve(file))
51
+ })
52
+ output.print(`Loaded ${files.length} files`)
53
53
 
54
- const newSteps = new Map();
54
+ const newSteps = new Map()
55
55
 
56
- const parseSteps = (steps) => {
57
- const newSteps = [];
58
- let currentKeyword = '';
56
+ const parseSteps = steps => {
57
+ const newSteps = []
58
+ let currentKeyword = ''
59
59
  for (const step of steps) {
60
60
  if (step.keyword.trim() === 'And') {
61
- if (!currentKeyword) throw new Error(`There is no active keyword for step '${step.text}'`);
62
- step.keyword = currentKeyword;
61
+ if (!currentKeyword) throw new Error(`There is no active keyword for step '${step.text}'`)
62
+ step.keyword = currentKeyword
63
63
  }
64
- currentKeyword = step.keyword;
64
+ currentKeyword = step.keyword
65
65
  try {
66
- matchStep(step.text);
66
+ matchStep(step.text)
67
67
  } catch (err) {
68
- let stepLine;
68
+ let stepLine
69
69
  if (/[{}()/]/.test(step.text)) {
70
70
  stepLine = escapeStringRegexp(step.text)
71
71
  .replace(/\//g, '\\/')
72
72
  .replace(/\"(.*?)\"/g, '"(.*?)"')
73
73
  .replace(/(\d+\\\.\d+)/, '(\\d+\\.\\d+)')
74
- .replace(/ (\d+) /, ' (\\d+) ');
75
- stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: true });
74
+ .replace(/ (\d+) /, ' (\\d+) ')
75
+ stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: true })
76
76
  } else {
77
77
  stepLine = step.text
78
78
  .replace(/\"(.*?)\"/g, '{string}')
79
79
  .replace(/(\d+\.\d+)/, '{float}')
80
- .replace(/ (\d+) /, ' {int} ');
81
- stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: false });
80
+ .replace(/ (\d+) /, ' {int} ')
81
+ stepLine = Object.assign(stepLine, { type: step.keyword.trim(), location: step.location, regexp: false })
82
82
  }
83
- newSteps.push(stepLine);
83
+ newSteps.push(stepLine)
84
84
  }
85
85
  }
86
- return newSteps;
87
- };
86
+ return newSteps
87
+ }
88
88
 
89
- const parseFile = (file) => {
90
- const ast = parser.parse(fs.readFileSync(file).toString());
89
+ const parseFile = file => {
90
+ const ast = parser.parse(fs.readFileSync(file).toString())
91
91
  for (const child of ast.feature.children) {
92
- if (child.scenario.keyword === 'Scenario Outline') continue; // skip scenario outline
93
- parseSteps(child.scenario.steps).map((step) => {
94
- return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) });
95
- }).map((step) => newSteps.set(`${step.type}(${step})`, step));
92
+ if (child.scenario.keyword === 'Scenario Outline') continue // skip scenario outline
93
+ parseSteps(child.scenario.steps)
94
+ .map(step => {
95
+ return Object.assign(step, { file: file.replace(global.codecept_dir, '').slice(1) })
96
+ })
97
+ .map(step => newSteps.set(`${step.type}(${step})`, step))
96
98
  }
97
- };
99
+ }
98
100
 
99
- files.forEach(file => parseFile(file));
101
+ files.forEach(file => parseFile(file))
100
102
 
101
- let stepFile = options.path || config.gherkin.steps[0];
103
+ let stepFile = options.path || config.gherkin.steps[0]
102
104
  if (!fs.existsSync(stepFile)) {
103
- output.error(`Please enter a valid step file path ${stepFile}`);
104
- process.exit(1);
105
+ output.error(`Please enter a valid step file path ${stepFile}`)
106
+ process.exit(1)
105
107
  }
106
108
 
107
109
  if (!fsPath.isAbsolute(stepFile)) {
108
- stepFile = fsPath.join(global.codecept_dir, stepFile);
110
+ stepFile = fsPath.join(global.codecept_dir, stepFile)
109
111
  }
110
112
 
111
113
  const snippets = [...newSteps.values()]
112
114
  .filter((value, index, self) => self.indexOf(value) === index)
113
- .map((step) => {
115
+ .map(step => {
114
116
  return `
115
117
  ${step.type}(${step.regexp ? '/^' : "'"}${step}${step.regexp ? '$/' : "'"}, () => {
116
118
  // From "${step.file}" ${JSON.stringify(step.location)}
117
119
  throw new Error('Not implemented yet');
118
- });`;
119
- });
120
+ });`
121
+ })
120
122
 
121
123
  if (!snippets.length) {
122
- output.print('No new snippets found');
123
- return;
124
+ output.print('No new snippets found')
125
+ return
124
126
  }
125
- output.success(`Snippets generated: ${snippets.length}`);
126
- output.print(snippets.join('\n'));
127
+ output.success(`Snippets generated: ${snippets.length}`)
128
+ output.print(snippets.join('\n'))
127
129
 
128
130
  if (!options.dryRun) {
129
- output.success(`Snippets added to ${output.colors.bold(stepFile)}`);
130
- fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n');
131
+ output.success(`Snippets added to ${output.colors.bold(stepFile)}`)
132
+ fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n')
131
133
  }
132
- };
134
+ }
@@ -1,25 +1,28 @@
1
- const { getConfig, getTestRoot } = require('../utils');
2
- const Codecept = require('../../codecept');
3
- const output = require('../../output');
4
- const { getSteps } = require('../../interfaces/bdd');
1
+ import { getConfig, getTestRoot } from '../utils.js'
2
+ import Codecept from '../../codecept.js'
3
+ import output from '../../output.js'
4
+ import { getSteps, clearSteps } from '../../mocha/bdd.js'
5
5
 
6
- module.exports = function (genPath, options) {
7
- const configFile = options.config || genPath;
8
- const testsPath = getTestRoot(configFile);
9
- const config = getConfig(configFile);
10
- if (!config) return;
6
+ export default async function (genPath, options) {
7
+ const configFile = options.config || genPath
8
+ const testsPath = getTestRoot(configFile)
9
+ const config = await getConfig(configFile)
10
+ if (!config) return
11
11
 
12
- const codecept = new Codecept(config, {});
13
- codecept.init(testsPath);
12
+ // Clear any previously loaded steps
13
+ clearSteps()
14
+
15
+ const codecept = new Codecept(config, {})
16
+ await codecept.init(testsPath)
14
17
 
15
- output.print('Gherkin Step Definitions:');
16
- output.print();
17
- const steps = getSteps();
18
+ output.print('Gherkin Step Definitions:')
19
+ output.print()
20
+ const steps = getSteps()
18
21
  for (const step of Object.keys(steps)) {
19
- output.print(` ${output.colors.bold(step)} ${output.colors.green(steps[step].line || '')}`);
22
+ output.print(` ${output.colors.bold(step)} ${output.colors.green(steps[step].line || '')}`)
20
23
  }
21
- output.print();
24
+ output.print()
22
25
  if (!Object.keys(steps).length) {
23
- output.error('No Gherkin steps defined');
26
+ output.error('No Gherkin steps defined')
24
27
  }
25
- };
28
+ }