codeceptjs 4.0.0-beta.2 → 4.0.0-beta.3

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 (151) hide show
  1. package/bin/codecept.js +84 -81
  2. package/lib/actor.js +13 -13
  3. package/lib/ai.js +10 -13
  4. package/lib/assert/empty.js +20 -21
  5. package/lib/assert/equal.js +37 -39
  6. package/lib/assert/error.js +14 -14
  7. package/lib/assert/include.js +46 -47
  8. package/lib/assert/throws.js +13 -11
  9. package/lib/assert/truth.js +19 -22
  10. package/lib/assert.js +4 -2
  11. package/lib/cli.js +57 -49
  12. package/lib/codecept.js +142 -155
  13. package/lib/colorUtils.js +3 -3
  14. package/lib/command/configMigrate.js +58 -52
  15. package/lib/command/definitions.js +88 -89
  16. package/lib/command/dryRun.js +71 -68
  17. package/lib/command/generate.js +197 -188
  18. package/lib/command/gherkin/init.js +27 -16
  19. package/lib/command/gherkin/snippets.js +20 -20
  20. package/lib/command/gherkin/steps.js +8 -8
  21. package/lib/command/info.js +40 -38
  22. package/lib/command/init.js +290 -288
  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 +6 -2
  28. package/lib/command/run-multiple.js +113 -93
  29. package/lib/command/run-rerun.js +20 -25
  30. package/lib/command/run-workers.js +64 -66
  31. package/lib/command/run.js +26 -29
  32. package/lib/command/utils.js +80 -65
  33. package/lib/command/workers/runTests.js +10 -10
  34. package/lib/config.js +10 -9
  35. package/lib/container.js +40 -48
  36. package/lib/data/context.js +60 -59
  37. package/lib/data/dataScenarioConfig.js +47 -47
  38. package/lib/data/dataTableArgument.js +29 -29
  39. package/lib/data/table.js +26 -20
  40. package/lib/event.js +163 -167
  41. package/lib/heal.js +13 -17
  42. package/lib/helper/AI.js +130 -41
  43. package/lib/helper/ApiDataFactory.js +73 -69
  44. package/lib/helper/Appium.js +413 -382
  45. package/lib/helper/ExpectHelper.js +40 -48
  46. package/lib/helper/FileSystem.js +80 -79
  47. package/lib/helper/GraphQL.js +44 -43
  48. package/lib/helper/GraphQLDataFactory.js +50 -50
  49. package/lib/helper/JSONResponse.js +65 -62
  50. package/lib/helper/Mochawesome.js +28 -28
  51. package/lib/helper/MockServer.js +12 -14
  52. package/lib/helper/Nightmare.js +662 -566
  53. package/lib/helper/Playwright.js +1361 -1216
  54. package/lib/helper/Protractor.js +663 -627
  55. package/lib/helper/Puppeteer.js +1231 -1128
  56. package/lib/helper/REST.js +159 -68
  57. package/lib/helper/SoftExpectHelper.js +2 -2
  58. package/lib/helper/TestCafe.js +490 -484
  59. package/lib/helper/WebDriver.js +1297 -1156
  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 +2 -2
  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 +3 -2
  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 +6 -7
  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 +6 -10
  97. package/lib/mochaFactory.js +18 -15
  98. package/lib/output.js +6 -10
  99. package/lib/parser.js +15 -12
  100. package/lib/pause.js +40 -33
  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 +115 -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 -2
  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 -32
  136. package/package.json +56 -57
  137. package/translations/de-DE.js +1 -1
  138. package/translations/fr-FR.js +1 -1
  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 +415 -65
  148. package/typings/promiseBasedTypes.d.ts +32 -0
  149. package/typings/types.d.ts +32 -0
  150. package/lib/dirname.js +0 -5
  151. package/lib/helper/Expect.js +0 -425
@@ -1,81 +1,80 @@
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';
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'
18
12
 
19
13
  const testTemplate = `Feature('{{feature}}');
20
14
 
21
15
  Scenario('test something', async ({ {{actor}} }) => {
22
16
 
23
17
  });
24
- `;
18
+ `
25
19
 
26
20
  // generates empty test
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;
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,
51
39
  },
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', '');
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', '')
74
73
 
75
- if (!safeFileWrite(testFile, testContent)) return;
76
- output.success(`\nTest for ${result.filename} was created in ${testFile}`);
77
- });
78
- };
74
+ if (!safeFileWrite(testFile, testContent)) return
75
+ output.success(`\nTest for ${result.filename} was created in ${testFile}`)
76
+ })
77
+ }
79
78
 
80
79
  const pageObjectTemplate = `const { I } = inject();
81
80
 
@@ -83,7 +82,7 @@ module.exports = {
83
82
 
84
83
  // insert your locators and methods here
85
84
  }
86
- `;
85
+ `
87
86
 
88
87
  const poModuleTemplateTS = `const { I } = inject();
89
88
 
@@ -91,7 +90,7 @@ export = {
91
90
 
92
91
  // insert your locators and methods here
93
92
  }
94
- `;
93
+ `
95
94
 
96
95
  const poClassTemplate = `const { I } = inject();
97
96
 
@@ -106,96 +105,101 @@ class {{name}} {
106
105
  // For inheritance
107
106
  module.exports = new {{name}}();
108
107
  export = {{name}};
109
- `;
108
+ `
110
109
 
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;
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
116
115
 
117
- let configFile = path.join(testsPath, `codecept.conf.${extension}`);
116
+ let configFile = path.join(testsPath, `codecept.conf.${extension}`)
118
117
 
119
118
  if (!fileExists(configFile)) {
120
- extension = 'ts';
121
- configFile = path.join(testsPath, `codecept.conf.${extension}`);
119
+ extension = 'ts'
120
+ configFile = path.join(testsPath, `codecept.conf.${extension}`)
122
121
  }
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
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}')`
157
161
  }
158
- actor = `require('${actorPath}')`;
159
- }
160
162
 
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
- }
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
+ }
170
172
 
171
- let data = readConfig(configFile);
172
- config.include[name] = result.filename;
173
+ let data = readConfig(configFile)
174
+ config.include[name] = result.filename
173
175
 
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])}`;
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])}`
176
178
 
177
- data = data.replace(/include:[\s\S][^\}]*/i, `${currentInclude},`);
179
+ data = data.replace(/include:[\s\S][^\}]*/i, `${currentInclude},`)
178
180
 
179
- fs.writeFileSync(configFile, beautify(data), 'utf-8');
181
+ fs.writeFileSync(configFile, beautify(data), 'utf-8')
180
182
 
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:
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:
183
185
 
184
186
  include: {
185
187
  ...
186
188
  ${name}: '${result.filename}',
187
- },`);
189
+ },`)
188
190
 
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`);
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`)
191
193
 
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
- };
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
+ }
199
203
 
200
204
  const helperTemplate = `const Helper = require('@codeceptjs/helper');
201
205
 
@@ -223,73 +227,78 @@ class {{name}} extends Helper {
223
227
  }
224
228
 
225
229
  module.exports = {{name}};
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):
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):
253
262
 
254
263
  helpers: {
255
264
  ${name}: {
256
265
  require: '${result.filename}',
257
266
  },
258
267
  },
259
- `);
260
- });
261
- };
268
+ `)
269
+ })
270
+ }
262
271
 
263
- const healTemplate = fs.readFileSync(path.join(__dirname, '/template/heal.js'), 'utf8').toString();
272
+ const healTemplate = fs.readFileSync(path.join(__dirname, '../template/heal.js'), 'utf8').toString()
264
273
 
265
- export function heal(genPath) {
266
- const testsPath = getTestRoot(genPath);
274
+ module.exports.heal = function (genPath) {
275
+ const testsPath = getTestRoot(genPath)
267
276
 
268
- let configFile = path.join(testsPath, `codecept.conf.${extension}`);
277
+ let configFile = path.join(testsPath, `codecept.conf.${extension}`)
269
278
 
270
279
  if (!fileExists(configFile)) {
271
- configFile = path.join(testsPath, `codecept.conf.${extension}`);
272
- if (fileExists(configFile)) extension = 'ts';
280
+ configFile = path.join(testsPath, `codecept.conf.${extension}`)
281
+ if (fileExists(configFile)) extension = 'ts'
273
282
  }
274
283
 
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('--------------------------');
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('--------------------------')
279
288
  output.print(`
280
289
  require('./heal')
281
290
 
282
291
  exports.config = {
283
- // ...
292
+ // ...
284
293
  plugins: {
285
294
  heal: {
286
295
  enabled: true
287
296
  }
288
297
  }
289
298
  }
290
- `);
299
+ `)
291
300
 
292
- const healFile = path.join(testsPath, `heal.${extension}`);
293
- if (!safeFileWrite(healFile, healTemplate)) return;
294
- output.success(`Heal recipes were created in ${healFile}`);
295
- };
301
+ const healFile = path.join(testsPath, `heal.${extension}`)
302
+ if (!safeFileWrite(healFile, healTemplate)) return
303
+ output.success(`Heal recipes were created in ${healFile}`)
304
+ }
@@ -1,10 +1,11 @@
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';
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');
8
9
 
9
10
  const featureFile = `Feature: Business rules
10
11
  In order to achieve my goals
@@ -23,15 +24,25 @@ Given('I have a defined step', () => {
23
24
  });
24
25
  `;
25
26
 
26
- export default function (genPath) {
27
+ module.exports = function (genPath) {
27
28
  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
+
28
38
  const config = getConfig(testsPath);
39
+ const extension = path.extname(configFile).substring(1);
29
40
 
30
41
  output.print('Initializing Gherkin (Cucumber BDD) for CodeceptJS');
31
42
  output.print('--------------------------');
32
43
 
33
44
  if (config.gherkin && config.gherkin.steps) {
34
- output.output.error('Gherkin is already initialized in this project. See `gherkin` section in the config');
45
+ output.error('Gherkin is already initialized in this project. See `gherkin` section in the config');
35
46
  process.exit(1);
36
47
  }
37
48
 
@@ -52,19 +63,19 @@ export default function (genPath) {
52
63
  output.success(`Created ${dir}, place step definitions into it`);
53
64
  }
54
65
 
55
- if (safeFileWrite(path.join(dir, 'steps.js'), stepsFile)) {
56
- output.success('Created sample steps file: step_definitions/steps.js');
66
+ if (safeFileWrite(path.join(dir, `steps.${extension}`), stepsFile)) {
67
+ output.success(
68
+ `Created sample steps file: step_definitions/steps.${extension}`,
69
+ );
57
70
  }
58
71
 
59
72
  config.gherkin = {
60
73
  features: './features/*.feature',
61
- steps: [
62
- './step_definitions/steps.js',
63
- ],
74
+ steps: [`./step_definitions/steps.${extension}`],
64
75
  };
65
76
 
66
- updateConfig(testsPath, config);
77
+ updateConfig(testsPath, config, extension);
67
78
 
68
79
  output.success('Gherkin setup is done.');
69
80
  output.success('Start writing feature files and implement corresponding steps.');
70
- }
81
+ };
@@ -1,13 +1,14 @@
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';
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');
11
12
 
12
13
  const uuidFn = Messages.IdGenerator.uuid();
13
14
  const builder = new Gherkin.AstBuilder(uuidFn);
@@ -15,7 +16,7 @@ const matcher = new Gherkin.GherkinClassicTokenMatcher();
15
16
  const parser = new Gherkin.Parser(builder, matcher);
16
17
  parser.stopAtFirstError = false;
17
18
 
18
- export default function (genPath, options) {
19
+ module.exports = function (genPath, options) {
19
20
  const configFile = options.config || genPath;
20
21
  const testsPath = getTestRoot(configFile);
21
22
  const config = getConfig(configFile);
@@ -25,19 +26,19 @@ export default function (genPath, options) {
25
26
  codecept.init(testsPath);
26
27
 
27
28
  if (!config.gherkin) {
28
- output.output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it');
29
+ output.error('Gherkin is not enabled in config. Run `codecept gherkin:init` to enable it');
29
30
  process.exit(1);
30
31
  }
31
32
  if (!config.gherkin.steps || !config.gherkin.steps[0]) {
32
- output.output.error('No gherkin steps defined in config. Exiting');
33
+ output.error('No gherkin steps defined in config. Exiting');
33
34
  process.exit(1);
34
35
  }
35
36
  if (!options.feature && !config.gherkin.features) {
36
- output.output.error('No gherkin features defined in config. Exiting');
37
+ output.error('No gherkin features defined in config. Exiting');
37
38
  process.exit(1);
38
39
  }
39
40
  if (options.path && !config.gherkin.steps.includes(options.path)) {
40
- output.output.error(`You must include ${options.path} to the gherkin steps in your config file`);
41
+ output.error(`You must include ${options.path} to the gherkin steps in your config file`);
41
42
  process.exit(1);
42
43
  }
43
44
 
@@ -86,7 +87,6 @@ export default function (genPath, options) {
86
87
  };
87
88
 
88
89
  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 @@ export default function (genPath, options) {
100
100
 
101
101
  let stepFile = options.path || config.gherkin.steps[0];
102
102
  if (!fs.existsSync(stepFile)) {
103
- output.output.error(`Please enter a valid step file path ${stepFile}`);
103
+ 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.output.success(`Snippets generated: ${snippets.length}`);
125
+ output.success(`Snippets generated: ${snippets.length}`);
126
126
  output.print(snippets.join('\n'));
127
127
 
128
128
  if (!options.dryRun) {
129
- output.output.success(`Snippets added to ${output.output.colors.bold(stepFile)}`);
129
+ output.success(`Snippets added to ${output.colors.bold(stepFile)}`);
130
130
  fs.writeFileSync(stepFile, fs.readFileSync(stepFile).toString() + snippets.join('\n') + '\n'); // eslint-disable-line
131
131
  }
132
- }
132
+ };