codeceptjs 3.6.7 → 4.0.0-beta.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 (149) hide show
  1. package/bin/codecept.js +81 -84
  2. package/lib/actor.js +13 -13
  3. package/lib/ai.js +13 -10
  4. package/lib/assert/empty.js +21 -20
  5. package/lib/assert/equal.js +39 -37
  6. package/lib/assert/error.js +14 -14
  7. package/lib/assert/include.js +47 -46
  8. package/lib/assert/throws.js +11 -13
  9. package/lib/assert/truth.js +22 -19
  10. package/lib/assert.js +2 -4
  11. package/lib/cli.js +49 -57
  12. package/lib/codecept.js +155 -142
  13. package/lib/colorUtils.js +3 -3
  14. package/lib/command/configMigrate.js +52 -58
  15. package/lib/command/definitions.js +89 -88
  16. package/lib/command/dryRun.js +68 -71
  17. package/lib/command/generate.js +188 -197
  18. package/lib/command/gherkin/init.js +16 -27
  19. package/lib/command/gherkin/snippets.js +20 -20
  20. package/lib/command/gherkin/steps.js +8 -8
  21. package/lib/command/info.js +38 -40
  22. package/lib/command/init.js +288 -290
  23. package/lib/command/interactive.js +32 -32
  24. package/lib/command/list.js +26 -26
  25. package/lib/command/run-multiple/chunk.js +5 -5
  26. package/lib/command/run-multiple/collection.js +3 -3
  27. package/lib/command/run-multiple/run.js +2 -6
  28. package/lib/command/run-multiple.js +93 -113
  29. package/lib/command/run-rerun.js +25 -20
  30. package/lib/command/run-workers.js +66 -64
  31. package/lib/command/run.js +29 -26
  32. package/lib/command/utils.js +65 -80
  33. package/lib/command/workers/runTests.js +10 -10
  34. package/lib/config.js +9 -10
  35. package/lib/container.js +48 -40
  36. package/lib/data/context.js +59 -60
  37. package/lib/data/dataScenarioConfig.js +47 -47
  38. package/lib/data/dataTableArgument.js +29 -29
  39. package/lib/data/table.js +20 -26
  40. package/lib/dirname.js +5 -0
  41. package/lib/event.js +167 -163
  42. package/lib/heal.js +17 -13
  43. package/lib/helper/AI.js +41 -130
  44. package/lib/helper/ApiDataFactory.js +69 -73
  45. package/lib/helper/Appium.js +381 -412
  46. package/lib/helper/Expect.js +425 -0
  47. package/lib/helper/ExpectHelper.js +48 -40
  48. package/lib/helper/FileSystem.js +79 -80
  49. package/lib/helper/GraphQL.js +43 -44
  50. package/lib/helper/GraphQLDataFactory.js +50 -50
  51. package/lib/helper/JSONResponse.js +62 -65
  52. package/lib/helper/Mochawesome.js +28 -28
  53. package/lib/helper/MockServer.js +14 -12
  54. package/lib/helper/Nightmare.js +566 -662
  55. package/lib/helper/Playwright.js +1216 -1361
  56. package/lib/helper/Protractor.js +627 -663
  57. package/lib/helper/Puppeteer.js +1128 -1231
  58. package/lib/helper/REST.js +68 -159
  59. package/lib/helper/SoftExpectHelper.js +2 -2
  60. package/lib/helper/TestCafe.js +484 -490
  61. package/lib/helper/WebDriver.js +1156 -1297
  62. package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
  63. package/lib/helper/errors/ConnectionRefused.js +1 -1
  64. package/lib/helper/errors/ElementAssertion.js +2 -2
  65. package/lib/helper/errors/ElementNotFound.js +2 -2
  66. package/lib/helper/errors/RemoteBrowserConnectionRefused.js +1 -1
  67. package/lib/helper/extras/Console.js +1 -1
  68. package/lib/helper/extras/PlaywrightPropEngine.js +2 -2
  69. package/lib/helper/extras/PlaywrightReactVueLocator.js +1 -1
  70. package/lib/helper/extras/PlaywrightRestartOpts.js +18 -21
  71. package/lib/helper/extras/Popup.js +1 -1
  72. package/lib/helper/extras/React.js +3 -3
  73. package/lib/helper/network/actions.js +7 -14
  74. package/lib/helper/network/utils.js +2 -3
  75. package/lib/helper/scripts/blurElement.js +1 -1
  76. package/lib/helper/scripts/focusElement.js +1 -1
  77. package/lib/helper/scripts/highlightElement.js +1 -1
  78. package/lib/helper/scripts/isElementClickable.js +1 -1
  79. package/lib/helper/testcafe/testControllerHolder.js +1 -1
  80. package/lib/helper/testcafe/testcafe-utils.js +7 -6
  81. package/lib/helper.js +3 -1
  82. package/lib/history.js +5 -6
  83. package/lib/hooks.js +6 -6
  84. package/lib/html.js +7 -7
  85. package/lib/index.js +41 -25
  86. package/lib/interfaces/bdd.js +64 -47
  87. package/lib/interfaces/featureConfig.js +19 -19
  88. package/lib/interfaces/gherkin.js +118 -124
  89. package/lib/interfaces/scenarioConfig.js +29 -29
  90. package/lib/listener/artifacts.js +9 -9
  91. package/lib/listener/config.js +24 -24
  92. package/lib/listener/exit.js +12 -12
  93. package/lib/listener/helpers.js +42 -42
  94. package/lib/listener/mocha.js +11 -11
  95. package/lib/listener/retry.js +30 -32
  96. package/lib/listener/steps.js +53 -50
  97. package/lib/listener/timeout.js +54 -54
  98. package/lib/locator.js +10 -6
  99. package/lib/mochaFactory.js +15 -18
  100. package/lib/output.js +10 -6
  101. package/lib/parser.js +12 -15
  102. package/lib/pause.js +33 -40
  103. package/lib/plugin/allure.js +15 -15
  104. package/lib/plugin/autoDelay.js +37 -29
  105. package/lib/plugin/autoLogin.js +65 -70
  106. package/lib/plugin/commentStep.js +18 -18
  107. package/lib/plugin/coverage.js +67 -115
  108. package/lib/plugin/customLocator.js +20 -21
  109. package/lib/plugin/debugErrors.js +24 -24
  110. package/lib/plugin/eachElement.js +38 -38
  111. package/lib/plugin/fakerTransform.js +6 -6
  112. package/lib/plugin/heal.js +108 -67
  113. package/lib/plugin/pauseOnFail.js +11 -11
  114. package/lib/plugin/retryFailedStep.js +39 -32
  115. package/lib/plugin/retryTo.js +40 -46
  116. package/lib/plugin/screenshotOnFail.js +87 -109
  117. package/lib/plugin/selenoid.js +118 -131
  118. package/lib/plugin/standardActingHelpers.js +8 -2
  119. package/lib/plugin/stepByStepReport.js +91 -110
  120. package/lib/plugin/stepTimeout.js +23 -24
  121. package/lib/plugin/subtitles.js +35 -34
  122. package/lib/plugin/tryTo.js +30 -40
  123. package/lib/plugin/wdio.js +75 -78
  124. package/lib/recorder.js +17 -14
  125. package/lib/rerun.js +10 -11
  126. package/lib/scenario.js +23 -25
  127. package/lib/secret.js +2 -4
  128. package/lib/session.js +10 -10
  129. package/lib/step.js +9 -12
  130. package/lib/store.js +3 -2
  131. package/lib/transform.js +1 -1
  132. package/lib/translation.js +8 -7
  133. package/lib/ui.js +14 -12
  134. package/lib/utils.js +72 -70
  135. package/lib/within.js +10 -10
  136. package/lib/workerStorage.js +25 -27
  137. package/lib/workers.js +32 -29
  138. package/package.json +53 -51
  139. package/translations/de-DE.js +1 -1
  140. package/translations/fr-FR.js +1 -1
  141. package/translations/index.js +13 -9
  142. package/translations/it-IT.js +1 -1
  143. package/translations/ja-JP.js +1 -1
  144. package/translations/pl-PL.js +1 -1
  145. package/translations/pt-BR.js +1 -1
  146. package/translations/ru-RU.js +1 -1
  147. package/translations/zh-CN.js +1 -1
  148. package/translations/zh-TW.js +1 -1
  149. package/typings/index.d.ts +65 -415
@@ -1,80 +1,81 @@
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')
10
-
11
- let extension = 'js'
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 {
7
+ fileExists, ucfirst, lcfirst, beautify,
8
+ } from '../utils.js';
9
+ import { output } from '../output.js';
10
+ import generateDefinitions from './definitions.js';
11
+ import {
12
+ getConfig, getTestRoot, safeFileWrite, readConfig,
13
+ } from './utils.js';
14
+ import container from '../container.js';
15
+ import { __dirname } from '../dirname.js';
16
+
17
+ let extension = 'js';
12
18
 
13
19
  const testTemplate = `Feature('{{feature}}');
14
20
 
15
21
  Scenario('test something', async ({ {{actor}} }) => {
16
22
 
17
23
  });
18
- `
24
+ `;
19
25
 
20
26
  // generates empty test
21
- module.exports.test = function (genPath) {
22
- const testsPath = getTestRoot(genPath)
23
- global.codecept_dir = testsPath
24
- const config = getConfig(testsPath)
25
- if (!config) return
26
-
27
- output.print('Creating a new test...')
28
- output.print('----------------------')
29
-
30
- const defaultExt = config.tests.match(/([^\*/]*?)$/)[1] || `_test.${extension}`
31
-
32
- return inquirer
33
- .prompt([
34
- {
35
- type: 'input',
36
- name: 'feature',
37
- message: 'Feature which is being tested (ex: account, login, etc)',
38
- validate: (val) => !!val,
27
+ export const test = function (genPath) {
28
+ const testsPath = getTestRoot(genPath);
29
+ global.codecept_dir = testsPath;
30
+ const config = getConfig(testsPath);
31
+ if (!config) return;
32
+
33
+ output.print('Creating a new test...');
34
+ output.print('----------------------');
35
+
36
+ const defaultExt = config.tests.match(/([^\*/]*?)$/)[1] || `_test.${extension}`;
37
+
38
+ return inquirer.prompt([
39
+ {
40
+ type: 'input',
41
+ name: 'feature',
42
+ message: 'Feature which is being tested (ex: account, login, etc)',
43
+ validate: (val) => !!val,
44
+ },
45
+ {
46
+ type: 'input',
47
+ message: 'Filename of a test',
48
+ name: 'filename',
49
+ default(answers) {
50
+ return (answers.feature).replace(' ', '_') + defaultExt;
39
51
  },
40
- {
41
- type: 'input',
42
- message: 'Filename of a test',
43
- name: 'filename',
44
- default(answers) {
45
- return answers.feature.replace(' ', '_') + defaultExt
46
- },
47
- },
48
- ])
49
- .then((result) => {
50
- const testFilePath = path.dirname(path.join(testsPath, config.tests)).replace(/\*\*$/, '')
51
- let testFile = path.join(testFilePath, result.filename)
52
- const ext = path.extname(testFile)
53
- if (!ext) testFile += defaultExt
54
- const dir = path.dirname(testFile)
55
- if (!fileExists(dir)) mkdirp.sync(dir)
56
- let testContent = testTemplate.replace('{{feature}}', result.feature)
57
-
58
- const container = require('../container')
59
- container.create(config, {})
60
- // translate scenario test
61
- if (container.translation().loaded) {
62
- const vocabulary = container.translation().vocabulary
63
- testContent = testContent.replace('{{actor}}', container.translation().I)
64
- if (vocabulary.contexts.Feature) testContent = testContent.replace('Feature', vocabulary.contexts.Feature)
65
- 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
- )
69
- } else {
70
- testContent = testContent.replace('{{actor}}', 'I')
71
- }
72
- if (!config.fullPromiseBased) testContent = testContent.replace('async', '')
52
+ },
53
+ ]).then((result) => {
54
+ const testFilePath = path.dirname(path.join(testsPath, config.tests)).replace(/\*\*$/, '');
55
+ let testFile = path.join(testFilePath, result.filename);
56
+ const ext = path.extname(testFile);
57
+ if (!ext) testFile += defaultExt;
58
+ const dir = path.dirname(testFile);
59
+ if (!fileExists(dir)) mkdirp.sync(dir);
60
+ let testContent = testTemplate.replace('{{feature}}', result.feature);
61
+
62
+ container.create(config, {});
63
+ // translate scenario test
64
+ if (container.translation().loaded) {
65
+ const vocabulary = container.translation().vocabulary;
66
+ testContent = testContent.replace('{{actor}}', container.translation().I);
67
+ if (vocabulary.contexts.Feature) testContent = testContent.replace('Feature', vocabulary.contexts.Feature);
68
+ if (vocabulary.contexts.Scenario) testContent = testContent.replace('Scenario', vocabulary.contexts.Scenario);
69
+ output.print(`Test was created in ${colors.bold(config.translation)} localization. See: https://codecept.io/translation/`);
70
+ } else {
71
+ testContent = testContent.replace('{{actor}}', 'I');
72
+ }
73
+ if (!config.fullPromiseBased) testContent = testContent.replace('async', '');
73
74
 
74
- if (!safeFileWrite(testFile, testContent)) return
75
- output.success(`\nTest for ${result.filename} was created in ${testFile}`)
76
- })
77
- }
75
+ if (!safeFileWrite(testFile, testContent)) return;
76
+ output.success(`\nTest for ${result.filename} was created in ${testFile}`);
77
+ });
78
+ };
78
79
 
79
80
  const pageObjectTemplate = `const { I } = inject();
80
81
 
@@ -82,7 +83,7 @@ module.exports = {
82
83
 
83
84
  // insert your locators and methods here
84
85
  }
85
- `
86
+ `;
86
87
 
87
88
  const poModuleTemplateTS = `const { I } = inject();
88
89
 
@@ -90,7 +91,7 @@ export = {
90
91
 
91
92
  // insert your locators and methods here
92
93
  }
93
- `
94
+ `;
94
95
 
95
96
  const poClassTemplate = `const { I } = inject();
96
97
 
@@ -105,101 +106,96 @@ class {{name}} {
105
106
  // For inheritance
106
107
  module.exports = new {{name}}();
107
108
  export = {{name}};
108
- `
109
+ `;
109
110
 
110
- module.exports.pageObject = function (genPath, opts) {
111
- const testsPath = getTestRoot(genPath)
112
- const config = getConfig(testsPath)
113
- const kind = opts.T || 'page'
114
- if (!config) return
111
+ export const pageObject = function (genPath, opts) {
112
+ const testsPath = getTestRoot(genPath);
113
+ const config = getConfig(testsPath);
114
+ const kind = opts.T || 'page';
115
+ if (!config) return;
115
116
 
116
- let configFile = path.join(testsPath, `codecept.conf.${extension}`)
117
+ let configFile = path.join(testsPath, `codecept.conf.${extension}`);
117
118
 
118
119
  if (!fileExists(configFile)) {
119
- extension = 'ts'
120
- configFile = path.join(testsPath, `codecept.conf.${extension}`)
120
+ extension = 'ts';
121
+ configFile = path.join(testsPath, `codecept.conf.${extension}`);
121
122
  }
122
- output.print(`Creating a new ${kind} object`)
123
- output.print('--------------------------')
124
-
125
- return inquirer
126
- .prompt([
127
- {
128
- type: 'input',
129
- name: 'name',
130
- message: `Name of a ${kind} object`,
131
- validate: (val) => !!val,
132
- },
133
- {
134
- type: 'input',
135
- name: 'filename',
136
- message: 'Where should it be stored',
137
- default: (answers) => `./${kind}s/${answers.name}.${extension}`,
138
- },
139
- {
140
- type: 'list',
141
- name: 'objectType',
142
- message: 'What is your preferred object type',
143
- choices: ['module', 'class'],
144
- default: 'module',
145
- },
146
- ])
147
- .then((result) => {
148
- const pageObjectFile = path.join(testsPath, result.filename)
149
- const dir = path.dirname(pageObjectFile)
150
- if (!fileExists(dir)) fs.mkdirSync(dir)
151
-
152
- let actor = 'actor'
153
-
154
- if (config.include.I) {
155
- let actorPath = config.include.I
156
- if (actorPath.charAt(0) === '.') {
157
- // relative path
158
- actorPath = path.relative(dir, path.dirname(path.join(testsPath, actorPath))) + actorPath.substring(1) // get an upper level
159
- }
160
- actor = `require('${actorPath}')`
123
+ output.print(`Creating a new ${kind} object`);
124
+ output.print('--------------------------');
125
+
126
+ return inquirer.prompt([
127
+ {
128
+ type: 'input',
129
+ name: 'name',
130
+ message: `Name of a ${kind} object`,
131
+ validate: (val) => !!val,
132
+ },
133
+ {
134
+ type: 'input',
135
+ name: 'filename',
136
+ message: 'Where should it be stored',
137
+ default: answers => `./${kind}s/${answers.name}.${extension}`,
138
+ },
139
+ {
140
+ type: 'list',
141
+ name: 'objectType',
142
+ message: 'What is your preferred object type',
143
+ choices: ['module', 'class'],
144
+ default: 'module',
145
+ },
146
+ ]).then((result) => {
147
+ const pageObjectFile = path.join(testsPath, result.filename);
148
+ const dir = path.dirname(pageObjectFile);
149
+ if (!fileExists(dir)) fs.mkdirSync(dir);
150
+
151
+ let actor = 'actor';
152
+
153
+ if (config.include.I) {
154
+ let actorPath = config.include.I;
155
+ if (actorPath.charAt(0) === '.') { // relative path
156
+ actorPath = path.relative(dir, path.dirname(path.join(testsPath, actorPath))) + actorPath.substring(1); // get an upper level
161
157
  }
158
+ actor = `require('${actorPath}')`;
159
+ }
162
160
 
163
- const name = lcfirst(result.name) + ucfirst(kind)
164
- if (result.objectType === 'module' && extension === 'ts') {
165
- if (!safeFileWrite(pageObjectFile, poModuleTemplateTS.replace('{{actor}}', actor))) return
166
- } else if (result.objectType === 'module' && extension === 'js') {
167
- if (!safeFileWrite(pageObjectFile, pageObjectTemplate.replace('{{actor}}', actor))) return
168
- } else if (result.objectType === 'class') {
169
- const content = poClassTemplate.replace(/{{actor}}/g, actor).replace(/{{name}}/g, name)
170
- if (!safeFileWrite(pageObjectFile, content)) return
171
- }
161
+ const name = lcfirst(result.name) + ucfirst(kind);
162
+ if (result.objectType === 'module' && extension === 'ts') {
163
+ if (!safeFileWrite(pageObjectFile, poModuleTemplateTS.replace('{{actor}}', actor))) return;
164
+ } else if (result.objectType === 'module' && extension === 'js') {
165
+ if (!safeFileWrite(pageObjectFile, pageObjectTemplate.replace('{{actor}}', actor))) return;
166
+ } else if (result.objectType === 'class') {
167
+ const content = poClassTemplate.replace(/{{actor}}/g, actor).replace(/{{name}}/g, name);
168
+ if (!safeFileWrite(pageObjectFile, content)) return;
169
+ }
172
170
 
173
- let data = readConfig(configFile)
174
- config.include[name] = result.filename
171
+ let data = readConfig(configFile);
172
+ config.include[name] = result.filename;
175
173
 
176
- if (!data) throw Error('Config file is empty')
177
- const currentInclude = `${data.match(/include:[\s\S][^\}]*/i)[0]}\n ${name}:${JSON.stringify(config.include[name])}`
174
+ if (!data) throw Error('Config file is empty');
175
+ const currentInclude = `${data.match(/include:[\s\S][^\}]*/i)[0]}\n ${name}:${JSON.stringify(config.include[name])}`;
178
176
 
179
- data = data.replace(/include:[\s\S][^\}]*/i, `${currentInclude},`)
177
+ data = data.replace(/include:[\s\S][^\}]*/i, `${currentInclude},`);
180
178
 
181
- fs.writeFileSync(configFile, beautify(data), 'utf-8')
179
+ fs.writeFileSync(configFile, beautify(data), 'utf-8');
182
180
 
183
- output.success(`${ucfirst(kind)} object for ${result.name} was created in ${pageObjectFile}`)
184
- output.print(`Your config file (${colors.cyan('include')} section) has included the new created PO:
181
+ output.success(`${ucfirst(kind)} object for ${result.name} was created in ${pageObjectFile}`);
182
+ output.print(`Your config file (${colors.cyan('include')} section) has included the new created PO:
185
183
 
186
184
  include: {
187
185
  ...
188
186
  ${name}: '${result.filename}',
189
- },`)
187
+ },`);
190
188
 
191
- output.print(`Use ${output.colors.bold(colors.cyan(name))} as parameter in test scenarios to access this object:`)
192
- output.print(`\nScenario('my new test', ({ I, ${name} })) { /** ... */ }\n`)
189
+ output.print(`Use ${output.colors.bold(colors.cyan(name))} as parameter in test scenarios to access this object:`);
190
+ output.print(`\nScenario('my new test', ({ I, ${name} })) { /** ... */ }\n`);
193
191
 
194
- try {
195
- generateDefinitions(testsPath, {})
196
- } catch (_err) {
197
- output.print(
198
- `Run ${colors.green('npx codeceptjs def')} to update your types to get auto-completion for object.`,
199
- )
200
- }
201
- })
202
- }
192
+ try {
193
+ generateDefinitions(testsPath, {});
194
+ } catch (_err) {
195
+ output.print(`Run ${colors.green('npx codeceptjs def')} to update your types to get auto-completion for object.`);
196
+ }
197
+ });
198
+ };
203
199
 
204
200
  const helperTemplate = `const Helper = require('@codeceptjs/helper');
205
201
 
@@ -227,78 +223,73 @@ class {{name}} extends Helper {
227
223
  }
228
224
 
229
225
  module.exports = {{name}};
230
- `
231
-
232
- module.exports.helper = function (genPath) {
233
- const testsPath = getTestRoot(genPath)
234
-
235
- output.print('Creating a new helper')
236
- output.print('--------------------------')
237
-
238
- return inquirer
239
- .prompt([
240
- {
241
- type: 'input',
242
- name: 'name',
243
- message: 'Name of a Helper',
244
- validate: (val) => !!val,
245
- },
246
- {
247
- type: 'input',
248
- name: 'filename',
249
- message: 'Where should it be stored',
250
- default: (answers) => `./${answers.name.toLowerCase()}_helper.${extension}`,
251
- },
252
- ])
253
- .then((result) => {
254
- const name = ucfirst(result.name)
255
- const helperFile = path.join(testsPath, result.filename)
256
- const dir = path.dirname(helperFile)
257
- if (!fileExists(dir)) fs.mkdirSync(dir)
258
-
259
- if (!safeFileWrite(helperFile, helperTemplate.replace(/{{name}}/g, name))) return
260
- output.success(`Helper for ${name} was created in ${helperFile}`)
261
- output.print(`Update your config file (add to ${colors.cyan('helpers')} section):
226
+ `;
227
+
228
+ export const helper = function (genPath) {
229
+ const testsPath = getTestRoot(genPath);
230
+
231
+ output.print('Creating a new helper');
232
+ output.print('--------------------------');
233
+
234
+ return inquirer.prompt([{
235
+ type: 'input',
236
+ name: 'name',
237
+ message: 'Name of a Helper',
238
+ validate: (val) => !!val,
239
+ }, {
240
+ type: 'input',
241
+ name: 'filename',
242
+ message: 'Where should it be stored',
243
+ default: answers => `./${answers.name.toLowerCase()}_helper.${extension}`,
244
+ }]).then((result) => {
245
+ const name = ucfirst(result.name);
246
+ const helperFile = path.join(testsPath, result.filename);
247
+ const dir = path.dirname(helperFile);
248
+ if (!fileExists(dir)) fs.mkdirSync(dir);
249
+
250
+ if (!safeFileWrite(helperFile, helperTemplate.replace(/{{name}}/g, name))) return;
251
+ output.success(`Helper for ${name} was created in ${helperFile}`);
252
+ output.print(`Update your config file (add to ${colors.cyan('helpers')} section):
262
253
 
263
254
  helpers: {
264
255
  ${name}: {
265
256
  require: '${result.filename}',
266
257
  },
267
258
  },
268
- `)
269
- })
270
- }
259
+ `);
260
+ });
261
+ };
271
262
 
272
- const healTemplate = fs.readFileSync(path.join(__dirname, '../template/heal.js'), 'utf8').toString()
263
+ const healTemplate = fs.readFileSync(path.join(__dirname, '/template/heal.js'), 'utf8').toString();
273
264
 
274
- module.exports.heal = function (genPath) {
275
- const testsPath = getTestRoot(genPath)
265
+ export function heal(genPath) {
266
+ const testsPath = getTestRoot(genPath);
276
267
 
277
- let configFile = path.join(testsPath, `codecept.conf.${extension}`)
268
+ let configFile = path.join(testsPath, `codecept.conf.${extension}`);
278
269
 
279
270
  if (!fileExists(configFile)) {
280
- configFile = path.join(testsPath, `codecept.conf.${extension}`)
281
- if (fileExists(configFile)) extension = 'ts'
271
+ configFile = path.join(testsPath, `codecept.conf.${extension}`);
272
+ if (fileExists(configFile)) extension = 'ts';
282
273
  }
283
274
 
284
- output.print('Creating basic heal recipes')
285
- output.print(`Add your own custom recipes to ./heal.${extension} file`)
286
- output.print('Require this file in the config file and enable heal plugin:')
287
- output.print('--------------------------')
275
+ output.print('Creating basic heal recipes');
276
+ output.print(`Add your own custom recipes to ./heal.${extension} file`);
277
+ output.print('Require this file in the config file and enable heal plugin:');
278
+ output.print('--------------------------');
288
279
  output.print(`
289
280
  require('./heal')
290
281
 
291
282
  exports.config = {
292
- // ...
283
+ // ...
293
284
  plugins: {
294
285
  heal: {
295
286
  enabled: true
296
287
  }
297
288
  }
298
289
  }
299
- `)
290
+ `);
300
291
 
301
- const healFile = path.join(testsPath, `heal.${extension}`)
302
- if (!safeFileWrite(healFile, healTemplate)) return
303
- output.success(`Heal recipes were created in ${healFile}`)
304
- }
292
+ const healFile = path.join(testsPath, `heal.${extension}`);
293
+ if (!safeFileWrite(healFile, healTemplate)) return;
294
+ output.success(`Heal recipes were created in ${healFile}`);
295
+ };
@@ -1,11 +1,10 @@
1
- const path = require('path');
2
- const mkdirp = require('mkdirp');
3
-
4
- const output = require('../../output');
5
- const { fileExists } = require('../../utils');
6
- const {
7
- getConfig, getTestRoot, updateConfig, safeFileWrite, findConfigFile,
8
- } = require('../utils');
1
+ import path from 'path';
2
+ import mkdirp from 'mkdirp';
3
+ import * as output from '../../output.js';
4
+ import { fileExists } from '../../utils.js';
5
+ import {
6
+ getConfig, getTestRoot, updateConfig, safeFileWrite,
7
+ } from '../utils.js';
9
8
 
10
9
  const featureFile = `Feature: Business rules
11
10
  In order to achieve my goals
@@ -24,25 +23,15 @@ Given('I have a defined step', () => {
24
23
  });
25
24
  `;
26
25
 
27
- module.exports = function (genPath) {
26
+ export default function (genPath) {
28
27
  const testsPath = getTestRoot(genPath);
29
- const configFile = findConfigFile(testsPath);
30
-
31
- 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);
36
- }
37
-
38
28
  const config = getConfig(testsPath);
39
- const extension = path.extname(configFile).substring(1);
40
29
 
41
30
  output.print('Initializing Gherkin (Cucumber BDD) for CodeceptJS');
42
31
  output.print('--------------------------');
43
32
 
44
33
  if (config.gherkin && config.gherkin.steps) {
45
- output.error('Gherkin is already initialized in this project. See `gherkin` section in the config');
34
+ output.output.error('Gherkin is already initialized in this project. See `gherkin` section in the config');
46
35
  process.exit(1);
47
36
  }
48
37
 
@@ -63,19 +52,19 @@ module.exports = function (genPath) {
63
52
  output.success(`Created ${dir}, place step definitions into it`);
64
53
  }
65
54
 
66
- if (safeFileWrite(path.join(dir, `steps.${extension}`), stepsFile)) {
67
- output.success(
68
- `Created sample steps file: step_definitions/steps.${extension}`,
69
- );
55
+ if (safeFileWrite(path.join(dir, 'steps.js'), stepsFile)) {
56
+ output.success('Created sample steps file: step_definitions/steps.js');
70
57
  }
71
58
 
72
59
  config.gherkin = {
73
60
  features: './features/*.feature',
74
- steps: [`./step_definitions/steps.${extension}`],
61
+ steps: [
62
+ './step_definitions/steps.js',
63
+ ],
75
64
  };
76
65
 
77
- updateConfig(testsPath, config, extension);
66
+ updateConfig(testsPath, config);
78
67
 
79
68
  output.success('Gherkin setup is done.');
80
69
  output.success('Start writing feature files and implement corresponding steps.');
81
- };
70
+ }
@@ -1,14 +1,13 @@
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');
7
-
8
- const { getConfig, getTestRoot } = require('../utils');
9
- const Codecept = require('../../codecept');
10
- const output = require('../../output');
11
- const { matchStep } = require('../../interfaces/bdd');
1
+ import escapeStringRegexp from 'escape-string-regexp';
2
+ import fs from 'fs';
3
+ import Gherkin from '@cucumber/gherkin';
4
+ import * as Messages from '@cucumber/messages';
5
+ import glob from 'glob';
6
+ import fsPath from 'path';
7
+ import { getConfig, getTestRoot } from '../utils.js';
8
+ import Codecept from '../../codecept.js';
9
+ import * as output from '../../output.js';
10
+ import { matchStep } from '../../interfaces/bdd.js';
12
11
 
13
12
  const uuidFn = Messages.IdGenerator.uuid();
14
13
  const builder = new Gherkin.AstBuilder(uuidFn);
@@ -16,7 +15,7 @@ const matcher = new Gherkin.GherkinClassicTokenMatcher();
16
15
  const parser = new Gherkin.Parser(builder, matcher);
17
16
  parser.stopAtFirstError = false;
18
17
 
19
- module.exports = function (genPath, options) {
18
+ export default function (genPath, options) {
20
19
  const configFile = options.config || genPath;
21
20
  const testsPath = getTestRoot(configFile);
22
21
  const config = getConfig(configFile);
@@ -26,19 +25,19 @@ module.exports = function (genPath, options) {
26
25
  codecept.init(testsPath);
27
26
 
28
27
  if (!config.gherkin) {
29
- output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it');
28
+ output.output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it');
30
29
  process.exit(1);
31
30
  }
32
31
  if (!config.gherkin.steps || !config.gherkin.steps[0]) {
33
- output.error('No gherkin steps defined in config. Exiting');
32
+ output.output.error('No gherkin steps defined in config. Exiting');
34
33
  process.exit(1);
35
34
  }
36
35
  if (!options.feature && !config.gherkin.features) {
37
- output.error('No gherkin features defined in config. Exiting');
36
+ output.output.error('No gherkin features defined in config. Exiting');
38
37
  process.exit(1);
39
38
  }
40
39
  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`);
40
+ output.output.error(`You must include ${options.path} to the gherkin steps in your config file`);
42
41
  process.exit(1);
43
42
  }
44
43
 
@@ -87,6 +86,7 @@ module.exports = function (genPath, options) {
87
86
  };
88
87
 
89
88
  const parseFile = (file) => {
89
+ console.log(file);
90
90
  const ast = parser.parse(fs.readFileSync(file).toString());
91
91
  for (const child of ast.feature.children) {
92
92
  if (child.scenario.keyword === 'Scenario Outline') continue; // skip scenario outline
@@ -100,7 +100,7 @@ module.exports = function (genPath, options) {
100
100
 
101
101
  let stepFile = options.path || config.gherkin.steps[0];
102
102
  if (!fs.existsSync(stepFile)) {
103
- output.error(`Please enter a valid step file path ${stepFile}`);
103
+ output.output.error(`Please enter a valid step file path ${stepFile}`);
104
104
  process.exit(1);
105
105
  }
106
106
 
@@ -122,11 +122,11 @@ ${step.type}(${step.regexp ? '/^' : "'"}${step}${step.regexp ? '$/' : "'"}, () =
122
122
  output.print('No new snippets found');
123
123
  return;
124
124
  }
125
- output.success(`Snippets generated: ${snippets.length}`);
125
+ output.output.success(`Snippets generated: ${snippets.length}`);
126
126
  output.print(snippets.join('\n'));
127
127
 
128
128
  if (!options.dryRun) {
129
- output.success(`Snippets added to ${output.colors.bold(stepFile)}`);
129
+ output.output.success(`Snippets added to ${output.output.colors.bold(stepFile)}`);
130
130
  fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n'); // eslint-disable-line
131
131
  }
132
- };
132
+ }