codeceptjs 3.6.10 → 3.7.0-beta.10
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/README.md +89 -119
- package/bin/codecept.js +9 -2
- package/docs/webapi/clearCookie.mustache +1 -1
- package/lib/actor.js +66 -102
- package/lib/ai.js +130 -121
- package/lib/assert/empty.js +3 -5
- package/lib/assert/equal.js +4 -7
- package/lib/assert/include.js +4 -6
- package/lib/assert/throws.js +2 -4
- package/lib/assert/truth.js +2 -2
- package/lib/codecept.js +87 -83
- package/lib/command/check.js +186 -0
- package/lib/command/configMigrate.js +2 -4
- package/lib/command/definitions.js +8 -26
- package/lib/command/generate.js +10 -14
- package/lib/command/gherkin/snippets.js +10 -8
- package/lib/command/gherkin/steps.js +1 -1
- package/lib/command/info.js +1 -3
- package/lib/command/init.js +8 -12
- package/lib/command/interactive.js +2 -2
- package/lib/command/list.js +1 -1
- package/lib/command/run-multiple.js +12 -35
- package/lib/command/run-workers.js +5 -57
- package/lib/command/utils.js +5 -6
- package/lib/command/workers/runTests.js +68 -232
- package/lib/container.js +354 -237
- package/lib/data/context.js +10 -13
- package/lib/data/dataScenarioConfig.js +8 -8
- package/lib/data/dataTableArgument.js +6 -6
- package/lib/data/table.js +5 -11
- package/lib/effects.js +218 -0
- package/lib/els.js +158 -0
- package/lib/event.js +19 -17
- package/lib/heal.js +88 -80
- package/lib/helper/AI.js +2 -1
- package/lib/helper/ApiDataFactory.js +3 -6
- package/lib/helper/Appium.js +45 -51
- package/lib/helper/FileSystem.js +3 -3
- package/lib/helper/GraphQLDataFactory.js +3 -3
- package/lib/helper/JSONResponse.js +57 -37
- package/lib/helper/Nightmare.js +35 -53
- package/lib/helper/Playwright.js +211 -252
- package/lib/helper/Protractor.js +54 -77
- package/lib/helper/Puppeteer.js +139 -232
- package/lib/helper/REST.js +5 -17
- package/lib/helper/TestCafe.js +21 -44
- package/lib/helper/WebDriver.js +131 -169
- package/lib/helper/testcafe/testcafe-utils.js +26 -27
- package/lib/listener/emptyRun.js +55 -0
- package/lib/listener/exit.js +7 -10
- package/lib/listener/{retry.js → globalRetry.js} +5 -5
- package/lib/listener/globalTimeout.js +165 -0
- package/lib/listener/helpers.js +15 -15
- package/lib/listener/mocha.js +1 -1
- package/lib/listener/result.js +12 -0
- package/lib/listener/steps.js +20 -18
- package/lib/listener/store.js +20 -0
- package/lib/mocha/asyncWrapper.js +216 -0
- package/lib/{interfaces → mocha}/bdd.js +3 -3
- package/lib/mocha/cli.js +308 -0
- package/lib/mocha/factory.js +104 -0
- package/lib/{interfaces → mocha}/featureConfig.js +24 -12
- package/lib/{interfaces → mocha}/gherkin.js +26 -28
- package/lib/mocha/hooks.js +112 -0
- package/lib/mocha/index.js +12 -0
- package/lib/mocha/inject.js +29 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +21 -6
- package/lib/mocha/suite.js +81 -0
- package/lib/mocha/test.js +159 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +219 -0
- package/lib/output.js +82 -62
- package/lib/pause.js +155 -138
- package/lib/plugin/analyze.js +349 -0
- package/lib/plugin/autoDelay.js +6 -6
- package/lib/plugin/autoLogin.js +6 -7
- package/lib/plugin/commentStep.js +6 -1
- package/lib/plugin/coverage.js +10 -19
- package/lib/plugin/customLocator.js +3 -3
- package/lib/plugin/customReporter.js +52 -0
- package/lib/plugin/eachElement.js +1 -1
- package/lib/plugin/fakerTransform.js +1 -1
- package/lib/plugin/heal.js +36 -9
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/retryFailedStep.js +4 -4
- package/lib/plugin/retryTo.js +18 -118
- package/lib/plugin/screenshotOnFail.js +17 -49
- package/lib/plugin/selenoid.js +15 -35
- package/lib/plugin/standardActingHelpers.js +4 -1
- package/lib/plugin/stepByStepReport.js +56 -17
- package/lib/plugin/stepTimeout.js +5 -12
- package/lib/plugin/subtitles.js +4 -4
- package/lib/plugin/tryTo.js +17 -107
- package/lib/plugin/wdio.js +8 -10
- package/lib/recorder.js +146 -125
- package/lib/rerun.js +43 -42
- package/lib/result.js +161 -0
- package/lib/secret.js +1 -1
- package/lib/step/base.js +228 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +21 -332
- package/lib/steps.js +50 -0
- package/lib/store.js +10 -2
- package/lib/template/heal.js +2 -11
- package/lib/timeout.js +66 -0
- package/lib/utils.js +317 -216
- package/lib/within.js +73 -55
- package/lib/workers.js +259 -275
- package/package.json +56 -54
- package/typings/index.d.ts +175 -186
- package/typings/promiseBasedTypes.d.ts +164 -17
- package/typings/types.d.ts +284 -115
- package/lib/cli.js +0 -256
- package/lib/helper/ExpectHelper.js +0 -391
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -113
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/scenario.js +0 -224
- package/lib/ui.js +0 -236
package/lib/codecept.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
const { existsSync, readFileSync } = require('fs')
|
|
2
|
-
const glob = require('glob')
|
|
3
|
-
const fsPath = require('path')
|
|
4
|
-
const { resolve } = require('path')
|
|
5
|
-
|
|
6
|
-
const container = require('./container')
|
|
7
|
-
const Config = require('./config')
|
|
8
|
-
const event = require('./event')
|
|
9
|
-
const runHook = require('./hooks')
|
|
10
|
-
const output = require('./output')
|
|
11
|
-
const { emptyFolder } = require('./utils')
|
|
1
|
+
const { existsSync, readFileSync } = require('fs')
|
|
2
|
+
const glob = require('glob')
|
|
3
|
+
const fsPath = require('path')
|
|
4
|
+
const { resolve } = require('path')
|
|
5
|
+
|
|
6
|
+
const container = require('./container')
|
|
7
|
+
const Config = require('./config')
|
|
8
|
+
const event = require('./event')
|
|
9
|
+
const runHook = require('./hooks')
|
|
10
|
+
const output = require('./output')
|
|
11
|
+
const { emptyFolder } = require('./utils')
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* CodeceptJS runner
|
|
@@ -22,10 +22,10 @@ class Codecept {
|
|
|
22
22
|
* @param {*} opts
|
|
23
23
|
*/
|
|
24
24
|
constructor(config, opts) {
|
|
25
|
-
this.config = Config.create(config)
|
|
26
|
-
this.opts = opts
|
|
27
|
-
this.testFiles = new Array(0)
|
|
28
|
-
this.requireModules(config.require)
|
|
25
|
+
this.config = Config.create(config)
|
|
26
|
+
this.opts = opts
|
|
27
|
+
this.testFiles = new Array(0)
|
|
28
|
+
this.requireModules(config.require)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -35,13 +35,13 @@ class Codecept {
|
|
|
35
35
|
*/
|
|
36
36
|
requireModules(requiringModules) {
|
|
37
37
|
if (requiringModules) {
|
|
38
|
-
requiringModules.forEach(
|
|
39
|
-
const isLocalFile = existsSync(requiredModule) || existsSync(`${requiredModule}.js`)
|
|
38
|
+
requiringModules.forEach(requiredModule => {
|
|
39
|
+
const isLocalFile = existsSync(requiredModule) || existsSync(`${requiredModule}.js`)
|
|
40
40
|
if (isLocalFile) {
|
|
41
|
-
requiredModule = resolve(requiredModule)
|
|
41
|
+
requiredModule = resolve(requiredModule)
|
|
42
42
|
}
|
|
43
|
-
require(requiredModule)
|
|
44
|
-
})
|
|
43
|
+
require(requiredModule)
|
|
44
|
+
})
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -52,10 +52,10 @@ class Codecept {
|
|
|
52
52
|
* @param {string} dir
|
|
53
53
|
*/
|
|
54
54
|
init(dir) {
|
|
55
|
-
this.initGlobals(dir)
|
|
55
|
+
this.initGlobals(dir)
|
|
56
56
|
// initializing listeners
|
|
57
|
-
container.create(this.config, this.opts)
|
|
58
|
-
this.runHooks()
|
|
57
|
+
container.create(this.config, this.opts)
|
|
58
|
+
this.runHooks()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/**
|
|
@@ -64,37 +64,37 @@ class Codecept {
|
|
|
64
64
|
* @param {string} dir
|
|
65
65
|
*/
|
|
66
66
|
initGlobals(dir) {
|
|
67
|
-
global.codecept_dir = dir
|
|
68
|
-
global.output_dir = fsPath.resolve(dir, this.config.output)
|
|
67
|
+
global.codecept_dir = dir
|
|
68
|
+
global.output_dir = fsPath.resolve(dir, this.config.output)
|
|
69
69
|
|
|
70
|
-
if (this.config.emptyOutputFolder) emptyFolder(global.output_dir)
|
|
70
|
+
if (this.config.emptyOutputFolder) emptyFolder(global.output_dir)
|
|
71
71
|
|
|
72
72
|
if (!this.config.noGlobals) {
|
|
73
|
-
global.Helper = global.codecept_helper = require('@codeceptjs/helper')
|
|
74
|
-
global.actor = global.codecept_actor = require('./actor')
|
|
75
|
-
global.pause = require('./pause')
|
|
76
|
-
global.within = require('./within')
|
|
77
|
-
global.session = require('./session')
|
|
78
|
-
global.DataTable = require('./data/table')
|
|
79
|
-
global.locate = locator => require('./locator').build(locator)
|
|
80
|
-
global.inject = container.support
|
|
81
|
-
global.share = container.share
|
|
82
|
-
global.secret = require('./secret').secret
|
|
83
|
-
global.codecept_debug = output.debug
|
|
84
|
-
global.codeceptjs = require('./index')
|
|
73
|
+
global.Helper = global.codecept_helper = require('@codeceptjs/helper')
|
|
74
|
+
global.actor = global.codecept_actor = require('./actor')
|
|
75
|
+
global.pause = require('./pause')
|
|
76
|
+
global.within = require('./within')
|
|
77
|
+
global.session = require('./session')
|
|
78
|
+
global.DataTable = require('./data/table')
|
|
79
|
+
global.locate = locator => require('./locator').build(locator)
|
|
80
|
+
global.inject = container.support
|
|
81
|
+
global.share = container.share
|
|
82
|
+
global.secret = require('./secret').secret
|
|
83
|
+
global.codecept_debug = output.debug
|
|
84
|
+
global.codeceptjs = require('./index') // load all objects
|
|
85
85
|
|
|
86
86
|
// BDD
|
|
87
|
-
const stepDefinitions = require('./
|
|
88
|
-
global.Given = stepDefinitions.Given
|
|
89
|
-
global.When = stepDefinitions.When
|
|
90
|
-
global.Then = stepDefinitions.Then
|
|
91
|
-
global.DefineParameterType = stepDefinitions.defineParameterType
|
|
87
|
+
const stepDefinitions = require('./mocha/bdd')
|
|
88
|
+
global.Given = stepDefinitions.Given
|
|
89
|
+
global.When = stepDefinitions.When
|
|
90
|
+
global.Then = stepDefinitions.Then
|
|
91
|
+
global.DefineParameterType = stepDefinitions.defineParameterType
|
|
92
92
|
|
|
93
93
|
// debug mode
|
|
94
|
-
global.debugMode = false
|
|
94
|
+
global.debugMode = false
|
|
95
95
|
|
|
96
96
|
// mask sensitive data
|
|
97
|
-
global.maskSensitiveData = this.config.maskSensitiveData || false
|
|
97
|
+
global.maskSensitiveData = this.config.maskSensitiveData || false
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
@@ -103,16 +103,18 @@ class Codecept {
|
|
|
103
103
|
*/
|
|
104
104
|
runHooks() {
|
|
105
105
|
// default hooks
|
|
106
|
-
runHook(require('./listener/
|
|
107
|
-
runHook(require('./listener/
|
|
108
|
-
runHook(require('./listener/config'))
|
|
109
|
-
runHook(require('./listener/
|
|
110
|
-
runHook(require('./listener/
|
|
111
|
-
runHook(require('./listener/
|
|
112
|
-
runHook(require('./listener/
|
|
106
|
+
runHook(require('./listener/store'))
|
|
107
|
+
runHook(require('./listener/steps'))
|
|
108
|
+
runHook(require('./listener/config'))
|
|
109
|
+
runHook(require('./listener/result'))
|
|
110
|
+
runHook(require('./listener/helpers'))
|
|
111
|
+
runHook(require('./listener/globalTimeout'))
|
|
112
|
+
runHook(require('./listener/globalRetry'))
|
|
113
|
+
runHook(require('./listener/exit'))
|
|
114
|
+
runHook(require('./listener/emptyRun'))
|
|
113
115
|
|
|
114
116
|
// custom hooks (previous iteration of plugins)
|
|
115
|
-
this.config.hooks.forEach(hook => runHook(hook))
|
|
117
|
+
this.config.hooks.forEach(hook => runHook(hook))
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
/**
|
|
@@ -120,7 +122,7 @@ class Codecept {
|
|
|
120
122
|
*
|
|
121
123
|
*/
|
|
122
124
|
async bootstrap() {
|
|
123
|
-
return runHook(this.config.bootstrap, 'bootstrap')
|
|
125
|
+
return runHook(this.config.bootstrap, 'bootstrap')
|
|
124
126
|
}
|
|
125
127
|
|
|
126
128
|
/**
|
|
@@ -128,7 +130,7 @@ class Codecept {
|
|
|
128
130
|
|
|
129
131
|
*/
|
|
130
132
|
async teardown() {
|
|
131
|
-
return runHook(this.config.teardown, 'teardown')
|
|
133
|
+
return runHook(this.config.teardown, 'teardown')
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
/**
|
|
@@ -139,42 +141,42 @@ class Codecept {
|
|
|
139
141
|
loadTests(pattern) {
|
|
140
142
|
const options = {
|
|
141
143
|
cwd: global.codecept_dir,
|
|
142
|
-
}
|
|
144
|
+
}
|
|
143
145
|
|
|
144
|
-
let patterns = [pattern]
|
|
146
|
+
let patterns = [pattern]
|
|
145
147
|
if (!pattern) {
|
|
146
|
-
patterns = []
|
|
148
|
+
patterns = []
|
|
147
149
|
|
|
148
150
|
// If the user wants to test a specific set of test files as an array or string.
|
|
149
151
|
if (this.config.tests && !this.opts.features) {
|
|
150
152
|
if (Array.isArray(this.config.tests)) {
|
|
151
|
-
patterns.push(...this.config.tests)
|
|
153
|
+
patterns.push(...this.config.tests)
|
|
152
154
|
} else {
|
|
153
|
-
patterns.push(this.config.tests)
|
|
155
|
+
patterns.push(this.config.tests)
|
|
154
156
|
}
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
if (this.config.gherkin.features && !this.opts.tests) {
|
|
158
160
|
if (Array.isArray(this.config.gherkin.features)) {
|
|
159
161
|
this.config.gherkin.features.forEach(feature => {
|
|
160
|
-
patterns.push(feature)
|
|
161
|
-
})
|
|
162
|
+
patterns.push(feature)
|
|
163
|
+
})
|
|
162
164
|
} else {
|
|
163
|
-
patterns.push(this.config.gherkin.features)
|
|
165
|
+
patterns.push(this.config.gherkin.features)
|
|
164
166
|
}
|
|
165
167
|
}
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
for (pattern of patterns) {
|
|
169
|
-
glob.sync(pattern, options).forEach(
|
|
170
|
-
if (file.includes('node_modules')) return
|
|
171
|
+
glob.sync(pattern, options).forEach(file => {
|
|
172
|
+
if (file.includes('node_modules')) return
|
|
171
173
|
if (!fsPath.isAbsolute(file)) {
|
|
172
|
-
file = fsPath.join(global.codecept_dir, file)
|
|
174
|
+
file = fsPath.join(global.codecept_dir, file)
|
|
173
175
|
}
|
|
174
176
|
if (!this.testFiles.includes(fsPath.resolve(file))) {
|
|
175
|
-
this.testFiles.push(fsPath.resolve(file))
|
|
177
|
+
this.testFiles.push(fsPath.resolve(file))
|
|
176
178
|
}
|
|
177
|
-
})
|
|
179
|
+
})
|
|
178
180
|
}
|
|
179
181
|
}
|
|
180
182
|
|
|
@@ -185,34 +187,36 @@ class Codecept {
|
|
|
185
187
|
* @returns {Promise<void>}
|
|
186
188
|
*/
|
|
187
189
|
async run(test) {
|
|
190
|
+
await container.started()
|
|
191
|
+
|
|
188
192
|
return new Promise((resolve, reject) => {
|
|
189
|
-
const mocha = container.mocha()
|
|
190
|
-
mocha.files = this.testFiles
|
|
193
|
+
const mocha = container.mocha()
|
|
194
|
+
mocha.files = this.testFiles
|
|
191
195
|
if (test) {
|
|
192
196
|
if (!fsPath.isAbsolute(test)) {
|
|
193
|
-
test = fsPath.join(global.codecept_dir, test)
|
|
197
|
+
test = fsPath.join(global.codecept_dir, test)
|
|
194
198
|
}
|
|
195
|
-
mocha.files = mocha.files.filter(t => fsPath.basename(t, '.js') === test || t === test)
|
|
199
|
+
mocha.files = mocha.files.filter(t => fsPath.basename(t, '.js') === test || t === test)
|
|
196
200
|
}
|
|
197
201
|
const done = () => {
|
|
198
|
-
event.emit(event.all.result,
|
|
199
|
-
event.emit(event.all.after, this)
|
|
200
|
-
resolve()
|
|
201
|
-
}
|
|
202
|
+
event.emit(event.all.result, container.result())
|
|
203
|
+
event.emit(event.all.after, this)
|
|
204
|
+
resolve()
|
|
205
|
+
}
|
|
202
206
|
|
|
203
207
|
try {
|
|
204
|
-
event.emit(event.all.before, this)
|
|
205
|
-
mocha.run(() => done())
|
|
208
|
+
event.emit(event.all.before, this)
|
|
209
|
+
mocha.run(() => done())
|
|
206
210
|
} catch (e) {
|
|
207
|
-
output.error(e.stack)
|
|
208
|
-
reject(e)
|
|
211
|
+
output.error(e.stack)
|
|
212
|
+
reject(e)
|
|
209
213
|
}
|
|
210
|
-
})
|
|
214
|
+
})
|
|
211
215
|
}
|
|
212
216
|
|
|
213
217
|
static version() {
|
|
214
|
-
return JSON.parse(readFileSync(`${__dirname}/../package.json`, 'utf8')).version
|
|
218
|
+
return JSON.parse(readFileSync(`${__dirname}/../package.json`, 'utf8')).version
|
|
215
219
|
}
|
|
216
220
|
}
|
|
217
221
|
|
|
218
|
-
module.exports = Codecept
|
|
222
|
+
module.exports = Codecept
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
const { getConfig, getTestRoot } = require('./utils')
|
|
2
|
+
const Codecept = require('../codecept')
|
|
3
|
+
const output = require('../output')
|
|
4
|
+
const store = require('../store')
|
|
5
|
+
const container = require('../container')
|
|
6
|
+
const figures = require('figures')
|
|
7
|
+
const chalk = require('chalk')
|
|
8
|
+
const { createTest } = require('../mocha/test')
|
|
9
|
+
const { getMachineInfo } = require('./info')
|
|
10
|
+
const definitions = require('./definitions')
|
|
11
|
+
|
|
12
|
+
module.exports = async function (options) {
|
|
13
|
+
const configFile = options.config
|
|
14
|
+
|
|
15
|
+
setTimeout(() => {
|
|
16
|
+
output.error("Something went wrong. Checks didn't pass and timed out. Please check your config and helpers.")
|
|
17
|
+
process.exit(1)
|
|
18
|
+
}, options.timeout || 50000)
|
|
19
|
+
|
|
20
|
+
const checks = {
|
|
21
|
+
config: false,
|
|
22
|
+
container: false,
|
|
23
|
+
pageObjects: false,
|
|
24
|
+
plugins: false,
|
|
25
|
+
ai: true, // we don't need to check AI
|
|
26
|
+
helpers: false,
|
|
27
|
+
setup: false,
|
|
28
|
+
tests: false,
|
|
29
|
+
def: false,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const testRoot = getTestRoot(configFile)
|
|
33
|
+
let config = getConfig(configFile)
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
config = getConfig(configFile)
|
|
37
|
+
checks['config'] = true
|
|
38
|
+
} catch (err) {
|
|
39
|
+
checks['config'] = err
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
printCheck('config', checks['config'], config.name)
|
|
43
|
+
|
|
44
|
+
let codecept
|
|
45
|
+
try {
|
|
46
|
+
codecept = new Codecept(config, options)
|
|
47
|
+
codecept.init(testRoot)
|
|
48
|
+
await container.started()
|
|
49
|
+
checks.container = true
|
|
50
|
+
} catch (err) {
|
|
51
|
+
checks.container = err
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const standardActingHelpers = container.STANDARD_ACTING_HELPERS
|
|
55
|
+
|
|
56
|
+
printCheck('container', checks['container'])
|
|
57
|
+
|
|
58
|
+
if (codecept) {
|
|
59
|
+
try {
|
|
60
|
+
if (options.bootstrap) await codecept.bootstrap()
|
|
61
|
+
checks.bootstrap = true
|
|
62
|
+
} catch (err) {
|
|
63
|
+
checks.bootstrap = err
|
|
64
|
+
}
|
|
65
|
+
printCheck('bootstrap', checks['bootstrap'], options.bootstrap ? 'Bootstrap was executed' : 'No bootstrap command')
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let numTests = 0
|
|
69
|
+
if (codecept) {
|
|
70
|
+
try {
|
|
71
|
+
codecept.loadTests()
|
|
72
|
+
const mocha = container.mocha()
|
|
73
|
+
mocha.files = codecept.testFiles
|
|
74
|
+
mocha.loadFiles()
|
|
75
|
+
mocha.suite.suites.forEach(suite => {
|
|
76
|
+
numTests += suite.tests.length
|
|
77
|
+
})
|
|
78
|
+
if (numTests > 0) {
|
|
79
|
+
checks.tests = true
|
|
80
|
+
} else {
|
|
81
|
+
throw new Error('No tests found')
|
|
82
|
+
}
|
|
83
|
+
} catch (err) {
|
|
84
|
+
checks.tests = err
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (config?.ai?.request) {
|
|
89
|
+
checks.ai = true
|
|
90
|
+
printCheck('ai', checks['ai'], 'AI configuration is enabled, request function is set')
|
|
91
|
+
} else {
|
|
92
|
+
printCheck('ai', checks['ai'], 'AI is disabled')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
printCheck('tests', checks['tests'], `Total: ${numTests} tests`)
|
|
96
|
+
|
|
97
|
+
store.dryRun = true
|
|
98
|
+
|
|
99
|
+
const helpers = container.helpers()
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
if (!Object.keys(helpers).length) throw new Error('No helpers found')
|
|
103
|
+
// load helpers
|
|
104
|
+
for (const helper of Object.values(helpers)) {
|
|
105
|
+
if (helper._init) helper._init()
|
|
106
|
+
}
|
|
107
|
+
checks.helpers = true
|
|
108
|
+
} catch (err) {
|
|
109
|
+
checks.helpers = err
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
printCheck('helpers', checks['helpers'], `${Object.keys(helpers).join(', ')}`)
|
|
113
|
+
|
|
114
|
+
const pageObjects = container.support()
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
if (Object.keys(pageObjects).length) {
|
|
118
|
+
for (const pageObject of Object.values(pageObjects)) {
|
|
119
|
+
pageObject.name
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
checks.pageObjects = true
|
|
123
|
+
} catch (err) {
|
|
124
|
+
checks.pageObjects = err
|
|
125
|
+
}
|
|
126
|
+
printCheck('page objects', checks['pageObjects'], `Total: ${Object.keys(pageObjects).length} support objects`)
|
|
127
|
+
|
|
128
|
+
checks.plugins = true // how to check plugins?
|
|
129
|
+
printCheck('plugins', checks['plugins'], Object.keys(container.plugins()).join(', '))
|
|
130
|
+
|
|
131
|
+
if (Object.keys(helpers).length) {
|
|
132
|
+
const suite = container.mocha().suite
|
|
133
|
+
const test = createTest('test', () => {})
|
|
134
|
+
try {
|
|
135
|
+
for (const helper of Object.values(helpers)) {
|
|
136
|
+
if (helper._beforeSuite) await helper._beforeSuite(suite)
|
|
137
|
+
if (helper._before) await helper._before(test)
|
|
138
|
+
if (helper._passed) await helper._passed(test)
|
|
139
|
+
if (helper._after) await helper._after(test)
|
|
140
|
+
if (helper._finishTest) await helper._finishTest(suite)
|
|
141
|
+
if (helper._afterSuite) await helper._afterSuite(suite)
|
|
142
|
+
}
|
|
143
|
+
checks.setup = true
|
|
144
|
+
} catch (err) {
|
|
145
|
+
checks.setup = err
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
printCheck('Helpers Before/After', checks['setup'], standardActingHelpers.some(h => Object.keys(helpers).includes(h)) ? 'Initializing and closing browser' : '')
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
definitions(configFile, { dryRun: true })
|
|
153
|
+
checks.def = true
|
|
154
|
+
} catch (err) {
|
|
155
|
+
checks.def = err
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
printCheck('TypeScript Definitions', checks['def'])
|
|
159
|
+
|
|
160
|
+
output.print('')
|
|
161
|
+
|
|
162
|
+
if (!Object.values(checks).every(check => check === true)) {
|
|
163
|
+
output.error("Something went wrong. Checks didn't pass.")
|
|
164
|
+
output.print()
|
|
165
|
+
await getMachineInfo()
|
|
166
|
+
process.exit(1)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
output.print(output.styles.success('All checks passed'.toUpperCase()), 'Ready to run your tests 🚀')
|
|
170
|
+
process.exit(0)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function printCheck(name, value, comment = '') {
|
|
174
|
+
let status = ''
|
|
175
|
+
if (value == true) {
|
|
176
|
+
status += chalk.bold.green(figures.tick)
|
|
177
|
+
} else {
|
|
178
|
+
status += chalk.bold.red(figures.cross)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (value instanceof Error) {
|
|
182
|
+
comment = `${comment} ${chalk.red(value.message)}`.trim()
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
output.print(status, name.toUpperCase(), chalk.dim(comment))
|
|
186
|
+
}
|
|
@@ -14,9 +14,7 @@ module.exports = function (initPath) {
|
|
|
14
14
|
|
|
15
15
|
print()
|
|
16
16
|
print(` Welcome to ${colors.magenta.bold('CodeceptJS')} configuration migration tool`)
|
|
17
|
-
print(
|
|
18
|
-
` It will help you switch from ${colors.cyan.bold('.json')} to ${colors.magenta.bold('.js')} config format at ease`,
|
|
19
|
-
)
|
|
17
|
+
print(` It will help you switch from ${colors.cyan.bold('.json')} to ${colors.magenta.bold('.js')} config format at ease`)
|
|
20
18
|
print()
|
|
21
19
|
|
|
22
20
|
if (!path) {
|
|
@@ -53,7 +51,7 @@ module.exports = function (initPath) {
|
|
|
53
51
|
default: true,
|
|
54
52
|
},
|
|
55
53
|
])
|
|
56
|
-
.then(
|
|
54
|
+
.then(result => {
|
|
57
55
|
if (result.configFile) {
|
|
58
56
|
const jsonConfigFile = path.join(testsPath, 'codecept.js')
|
|
59
57
|
const config = JSON.parse(fs.readFileSync(jsonConfigFile, 'utf8'))
|
|
@@ -5,7 +5,7 @@ const { getConfig, getTestRoot } = require('./utils')
|
|
|
5
5
|
const Codecept = require('../codecept')
|
|
6
6
|
const container = require('../container')
|
|
7
7
|
const output = require('../output')
|
|
8
|
-
const actingHelpers = [...
|
|
8
|
+
const actingHelpers = [...container.STANDARD_ACTING_HELPERS, 'REST']
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Prepare data and generate content of definitions file
|
|
@@ -21,14 +21,7 @@ const actingHelpers = [...require('../plugin/standardActingHelpers'), 'REST']
|
|
|
21
21
|
*
|
|
22
22
|
* @returns {string}
|
|
23
23
|
*/
|
|
24
|
-
const getDefinitionsFileContent = ({
|
|
25
|
-
hasCustomHelper,
|
|
26
|
-
hasCustomStepsFile,
|
|
27
|
-
helperNames,
|
|
28
|
-
supportObject,
|
|
29
|
-
importPaths,
|
|
30
|
-
translations,
|
|
31
|
-
}) => {
|
|
24
|
+
const getDefinitionsFileContent = ({ hasCustomHelper, hasCustomStepsFile, helperNames, supportObject, importPaths, translations }) => {
|
|
32
25
|
const getHelperListFragment = ({ hasCustomHelper, hasCustomStepsFile }) => {
|
|
33
26
|
if (hasCustomHelper && hasCustomStepsFile) {
|
|
34
27
|
return `${['ReturnType<steps_file>', 'WithTranslation<Methods>'].join(', ')}`
|
|
@@ -73,13 +66,7 @@ const getDefinitionsFileContent = ({
|
|
|
73
66
|
*
|
|
74
67
|
* @returns {string}
|
|
75
68
|
*/
|
|
76
|
-
const generateDefinitionsContent = ({
|
|
77
|
-
importPathsFragment,
|
|
78
|
-
supportObjectsTypeFragment,
|
|
79
|
-
methodsTypeFragment,
|
|
80
|
-
helpersListFragment,
|
|
81
|
-
translatedActionsFragment,
|
|
82
|
-
}) => {
|
|
69
|
+
const generateDefinitionsContent = ({ importPathsFragment, supportObjectsTypeFragment, methodsTypeFragment, helpersListFragment, translatedActionsFragment }) => {
|
|
83
70
|
return `/// <reference types='codeceptjs' />
|
|
84
71
|
${importPathsFragment}
|
|
85
72
|
|
|
@@ -185,15 +172,12 @@ module.exports = function (genPath, options) {
|
|
|
185
172
|
namespaceTranslationAliases.push(`interface ${translations.vocabulary.I} extends WithTranslation<Methods> {}`)
|
|
186
173
|
|
|
187
174
|
namespaceTranslationAliases.push(' namespace Translation {')
|
|
188
|
-
definitionsFileContent = definitionsFileContent.replace(
|
|
189
|
-
'namespace Translation {',
|
|
190
|
-
namespaceTranslationAliases.join('\n'),
|
|
191
|
-
)
|
|
175
|
+
definitionsFileContent = definitionsFileContent.replace('namespace Translation {', namespaceTranslationAliases.join('\n'))
|
|
192
176
|
|
|
193
177
|
const translationAliases = []
|
|
194
178
|
|
|
195
179
|
if (translations.vocabulary.contexts) {
|
|
196
|
-
Object.keys(translations.vocabulary.contexts).forEach(
|
|
180
|
+
Object.keys(translations.vocabulary.contexts).forEach(k => {
|
|
197
181
|
translationAliases.push(`declare const ${translations.vocabulary.contexts[k]}: typeof ${k};`)
|
|
198
182
|
})
|
|
199
183
|
}
|
|
@@ -201,6 +185,8 @@ module.exports = function (genPath, options) {
|
|
|
201
185
|
definitionsFileContent += `\n${translationAliases.join('\n')}`
|
|
202
186
|
}
|
|
203
187
|
|
|
188
|
+
if (options.dryRun) return
|
|
189
|
+
|
|
204
190
|
fs.writeFileSync(path.join(targetFolderPath, 'steps.d.ts'), definitionsFileContent)
|
|
205
191
|
output.print('TypeScript Definitions provide autocompletion in Visual Studio Code and other IDEs')
|
|
206
192
|
output.print('Definitions were generated in steps.d.ts')
|
|
@@ -222,11 +208,7 @@ function getPath(originalPath, targetFolderPath, testsPath) {
|
|
|
222
208
|
if (!parsedPath.dir.startsWith('.')) return path.posix.join(parsedPath.dir, parsedPath.base)
|
|
223
209
|
const relativePath = path.posix.relative(
|
|
224
210
|
targetFolderPath.split(path.sep).join(path.posix.sep),
|
|
225
|
-
path.posix.join(
|
|
226
|
-
testsPath.split(path.sep).join(path.posix.sep),
|
|
227
|
-
parsedPath.dir.split(path.sep).join(path.posix.sep),
|
|
228
|
-
parsedPath.base.split(path.sep).join(path.posix.sep),
|
|
229
|
-
),
|
|
211
|
+
path.posix.join(testsPath.split(path.sep).join(path.posix.sep), parsedPath.dir.split(path.sep).join(path.posix.sep), parsedPath.base.split(path.sep).join(path.posix.sep)),
|
|
230
212
|
)
|
|
231
213
|
|
|
232
214
|
return relativePath.startsWith('.') ? relativePath : `./${relativePath}`
|
package/lib/command/generate.js
CHANGED
|
@@ -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:
|
|
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(
|
|
49
|
+
.then(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)
|
|
@@ -63,9 +63,7 @@ module.exports.test = function (genPath) {
|
|
|
63
63
|
testContent = testContent.replace('{{actor}}', container.translation().I)
|
|
64
64
|
if (vocabulary.contexts.Feature) testContent = testContent.replace('Feature', vocabulary.contexts.Feature)
|
|
65
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
|
-
)
|
|
66
|
+
output.print(`Test was created in ${colors.bold(config.translation)} localization. See: https://codecept.io/translation/`)
|
|
69
67
|
} else {
|
|
70
68
|
testContent = testContent.replace('{{actor}}', 'I')
|
|
71
69
|
}
|
|
@@ -128,13 +126,13 @@ module.exports.pageObject = function (genPath, opts) {
|
|
|
128
126
|
type: 'input',
|
|
129
127
|
name: 'name',
|
|
130
128
|
message: `Name of a ${kind} object`,
|
|
131
|
-
validate:
|
|
129
|
+
validate: val => !!val,
|
|
132
130
|
},
|
|
133
131
|
{
|
|
134
132
|
type: 'input',
|
|
135
133
|
name: 'filename',
|
|
136
134
|
message: 'Where should it be stored',
|
|
137
|
-
default:
|
|
135
|
+
default: answers => `./${kind}s/${answers.name}.${extension}`,
|
|
138
136
|
},
|
|
139
137
|
{
|
|
140
138
|
type: 'list',
|
|
@@ -144,7 +142,7 @@ module.exports.pageObject = function (genPath, opts) {
|
|
|
144
142
|
default: 'module',
|
|
145
143
|
},
|
|
146
144
|
])
|
|
147
|
-
.then(
|
|
145
|
+
.then(result => {
|
|
148
146
|
const pageObjectFile = path.join(testsPath, result.filename)
|
|
149
147
|
const dir = path.dirname(pageObjectFile)
|
|
150
148
|
if (!fileExists(dir)) fs.mkdirSync(dir)
|
|
@@ -194,9 +192,7 @@ module.exports.pageObject = function (genPath, opts) {
|
|
|
194
192
|
try {
|
|
195
193
|
generateDefinitions(testsPath, {})
|
|
196
194
|
} catch (_err) {
|
|
197
|
-
output.print(
|
|
198
|
-
`Run ${colors.green('npx codeceptjs def')} to update your types to get auto-completion for object.`,
|
|
199
|
-
)
|
|
195
|
+
output.print(`Run ${colors.green('npx codeceptjs def')} to update your types to get auto-completion for object.`)
|
|
200
196
|
}
|
|
201
197
|
})
|
|
202
198
|
}
|
|
@@ -241,16 +237,16 @@ module.exports.helper = function (genPath) {
|
|
|
241
237
|
type: 'input',
|
|
242
238
|
name: 'name',
|
|
243
239
|
message: 'Name of a Helper',
|
|
244
|
-
validate:
|
|
240
|
+
validate: val => !!val,
|
|
245
241
|
},
|
|
246
242
|
{
|
|
247
243
|
type: 'input',
|
|
248
244
|
name: 'filename',
|
|
249
245
|
message: 'Where should it be stored',
|
|
250
|
-
default:
|
|
246
|
+
default: answers => `./${answers.name.toLowerCase()}_helper.${extension}`,
|
|
251
247
|
},
|
|
252
248
|
])
|
|
253
|
-
.then(
|
|
249
|
+
.then(result => {
|
|
254
250
|
const name = ucfirst(result.name)
|
|
255
251
|
const helperFile = path.join(testsPath, result.filename)
|
|
256
252
|
const dir = path.dirname(helperFile)
|