codeceptjs 3.7.0-beta.3 → 3.7.0-beta.5
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 +9 -10
- package/bin/codecept.js +7 -0
- package/lib/actor.js +47 -92
- package/lib/command/check.js +173 -0
- package/lib/command/definitions.js +2 -0
- package/lib/command/run-workers.js +1 -1
- package/lib/command/workers/runTests.js +112 -109
- package/lib/container.js +9 -0
- package/lib/effects.js +123 -0
- package/lib/heal.js +10 -0
- package/lib/helper/Appium.js +27 -16
- package/lib/helper/Playwright.js +15 -0
- package/lib/helper/Puppeteer.js +5 -0
- package/lib/helper/WebDriver.js +9 -1
- package/lib/listener/emptyRun.js +2 -5
- package/lib/listener/globalTimeout.js +41 -11
- package/lib/listener/steps.js +3 -0
- package/lib/mocha/cli.js +22 -5
- package/lib/mocha/featureConfig.js +13 -0
- package/lib/mocha/scenarioConfig.js +11 -0
- package/lib/mocha/test.js +15 -0
- package/lib/mocha/types.d.ts +6 -0
- package/lib/output.js +74 -73
- package/lib/pause.js +3 -7
- package/lib/plugin/heal.js +30 -0
- package/lib/plugin/stepTimeout.js +1 -1
- package/lib/recorder.js +1 -1
- package/lib/step/base.js +180 -0
- package/lib/step/config.js +50 -0
- package/lib/step/helper.js +47 -0
- package/lib/step/meta.js +91 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +25 -0
- package/lib/step/timeout.js +42 -0
- package/lib/step.js +15 -348
- package/lib/steps.js +23 -0
- package/lib/store.js +2 -0
- package/lib/utils.js +58 -0
- package/lib/within.js +2 -2
- package/lib/workers.js +2 -12
- package/package.json +7 -5
- package/typings/index.d.ts +5 -4
- package/typings/promiseBasedTypes.d.ts +1 -37
- package/typings/types.d.ts +39 -64
package/lib/output.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const colors = require('chalk')
|
|
2
|
-
const figures = require('figures')
|
|
3
|
-
const { maskSensitiveData } = require('invisi-data')
|
|
1
|
+
const colors = require('chalk')
|
|
2
|
+
const figures = require('figures')
|
|
3
|
+
const { maskSensitiveData } = require('invisi-data')
|
|
4
4
|
|
|
5
5
|
const styles = {
|
|
6
6
|
error: colors.bgRed.white.bold,
|
|
@@ -10,11 +10,12 @@ const styles = {
|
|
|
10
10
|
debug: colors.cyan,
|
|
11
11
|
log: colors.grey,
|
|
12
12
|
bold: colors.bold,
|
|
13
|
-
|
|
13
|
+
section: colors.white.dim.bold,
|
|
14
|
+
}
|
|
14
15
|
|
|
15
|
-
let outputLevel = 0
|
|
16
|
-
let outputProcess = ''
|
|
17
|
-
let newline = true
|
|
16
|
+
let outputLevel = 0
|
|
17
|
+
let outputProcess = ''
|
|
18
|
+
let newline = true
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* @alias output
|
|
@@ -28,7 +29,7 @@ module.exports = {
|
|
|
28
29
|
stepShift: 0,
|
|
29
30
|
|
|
30
31
|
standWithUkraine() {
|
|
31
|
-
return `#${colors.bold.yellow('StandWith')}${colors.bold.cyan('Ukraine')}
|
|
32
|
+
return `#${colors.bold.yellow('StandWith')}${colors.bold.cyan('Ukraine')}`
|
|
32
33
|
},
|
|
33
34
|
|
|
34
35
|
/**
|
|
@@ -37,8 +38,8 @@ module.exports = {
|
|
|
37
38
|
* @returns {number}
|
|
38
39
|
*/
|
|
39
40
|
level(level) {
|
|
40
|
-
if (level !== undefined) outputLevel = level
|
|
41
|
-
return outputLevel
|
|
41
|
+
if (level !== undefined) outputLevel = level
|
|
42
|
+
return outputLevel
|
|
42
43
|
},
|
|
43
44
|
|
|
44
45
|
/**
|
|
@@ -48,9 +49,9 @@ module.exports = {
|
|
|
48
49
|
* @returns {string}
|
|
49
50
|
*/
|
|
50
51
|
process(process) {
|
|
51
|
-
if (process === null) return (outputProcess = '')
|
|
52
|
-
if (process) outputProcess = String(process).length === 1 ? `[0${process}]` : `[${process}]
|
|
53
|
-
return outputProcess
|
|
52
|
+
if (process === null) return (outputProcess = '')
|
|
53
|
+
if (process) outputProcess = String(process).length === 1 ? `[0${process}]` : `[${process}]`
|
|
54
|
+
return outputProcess
|
|
54
55
|
},
|
|
55
56
|
|
|
56
57
|
/**
|
|
@@ -58,9 +59,9 @@ module.exports = {
|
|
|
58
59
|
* @param {string} msg
|
|
59
60
|
*/
|
|
60
61
|
debug(msg) {
|
|
61
|
-
const _msg = isMaskedData() ? maskSensitiveData(msg) : msg
|
|
62
|
+
const _msg = isMaskedData() ? maskSensitiveData(msg) : msg
|
|
62
63
|
if (outputLevel >= 2) {
|
|
63
|
-
print(' '.repeat(this.stepShift), styles.debug(`${figures.pointerSmall} ${_msg}`))
|
|
64
|
+
print(' '.repeat(this.stepShift), styles.debug(`${figures.pointerSmall} ${_msg}`))
|
|
64
65
|
}
|
|
65
66
|
},
|
|
66
67
|
|
|
@@ -69,9 +70,9 @@ module.exports = {
|
|
|
69
70
|
* @param {string} msg
|
|
70
71
|
*/
|
|
71
72
|
log(msg) {
|
|
72
|
-
const _msg = isMaskedData() ? maskSensitiveData(msg) : msg
|
|
73
|
+
const _msg = isMaskedData() ? maskSensitiveData(msg) : msg
|
|
73
74
|
if (outputLevel >= 3) {
|
|
74
|
-
print(' '.repeat(this.stepShift), styles.log(truncate(` ${_msg}`, this.spaceShift)))
|
|
75
|
+
print(' '.repeat(this.stepShift), styles.log(truncate(` ${_msg}`, this.spaceShift)))
|
|
75
76
|
}
|
|
76
77
|
},
|
|
77
78
|
|
|
@@ -80,7 +81,7 @@ module.exports = {
|
|
|
80
81
|
* @param {string} msg
|
|
81
82
|
*/
|
|
82
83
|
error(msg) {
|
|
83
|
-
print(styles.error(msg))
|
|
84
|
+
print(styles.error(msg))
|
|
84
85
|
},
|
|
85
86
|
|
|
86
87
|
/**
|
|
@@ -88,7 +89,7 @@ module.exports = {
|
|
|
88
89
|
* @param {string} msg
|
|
89
90
|
*/
|
|
90
91
|
success(msg) {
|
|
91
|
-
print(styles.success(msg))
|
|
92
|
+
print(styles.success(msg))
|
|
92
93
|
},
|
|
93
94
|
|
|
94
95
|
/**
|
|
@@ -97,7 +98,7 @@ module.exports = {
|
|
|
97
98
|
* @param {string} msg
|
|
98
99
|
*/
|
|
99
100
|
plugin(pluginName, msg = '') {
|
|
100
|
-
this.debug(`<${pluginName}> ${msg}`)
|
|
101
|
+
this.debug(`<${pluginName}> ${msg}`)
|
|
101
102
|
},
|
|
102
103
|
|
|
103
104
|
/**
|
|
@@ -105,26 +106,26 @@ module.exports = {
|
|
|
105
106
|
* @param {CodeceptJS.Step} step
|
|
106
107
|
*/
|
|
107
108
|
step(step) {
|
|
108
|
-
if (outputLevel === 0) return
|
|
109
|
-
if (!step) return
|
|
109
|
+
if (outputLevel === 0) return
|
|
110
|
+
if (!step) return
|
|
110
111
|
// Avoid to print non-gherkin steps, when gherkin is running for --steps mode
|
|
111
112
|
if (outputLevel === 1) {
|
|
112
113
|
if (typeof step === 'object' && step.hasBDDAncestor()) {
|
|
113
|
-
return
|
|
114
|
+
return
|
|
114
115
|
}
|
|
115
116
|
}
|
|
116
117
|
|
|
117
|
-
let stepLine = step.toCliStyled()
|
|
118
|
+
let stepLine = step.toCliStyled()
|
|
118
119
|
if (step.metaStep && outputLevel >= 1) {
|
|
119
120
|
// this.stepShift += 2;
|
|
120
|
-
stepLine = colors.dim(truncate(stepLine, this.spaceShift))
|
|
121
|
+
stepLine = colors.dim(truncate(stepLine, this.spaceShift))
|
|
121
122
|
}
|
|
122
123
|
if (step.comment) {
|
|
123
|
-
stepLine += colors.grey(step.comment.split('\n').join('\n' + ' '.repeat(4)))
|
|
124
|
+
stepLine += colors.grey(step.comment.split('\n').join('\n' + ' '.repeat(4)))
|
|
124
125
|
}
|
|
125
126
|
|
|
126
|
-
const _stepLine = isMaskedData() ? maskSensitiveData(stepLine) : stepLine
|
|
127
|
-
print(' '.repeat(this.stepShift), truncate(_stepLine, this.spaceShift))
|
|
127
|
+
const _stepLine = isMaskedData() ? maskSensitiveData(stepLine) : stepLine
|
|
128
|
+
print(' '.repeat(this.stepShift), truncate(_stepLine, this.spaceShift))
|
|
128
129
|
},
|
|
129
130
|
|
|
130
131
|
/** @namespace */
|
|
@@ -133,9 +134,9 @@ module.exports = {
|
|
|
133
134
|
* @param {Mocha.Suite} suite
|
|
134
135
|
*/
|
|
135
136
|
started: suite => {
|
|
136
|
-
if (!suite.title) return
|
|
137
|
-
print(`${colors.bold(suite.title)} --`)
|
|
138
|
-
if (suite.comment) print(suite.comment)
|
|
137
|
+
if (!suite.title) return
|
|
138
|
+
print(`${colors.bold(suite.title)} --`)
|
|
139
|
+
if (suite.comment) print(suite.comment)
|
|
139
140
|
},
|
|
140
141
|
},
|
|
141
142
|
|
|
@@ -145,25 +146,25 @@ module.exports = {
|
|
|
145
146
|
* @param {Mocha.Test} test
|
|
146
147
|
*/
|
|
147
148
|
started(test) {
|
|
148
|
-
print(` ${colors.magenta.bold(test.title)}`)
|
|
149
|
+
print(` ${colors.magenta.bold(test.title)}`)
|
|
149
150
|
},
|
|
150
151
|
/**
|
|
151
152
|
* @param {Mocha.Test} test
|
|
152
153
|
*/
|
|
153
154
|
passed(test) {
|
|
154
|
-
print(` ${colors.green.bold(figures.tick)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`)
|
|
155
|
+
print(` ${colors.green.bold(figures.tick)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`)
|
|
155
156
|
},
|
|
156
157
|
/**
|
|
157
158
|
* @param {Mocha.Test} test
|
|
158
159
|
*/
|
|
159
160
|
failed(test) {
|
|
160
|
-
print(` ${colors.red.bold(figures.cross)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`)
|
|
161
|
+
print(` ${colors.red.bold(figures.cross)} ${test.title} ${colors.grey(`in ${test.duration}ms`)}`)
|
|
161
162
|
},
|
|
162
163
|
/**
|
|
163
164
|
* @param {Mocha.Test} test
|
|
164
165
|
*/
|
|
165
166
|
skipped(test) {
|
|
166
|
-
print(` ${colors.yellow.bold('S')} ${test.title}`)
|
|
167
|
+
print(` ${colors.yellow.bold('S')} ${test.title}`)
|
|
167
168
|
},
|
|
168
169
|
},
|
|
169
170
|
|
|
@@ -174,38 +175,38 @@ module.exports = {
|
|
|
174
175
|
*/
|
|
175
176
|
|
|
176
177
|
started(test) {
|
|
177
|
-
if (outputLevel < 1) return
|
|
178
|
-
print(` ${colors.dim.bold('Scenario()')}`)
|
|
178
|
+
if (outputLevel < 1) return
|
|
179
|
+
print(` ${colors.dim.bold('Scenario()')}`)
|
|
179
180
|
},
|
|
180
181
|
|
|
181
182
|
/**
|
|
182
183
|
* @param {Mocha.Test} test
|
|
183
184
|
*/
|
|
184
185
|
passed(test) {
|
|
185
|
-
print(` ${colors.green.bold(`${figures.tick} OK`)} ${colors.grey(`in ${test.duration}ms`)}`)
|
|
186
|
-
print()
|
|
186
|
+
print(` ${colors.green.bold(`${figures.tick} OK`)} ${colors.grey(`in ${test.duration}ms`)}`)
|
|
187
|
+
print()
|
|
187
188
|
},
|
|
188
189
|
/**
|
|
189
190
|
* @param {Mocha.Test} test
|
|
190
191
|
*/
|
|
191
192
|
failed(test) {
|
|
192
|
-
print(` ${colors.red.bold(`${figures.cross} FAILED`)} ${colors.grey(`in ${test.duration}ms`)}`)
|
|
193
|
-
print()
|
|
193
|
+
print(` ${colors.red.bold(`${figures.cross} FAILED`)} ${colors.grey(`in ${test.duration}ms`)}`)
|
|
194
|
+
print()
|
|
194
195
|
},
|
|
195
196
|
},
|
|
196
197
|
|
|
197
198
|
hook: {
|
|
198
199
|
started(hook) {
|
|
199
|
-
if (outputLevel < 1) return
|
|
200
|
-
print(` ${colors.dim.bold(hook.toCode())}`)
|
|
200
|
+
if (outputLevel < 1) return
|
|
201
|
+
print(` ${colors.dim.bold(hook.toCode())}`)
|
|
201
202
|
},
|
|
202
203
|
passed(hook) {
|
|
203
|
-
if (outputLevel < 1) return
|
|
204
|
-
print()
|
|
204
|
+
if (outputLevel < 1) return
|
|
205
|
+
print()
|
|
205
206
|
},
|
|
206
207
|
failed(hook) {
|
|
207
|
-
if (outputLevel < 1) return
|
|
208
|
-
print(` ${colors.red.bold(hook.toCode())}`)
|
|
208
|
+
if (outputLevel < 1) return
|
|
209
|
+
print(` ${colors.red.bold(hook.toCode())}`)
|
|
209
210
|
},
|
|
210
211
|
},
|
|
211
212
|
|
|
@@ -217,9 +218,9 @@ module.exports = {
|
|
|
217
218
|
*/
|
|
218
219
|
say(message, color = 'cyan') {
|
|
219
220
|
if (colors[color] === undefined) {
|
|
220
|
-
color = 'cyan'
|
|
221
|
+
color = 'cyan'
|
|
221
222
|
}
|
|
222
|
-
if (outputLevel >= 1) print(` ${colors[color].bold(message)}`)
|
|
223
|
+
if (outputLevel >= 1) print(` ${colors[color].bold(message)}`)
|
|
223
224
|
},
|
|
224
225
|
|
|
225
226
|
/**
|
|
@@ -229,54 +230,54 @@ module.exports = {
|
|
|
229
230
|
* @param {number|string} duration
|
|
230
231
|
*/
|
|
231
232
|
result(passed, failed, skipped, duration, failedHooks = 0) {
|
|
232
|
-
let style = colors.bgGreen
|
|
233
|
-
let msg = ` ${passed || 0} passed
|
|
234
|
-
let status = style.bold(' OK ')
|
|
233
|
+
let style = colors.bgGreen
|
|
234
|
+
let msg = ` ${passed || 0} passed`
|
|
235
|
+
let status = style.bold(' OK ')
|
|
235
236
|
if (failed) {
|
|
236
|
-
style = style.bgRed
|
|
237
|
-
status = style.bold(' FAIL ')
|
|
238
|
-
msg += `, ${failed} failed
|
|
237
|
+
style = style.bgRed
|
|
238
|
+
status = style.bold(' FAIL ')
|
|
239
|
+
msg += `, ${failed} failed`
|
|
239
240
|
}
|
|
240
241
|
|
|
241
242
|
if (failedHooks > 0) {
|
|
242
|
-
style = style.bgRed
|
|
243
|
-
status = style.bold(' FAIL ')
|
|
244
|
-
msg += `, ${failedHooks} failedHooks
|
|
243
|
+
style = style.bgRed
|
|
244
|
+
status = style.bold(' FAIL ')
|
|
245
|
+
msg += `, ${failedHooks} failedHooks`
|
|
245
246
|
}
|
|
246
|
-
status += style.grey(' |')
|
|
247
|
+
status += style.grey(' |')
|
|
247
248
|
|
|
248
249
|
if (skipped) {
|
|
249
|
-
if (!failed) style = style.bgYellow
|
|
250
|
-
msg += `, ${skipped} skipped
|
|
250
|
+
if (!failed) style = style.bgYellow
|
|
251
|
+
msg += `, ${skipped} skipped`
|
|
251
252
|
}
|
|
252
|
-
msg += ' '
|
|
253
|
-
print(status + style(msg) + colors.grey(` // ${duration}`))
|
|
253
|
+
msg += ' '
|
|
254
|
+
print(status + style(msg) + colors.grey(` // ${duration}`))
|
|
254
255
|
},
|
|
255
|
-
}
|
|
256
|
+
}
|
|
256
257
|
|
|
257
258
|
function print(...msg) {
|
|
258
259
|
if (outputProcess) {
|
|
259
|
-
msg.unshift(outputProcess)
|
|
260
|
+
msg.unshift(outputProcess)
|
|
260
261
|
}
|
|
261
262
|
if (!newline) {
|
|
262
|
-
console.log()
|
|
263
|
-
newline = true
|
|
263
|
+
console.log()
|
|
264
|
+
newline = true
|
|
264
265
|
}
|
|
265
266
|
|
|
266
|
-
console.log.apply(this, msg)
|
|
267
|
+
console.log.apply(this, msg)
|
|
267
268
|
}
|
|
268
269
|
|
|
269
270
|
function truncate(msg, gap = 0) {
|
|
270
271
|
if (msg.indexOf('\n') > 0 || outputLevel >= 3) {
|
|
271
|
-
return msg
|
|
272
|
+
return msg // don't cut multi line steps or on verbose log level
|
|
272
273
|
}
|
|
273
|
-
const width = (process.stdout.columns || 200) - gap - 4
|
|
274
|
+
const width = (process.stdout.columns || 200) - gap - 4
|
|
274
275
|
if (msg.length > width) {
|
|
275
|
-
msg = msg.substr(0, width - 1) + figures.ellipsis
|
|
276
|
+
msg = msg.substr(0, width - 1) + figures.ellipsis
|
|
276
277
|
}
|
|
277
|
-
return msg
|
|
278
|
+
return msg
|
|
278
279
|
}
|
|
279
280
|
|
|
280
281
|
function isMaskedData() {
|
|
281
|
-
return global.maskSensitiveData === true || false
|
|
282
|
+
return global.maskSensitiveData === true || false
|
|
282
283
|
}
|
package/lib/pause.js
CHANGED
|
@@ -2,7 +2,6 @@ const colors = require('chalk')
|
|
|
2
2
|
const readline = require('readline')
|
|
3
3
|
const ora = require('ora-classic')
|
|
4
4
|
const debug = require('debug')('codeceptjs:pause')
|
|
5
|
-
const Fuse = require('fuse.js')
|
|
6
5
|
|
|
7
6
|
const container = require('./container')
|
|
8
7
|
const history = require('./history')
|
|
@@ -11,7 +10,7 @@ const aiAssistant = require('./ai')
|
|
|
11
10
|
const recorder = require('./recorder')
|
|
12
11
|
const event = require('./event')
|
|
13
12
|
const output = require('./output')
|
|
14
|
-
const { methodsOfObject } = require('./utils')
|
|
13
|
+
const { methodsOfObject, searchWithFusejs } = require('./utils')
|
|
15
14
|
|
|
16
15
|
// npm install colors
|
|
17
16
|
let rl
|
|
@@ -218,15 +217,12 @@ function completer(line) {
|
|
|
218
217
|
return [completions, line]
|
|
219
218
|
}
|
|
220
219
|
|
|
221
|
-
//
|
|
222
|
-
const
|
|
220
|
+
// Search using Fuse.js
|
|
221
|
+
const searchResults = searchWithFusejs(completions, line, {
|
|
223
222
|
threshold: 0.3,
|
|
224
223
|
distance: 100,
|
|
225
224
|
minMatchCharLength: 1,
|
|
226
225
|
})
|
|
227
|
-
|
|
228
|
-
// Search using Fuse.js
|
|
229
|
-
const searchResults = fuse.search(line)
|
|
230
226
|
const hits = searchResults.map(result => result.item)
|
|
231
227
|
|
|
232
228
|
return [hits, line]
|
package/lib/plugin/heal.js
CHANGED
|
@@ -5,6 +5,7 @@ const event = require('../event')
|
|
|
5
5
|
const output = require('../output')
|
|
6
6
|
const heal = require('../heal')
|
|
7
7
|
const store = require('../store')
|
|
8
|
+
const container = require('../container')
|
|
8
9
|
|
|
9
10
|
const defaultConfig = {
|
|
10
11
|
healLimit: 2,
|
|
@@ -115,4 +116,33 @@ module.exports = function (config = {}) {
|
|
|
115
116
|
i++
|
|
116
117
|
}
|
|
117
118
|
})
|
|
119
|
+
|
|
120
|
+
event.dispatcher.on(event.workers.result, ({ tests }) => {
|
|
121
|
+
const { print } = output
|
|
122
|
+
|
|
123
|
+
const healedTests = Object.values(tests)
|
|
124
|
+
.flat()
|
|
125
|
+
.filter(test => test.notes.some(note => note.type === 'heal'))
|
|
126
|
+
if (!healedTests.length) return
|
|
127
|
+
|
|
128
|
+
setTimeout(() => {
|
|
129
|
+
print('')
|
|
130
|
+
print('===================')
|
|
131
|
+
print(colors.bold.green('Self-Healing Report:'))
|
|
132
|
+
|
|
133
|
+
print('')
|
|
134
|
+
print('Suggested changes:')
|
|
135
|
+
print('')
|
|
136
|
+
|
|
137
|
+
healedTests.forEach(test => {
|
|
138
|
+
print(`${colors.bold.magenta(test.title)}`)
|
|
139
|
+
test.notes
|
|
140
|
+
.filter(note => note.type === 'heal')
|
|
141
|
+
.forEach(note => {
|
|
142
|
+
print(note.text)
|
|
143
|
+
print('')
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
}, 0)
|
|
147
|
+
})
|
|
118
148
|
}
|
package/lib/recorder.js
CHANGED
package/lib/step/base.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
const color = require('chalk')
|
|
2
|
+
const Secret = require('../secret')
|
|
3
|
+
const { getCurrentTimeout } = require('./timeout')
|
|
4
|
+
const { ucfirst, humanizeString } = require('../utils')
|
|
5
|
+
|
|
6
|
+
const STACK_LINE = 4
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Each command in test executed through `I.` object is wrapped in Step.
|
|
10
|
+
* Step allows logging executed commands and triggers hook before and after step execution.
|
|
11
|
+
* @param {string} name
|
|
12
|
+
*/
|
|
13
|
+
class Step {
|
|
14
|
+
constructor(name) {
|
|
15
|
+
/** @member {string} */
|
|
16
|
+
this.name = name
|
|
17
|
+
/** @member {Map<number, number>} */
|
|
18
|
+
this.timeouts = new Map()
|
|
19
|
+
|
|
20
|
+
/** @member {Array<*>} */
|
|
21
|
+
this.args = []
|
|
22
|
+
|
|
23
|
+
/** @member {Record<string,any>} */
|
|
24
|
+
this.opts = {}
|
|
25
|
+
/** @member {string} */
|
|
26
|
+
this.actor = 'I' // I = actor
|
|
27
|
+
/** @member {string} */
|
|
28
|
+
this.helperMethod = name // helper method
|
|
29
|
+
/** @member {string} */
|
|
30
|
+
this.status = 'pending'
|
|
31
|
+
/** @member {string} */
|
|
32
|
+
this.prefix = this.suffix = ''
|
|
33
|
+
/** @member {string} */
|
|
34
|
+
this.comment = ''
|
|
35
|
+
/** @member {any} */
|
|
36
|
+
this.metaStep = undefined
|
|
37
|
+
/** @member {string} */
|
|
38
|
+
this.stack = ''
|
|
39
|
+
|
|
40
|
+
this.setTrace()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setMetaStep(metaStep) {
|
|
44
|
+
this.metaStep = metaStep
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
run() {
|
|
48
|
+
throw new Error('Not implemented')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @returns {number|undefined}
|
|
53
|
+
*/
|
|
54
|
+
get timeout() {
|
|
55
|
+
return getCurrentTimeout(this.timeouts)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {number} timeout - timeout in milliseconds or 0 if no timeout
|
|
60
|
+
* @param {number} order - order defines the priority of timeout, timeouts set with lower order override those set with higher order.
|
|
61
|
+
* When order below 0 value of timeout only override if new value is lower
|
|
62
|
+
*/
|
|
63
|
+
setTimeout(timeout, order) {
|
|
64
|
+
this.timeouts.set(order, timeout)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** @function */
|
|
68
|
+
setTrace() {
|
|
69
|
+
Error.captureStackTrace(this)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** @param {Array<*>} args */
|
|
73
|
+
setArguments(args) {
|
|
74
|
+
this.args = args
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
setActor(actor) {
|
|
78
|
+
this.actor = actor || ''
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** @param {string} status */
|
|
82
|
+
setStatus(status) {
|
|
83
|
+
this.status = status
|
|
84
|
+
if (this.metaStep) {
|
|
85
|
+
this.metaStep.setStatus(status)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @return {string} */
|
|
90
|
+
humanize() {
|
|
91
|
+
return humanizeString(this.name)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** @return {string} */
|
|
95
|
+
humanizeArgs() {
|
|
96
|
+
return this.args
|
|
97
|
+
.map(arg => {
|
|
98
|
+
if (!arg) {
|
|
99
|
+
return ''
|
|
100
|
+
}
|
|
101
|
+
if (typeof arg === 'string') {
|
|
102
|
+
return `"${arg}"`
|
|
103
|
+
}
|
|
104
|
+
if (Array.isArray(arg)) {
|
|
105
|
+
try {
|
|
106
|
+
const res = JSON.stringify(arg)
|
|
107
|
+
return res
|
|
108
|
+
} catch (err) {
|
|
109
|
+
return `[${arg.toString()}]`
|
|
110
|
+
}
|
|
111
|
+
} else if (typeof arg === 'function') {
|
|
112
|
+
return arg.toString()
|
|
113
|
+
} else if (typeof arg === 'undefined') {
|
|
114
|
+
return `${arg}`
|
|
115
|
+
} else if (arg instanceof Secret) {
|
|
116
|
+
return arg.getMasked()
|
|
117
|
+
} else if (arg.toString && arg.toString() !== '[object Object]') {
|
|
118
|
+
return arg.toString()
|
|
119
|
+
} else if (typeof arg === 'object') {
|
|
120
|
+
const returnedArg = {}
|
|
121
|
+
for (const [key, value] of Object.entries(arg)) {
|
|
122
|
+
returnedArg[key] = value
|
|
123
|
+
if (value instanceof Secret) returnedArg[key] = value.getMasked()
|
|
124
|
+
}
|
|
125
|
+
return JSON.stringify(returnedArg)
|
|
126
|
+
}
|
|
127
|
+
return arg
|
|
128
|
+
})
|
|
129
|
+
.join(', ')
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** @return {string} */
|
|
133
|
+
line() {
|
|
134
|
+
const lines = this.stack.split('\n')
|
|
135
|
+
if (lines[STACK_LINE]) {
|
|
136
|
+
return lines[STACK_LINE].trim()
|
|
137
|
+
.replace(global.codecept_dir || '', '.')
|
|
138
|
+
.trim()
|
|
139
|
+
}
|
|
140
|
+
return ''
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** @return {string} */
|
|
144
|
+
toString() {
|
|
145
|
+
return ucfirst(`${this.prefix}${this.actor} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`).trim()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** @return {string} */
|
|
149
|
+
toCliStyled() {
|
|
150
|
+
return `${this.prefix}${this.actor} ${color.italic(this.humanize())} ${color.yellow(this.humanizeArgs())}${this.suffix}`
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** @return {string} */
|
|
154
|
+
toCode() {
|
|
155
|
+
return `${this.prefix}${this.actor}.${this.name}(${this.humanizeArgs()})${this.suffix}`
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
isMetaStep() {
|
|
159
|
+
return this.constructor.name === 'MetaStep'
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** @return {boolean} */
|
|
163
|
+
hasBDDAncestor() {
|
|
164
|
+
let hasBDD = false
|
|
165
|
+
let processingStep
|
|
166
|
+
processingStep = this
|
|
167
|
+
|
|
168
|
+
while (processingStep.metaStep) {
|
|
169
|
+
if (processingStep.metaStep.actor.match(/^(Given|When|Then|And)/)) {
|
|
170
|
+
hasBDD = true
|
|
171
|
+
break
|
|
172
|
+
} else {
|
|
173
|
+
processingStep = processingStep.metaStep
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return hasBDD
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
module.exports = Step
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StepConfig is a configuration object for a step.
|
|
3
|
+
* It is used to create a new step that is a combination of other steps.
|
|
4
|
+
*/
|
|
5
|
+
class StepConfig {
|
|
6
|
+
constructor(opts = {}) {
|
|
7
|
+
/** @member {{ opts: Record<string, any>, timeout: number|undefined, retry: number|undefined }} */
|
|
8
|
+
this.config = {
|
|
9
|
+
opts,
|
|
10
|
+
timeout: undefined,
|
|
11
|
+
retry: undefined,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Set the options for the step.
|
|
17
|
+
* @param {object} opts - The options for the step.
|
|
18
|
+
* @returns {StepConfig} - The step configuration object.
|
|
19
|
+
*/
|
|
20
|
+
opts(opts) {
|
|
21
|
+
this.config.opts = opts
|
|
22
|
+
return this
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Set the timeout for the step.
|
|
27
|
+
* @param {number} timeout - The timeout for the step.
|
|
28
|
+
* @returns {StepConfig} - The step configuration object.
|
|
29
|
+
*/
|
|
30
|
+
timeout(timeout) {
|
|
31
|
+
this.config.timeout = timeout
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Set the retry for the step.
|
|
37
|
+
* @param {number} retry - The retry for the step.
|
|
38
|
+
* @returns {StepConfig} - The step configuration object.
|
|
39
|
+
*/
|
|
40
|
+
retry(retry) {
|
|
41
|
+
this.config.retry = retry
|
|
42
|
+
return this
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getConfig() {
|
|
46
|
+
return this.config
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = StepConfig
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const Step = require('./base')
|
|
2
|
+
const store = require('../store')
|
|
3
|
+
|
|
4
|
+
class HelperStep extends Step {
|
|
5
|
+
constructor(helper, name) {
|
|
6
|
+
super(name)
|
|
7
|
+
/** @member {CodeceptJS.Helper} helper corresponding helper */
|
|
8
|
+
this.helper = helper
|
|
9
|
+
/** @member {string} helperMethod name of method to be executed */
|
|
10
|
+
this.helperMethod = name
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {...any} args
|
|
15
|
+
* @return {*}
|
|
16
|
+
*/
|
|
17
|
+
run() {
|
|
18
|
+
this.args = Array.prototype.slice.call(arguments)
|
|
19
|
+
|
|
20
|
+
if (store.dryRun) {
|
|
21
|
+
this.setStatus('success')
|
|
22
|
+
return Promise.resolve(new Proxy({}, dryRunResolver()))
|
|
23
|
+
}
|
|
24
|
+
let result
|
|
25
|
+
try {
|
|
26
|
+
if (this.helperMethod !== 'say') {
|
|
27
|
+
result = this.helper[this.helperMethod].apply(this.helper, this.args)
|
|
28
|
+
}
|
|
29
|
+
this.setStatus('success')
|
|
30
|
+
} catch (err) {
|
|
31
|
+
this.setStatus('failed')
|
|
32
|
+
throw err
|
|
33
|
+
}
|
|
34
|
+
return result
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = HelperStep
|
|
39
|
+
|
|
40
|
+
function dryRunResolver() {
|
|
41
|
+
return {
|
|
42
|
+
get(target, prop) {
|
|
43
|
+
if (prop === 'toString') return () => '<VALUE>'
|
|
44
|
+
return new Proxy({}, dryRunResolver())
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
}
|