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.
- package/bin/codecept.js +81 -84
- package/lib/actor.js +13 -13
- package/lib/ai.js +13 -10
- package/lib/assert/empty.js +21 -20
- package/lib/assert/equal.js +39 -37
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +47 -46
- package/lib/assert/throws.js +11 -13
- package/lib/assert/truth.js +22 -19
- package/lib/assert.js +2 -4
- package/lib/cli.js +49 -57
- package/lib/codecept.js +155 -142
- package/lib/colorUtils.js +3 -3
- package/lib/command/configMigrate.js +52 -58
- package/lib/command/definitions.js +89 -88
- package/lib/command/dryRun.js +68 -71
- package/lib/command/generate.js +188 -197
- package/lib/command/gherkin/init.js +16 -27
- package/lib/command/gherkin/snippets.js +20 -20
- package/lib/command/gherkin/steps.js +8 -8
- package/lib/command/info.js +38 -40
- package/lib/command/init.js +288 -290
- package/lib/command/interactive.js +32 -32
- package/lib/command/list.js +26 -26
- package/lib/command/run-multiple/chunk.js +5 -5
- package/lib/command/run-multiple/collection.js +3 -3
- package/lib/command/run-multiple/run.js +2 -6
- package/lib/command/run-multiple.js +93 -113
- package/lib/command/run-rerun.js +25 -20
- package/lib/command/run-workers.js +66 -64
- package/lib/command/run.js +29 -26
- package/lib/command/utils.js +65 -80
- package/lib/command/workers/runTests.js +10 -10
- package/lib/config.js +9 -10
- package/lib/container.js +48 -40
- package/lib/data/context.js +59 -60
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +20 -26
- package/lib/dirname.js +5 -0
- package/lib/event.js +167 -163
- package/lib/heal.js +17 -13
- package/lib/helper/AI.js +41 -130
- package/lib/helper/ApiDataFactory.js +69 -73
- package/lib/helper/Appium.js +381 -412
- package/lib/helper/Expect.js +425 -0
- package/lib/helper/ExpectHelper.js +48 -40
- package/lib/helper/FileSystem.js +79 -80
- package/lib/helper/GraphQL.js +43 -44
- package/lib/helper/GraphQLDataFactory.js +50 -50
- package/lib/helper/JSONResponse.js +62 -65
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +14 -12
- package/lib/helper/Nightmare.js +566 -662
- package/lib/helper/Playwright.js +1216 -1361
- package/lib/helper/Protractor.js +627 -663
- package/lib/helper/Puppeteer.js +1128 -1231
- package/lib/helper/REST.js +68 -159
- package/lib/helper/SoftExpectHelper.js +2 -2
- package/lib/helper/TestCafe.js +484 -490
- package/lib/helper/WebDriver.js +1156 -1297
- package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
- package/lib/helper/errors/ConnectionRefused.js +1 -1
- package/lib/helper/errors/ElementAssertion.js +2 -2
- package/lib/helper/errors/ElementNotFound.js +2 -2
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +1 -1
- package/lib/helper/extras/Console.js +1 -1
- package/lib/helper/extras/PlaywrightPropEngine.js +2 -2
- package/lib/helper/extras/PlaywrightReactVueLocator.js +1 -1
- package/lib/helper/extras/PlaywrightRestartOpts.js +18 -21
- package/lib/helper/extras/Popup.js +1 -1
- package/lib/helper/extras/React.js +3 -3
- package/lib/helper/network/actions.js +7 -14
- package/lib/helper/network/utils.js +2 -3
- package/lib/helper/scripts/blurElement.js +1 -1
- package/lib/helper/scripts/focusElement.js +1 -1
- package/lib/helper/scripts/highlightElement.js +1 -1
- package/lib/helper/scripts/isElementClickable.js +1 -1
- package/lib/helper/testcafe/testControllerHolder.js +1 -1
- package/lib/helper/testcafe/testcafe-utils.js +7 -6
- package/lib/helper.js +3 -1
- package/lib/history.js +5 -6
- package/lib/hooks.js +6 -6
- package/lib/html.js +7 -7
- package/lib/index.js +41 -25
- package/lib/interfaces/bdd.js +64 -47
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +118 -124
- package/lib/interfaces/scenarioConfig.js +29 -29
- package/lib/listener/artifacts.js +9 -9
- package/lib/listener/config.js +24 -24
- package/lib/listener/exit.js +12 -12
- package/lib/listener/helpers.js +42 -42
- package/lib/listener/mocha.js +11 -11
- package/lib/listener/retry.js +30 -32
- package/lib/listener/steps.js +53 -50
- package/lib/listener/timeout.js +54 -54
- package/lib/locator.js +10 -6
- package/lib/mochaFactory.js +15 -18
- package/lib/output.js +10 -6
- package/lib/parser.js +12 -15
- package/lib/pause.js +33 -40
- package/lib/plugin/allure.js +15 -15
- package/lib/plugin/autoDelay.js +37 -29
- package/lib/plugin/autoLogin.js +65 -70
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +67 -115
- package/lib/plugin/customLocator.js +20 -21
- package/lib/plugin/debugErrors.js +24 -24
- package/lib/plugin/eachElement.js +38 -38
- package/lib/plugin/fakerTransform.js +6 -6
- package/lib/plugin/heal.js +108 -67
- package/lib/plugin/pauseOnFail.js +11 -11
- package/lib/plugin/retryFailedStep.js +39 -32
- package/lib/plugin/retryTo.js +40 -46
- package/lib/plugin/screenshotOnFail.js +87 -109
- package/lib/plugin/selenoid.js +118 -131
- package/lib/plugin/standardActingHelpers.js +8 -2
- package/lib/plugin/stepByStepReport.js +91 -110
- package/lib/plugin/stepTimeout.js +23 -24
- package/lib/plugin/subtitles.js +35 -34
- package/lib/plugin/tryTo.js +30 -40
- package/lib/plugin/wdio.js +75 -78
- package/lib/recorder.js +17 -14
- package/lib/rerun.js +10 -11
- package/lib/scenario.js +23 -25
- package/lib/secret.js +2 -4
- package/lib/session.js +10 -10
- package/lib/step.js +9 -12
- package/lib/store.js +3 -2
- package/lib/transform.js +1 -1
- package/lib/translation.js +8 -7
- package/lib/ui.js +14 -12
- package/lib/utils.js +72 -70
- package/lib/within.js +10 -10
- package/lib/workerStorage.js +25 -27
- package/lib/workers.js +32 -29
- package/package.json +53 -51
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +13 -9
- package/translations/it-IT.js +1 -1
- package/translations/ja-JP.js +1 -1
- package/translations/pl-PL.js +1 -1
- package/translations/pt-BR.js +1 -1
- package/translations/ru-RU.js +1 -1
- package/translations/zh-CN.js +1 -1
- package/translations/zh-TW.js +1 -1
- package/typings/index.d.ts +65 -415
package/lib/command/generate.js
CHANGED
|
@@ -1,80 +1,81 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
174
|
-
|
|
171
|
+
let data = readConfig(configFile);
|
|
172
|
+
config.include[name] = result.filename;
|
|
175
173
|
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
177
|
+
data = data.replace(/include:[\s\S][^\}]*/i, `${currentInclude},`);
|
|
180
178
|
|
|
181
|
-
|
|
179
|
+
fs.writeFileSync(configFile, beautify(data), 'utf-8');
|
|
182
180
|
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
192
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
233
|
-
const testsPath = getTestRoot(genPath)
|
|
234
|
-
|
|
235
|
-
output.print('Creating a new helper')
|
|
236
|
-
output.print('--------------------------')
|
|
237
|
-
|
|
238
|
-
return inquirer
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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, '
|
|
263
|
+
const healTemplate = fs.readFileSync(path.join(__dirname, '/template/heal.js'), 'utf8').toString();
|
|
273
264
|
|
|
274
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
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,
|
|
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: [
|
|
61
|
+
steps: [
|
|
62
|
+
'./step_definitions/steps.js',
|
|
63
|
+
],
|
|
75
64
|
};
|
|
76
65
|
|
|
77
|
-
updateConfig(testsPath, config
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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
|
+
}
|