Skip to content

Commit f27e662

Browse files
DavertMikDavertMik
and
DavertMik
authored
added sections for steps (#4777)
* added sections for steps * Update lib/steps.js * Update test/data/sandbox/configs/step-sections/step-sections_test.js * Update test/data/sandbox/configs/step-sections/step-sections_test.js --------- Co-authored-by: DavertMik <[email protected]>
1 parent 786638c commit f27e662

File tree

14 files changed

+278
-52
lines changed

14 files changed

+278
-52
lines changed

lib/listener/steps.js

+60-9
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,15 @@ const debug = require('debug')('codeceptjs:steps')
22
const event = require('../event')
33
const store = require('../store')
44
const output = require('../output')
5-
const { BeforeHook, AfterHook, BeforeSuiteHook, AfterSuiteHook } = require('../mocha/hooks')
65

76
let currentTest
87
let currentHook
98

109
/**
11-
* Register steps inside tests
1210
*/
1311
module.exports = function () {
14-
event.dispatcher.on(event.test.before, test => {
15-
test.startedAt = +new Date()
16-
test.artifacts = {}
17-
})
18-
1912
event.dispatcher.on(event.test.started, test => {
13+
test.startedAt = +new Date()
2014
currentTest = test
2115
currentTest.steps = []
2216
if (!('retryNum' in currentTest)) currentTest.retryNum = 0
@@ -36,13 +30,13 @@ module.exports = function () {
3630

3731
output.hook.started(hook)
3832

39-
if (hook.ctx && hook.ctx.test) debug(`--- STARTED ${hook.ctx.test.title} ---`)
33+
if (hook.ctx && hook.ctx.test) debug(`--- STARTED ${hook.title} ---`)
4034
})
4135

4236
event.dispatcher.on(event.hook.passed, hook => {
4337
currentHook = null
4438
output.hook.passed(hook)
45-
if (hook.ctx && hook.ctx.test) debug(`--- ENDED ${hook.ctx.test.title} ---`)
39+
if (hook.ctx && hook.ctx.test) debug(`--- ENDED ${hook.title} ---`)
4640
})
4741

4842
event.dispatcher.on(event.test.failed, () => {
@@ -88,4 +82,61 @@ module.exports = function () {
8882
store.currentStep = null
8983
store.stepOptions = null
9084
})
85+
86+
// listeners to output steps
87+
let currentMetaStep = []
88+
89+
event.dispatcher.on(event.bddStep.started, step => {
90+
if (!printSteps()) return
91+
92+
output.stepShift = 2
93+
output.step(step)
94+
})
95+
96+
event.dispatcher.on(event.step.started, step => {
97+
if (!printSteps()) return
98+
99+
let processingStep = step
100+
const metaSteps = []
101+
let isHidden = false
102+
while (processingStep.metaStep) {
103+
metaSteps.unshift(processingStep.metaStep)
104+
processingStep = processingStep.metaStep
105+
if (processingStep.collapsed) isHidden = true
106+
}
107+
const shift = metaSteps.length
108+
109+
for (let i = 0; i < Math.max(currentMetaStep.length, metaSteps.length); i++) {
110+
if (currentMetaStep[i] !== metaSteps[i]) {
111+
output.stepShift = 3 + 2 * i
112+
if (!metaSteps[i]) continue
113+
// bdd steps are handled by bddStep.started
114+
if (metaSteps[i].isBDD()) continue
115+
output.step(metaSteps[i])
116+
}
117+
}
118+
currentMetaStep = metaSteps
119+
120+
if (isHidden) return
121+
output.stepShift = 3 + 2 * shift
122+
output.step(step)
123+
})
124+
125+
event.dispatcher.on(event.step.finished, () => {
126+
if (!printSteps()) return
127+
output.stepShift = 0
128+
})
129+
}
130+
131+
let areStepsPrinted = false
132+
function printSteps() {
133+
if (output.level() < 1) return false
134+
135+
// if executed first time, print debug message
136+
if (!areStepsPrinted) {
137+
debug('Printing steps', 'Output level', output.level())
138+
areStepsPrinted = true
139+
}
140+
141+
return true
91142
}

lib/mocha/cli.js

-38
Original file line numberDiff line numberDiff line change
@@ -79,44 +79,6 @@ class Cli extends Base {
7979
output.test.started(test)
8080
}
8181
})
82-
83-
if (!codeceptjsEventDispatchersRegistered) {
84-
codeceptjsEventDispatchersRegistered = true
85-
86-
event.dispatcher.on(event.bddStep.started, step => {
87-
output.stepShift = 2
88-
output.step(step)
89-
})
90-
91-
event.dispatcher.on(event.step.started, step => {
92-
let processingStep = step
93-
const metaSteps = []
94-
while (processingStep.metaStep) {
95-
metaSteps.unshift(processingStep.metaStep)
96-
processingStep = processingStep.metaStep
97-
}
98-
const shift = metaSteps.length
99-
100-
for (let i = 0; i < Math.max(currentMetaStep.length, metaSteps.length); i++) {
101-
if (currentMetaStep[i] !== metaSteps[i]) {
102-
output.stepShift = 3 + 2 * i
103-
if (!metaSteps[i]) continue
104-
// bdd steps are handled by bddStep.started
105-
if (metaSteps[i].isBDD()) continue
106-
output.step(metaSteps[i])
107-
}
108-
}
109-
currentMetaStep = metaSteps
110-
output.stepShift = 3 + 2 * shift
111-
if (step.helper.constructor.name !== 'ExpectHelper') {
112-
output.step(step)
113-
}
114-
})
115-
116-
event.dispatcher.on(event.step.finished, () => {
117-
output.stepShift = 0
118-
})
119-
}
12082
}
12183

12284
runner.on('suite end', suite => {

lib/mocha/hooks.js

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class Hook {
77
this.runnable = context?.ctx?.test
88
this.ctx = context.ctx
99
this.error = error
10+
this.steps = []
1011
}
1112

1213
get hookName() {

lib/plugin/commentStep.js

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ let currentCommentStep
77
const defaultGlobalName = '__'
88

99
/**
10+
* @deprecated
11+
*
1012
* Add descriptive nested steps for your tests:
1113
*
1214
* ```js
@@ -100,6 +102,9 @@ const defaultGlobalName = '__'
100102
* ```
101103
*/
102104
module.exports = function (config) {
105+
console.log('commentStep is deprecated, disable it and use Section instead')
106+
console.log('const { Section: __ } = require("codeceptjs/steps")')
107+
103108
event.dispatcher.on(event.test.started, () => {
104109
currentCommentStep = null
105110
})

lib/step/base.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const Secret = require('../secret')
33
const { getCurrentTimeout } = require('./timeout')
44
const { ucfirst, humanizeString } = require('../utils')
55

6-
const STACK_LINE = 4
6+
const STACK_LINE = 5
77

88
/**
99
* Each command in test executed through `I.` object is wrapped in Step.
@@ -166,7 +166,7 @@ class Step {
166166
processingStep = this
167167

168168
while (processingStep.metaStep) {
169-
if (processingStep.metaStep.actor.match(/^(Given|When|Then|And)/)) {
169+
if (processingStep.metaStep.actor?.match(/^(Given|When|Then|And)/)) {
170170
hasBDD = true
171171
break
172172
} else {

lib/step/meta.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ class MetaStep extends Step {
66
constructor(actor, method) {
77
if (!method) method = ''
88
super(method)
9+
10+
/** @member {boolean} collsapsed hide children steps from output */
11+
this.collapsed = false
12+
913
this.actor = actor
1014
}
1115

@@ -32,7 +36,11 @@ class MetaStep extends Step {
3236
return `${this.prefix}${actorText} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`
3337
}
3438

35-
return `On ${this.prefix}${actorText}: ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`
39+
if (!this.actor) {
40+
return `${this.name} ${this.humanizeArgs()}${this.suffix}`.trim()
41+
}
42+
43+
return `On ${this.prefix}${actorText}: ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`.trim()
3644
}
3745

3846
humanize() {

lib/step/section.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
const MetaStep = require('./meta')
2+
const event = require('../event')
3+
4+
let currentSection
5+
6+
class Section {
7+
constructor(name = '') {
8+
this.name = name
9+
10+
this.metaStep = new MetaStep(null, name)
11+
12+
this.attachMetaStep = step => {
13+
if (currentSection !== this) return
14+
if (!step) return
15+
const metaStep = getRootMetaStep(step)
16+
17+
if (metaStep !== this.metaStep) {
18+
metaStep.metaStep = this.metaStep
19+
}
20+
}
21+
}
22+
23+
hidden() {
24+
this.metaStep.collapsed = true
25+
return this
26+
}
27+
28+
start() {
29+
if (currentSection) currentSection.end()
30+
currentSection = this
31+
event.dispatcher.prependListener(event.step.before, this.attachMetaStep)
32+
event.dispatcher.once(event.test.finished, () => this.end())
33+
return this
34+
}
35+
36+
end() {
37+
currentSection = null
38+
event.dispatcher.off(event.step.started, this.attachMetaStep)
39+
return this
40+
}
41+
42+
/**
43+
* @returns {Section}
44+
*/
45+
static current() {
46+
return currentSection
47+
}
48+
}
49+
50+
function getRootMetaStep(step) {
51+
if (step.metaStep) return getRootMetaStep(step.metaStep)
52+
return step
53+
}
54+
55+
module.exports = Section

lib/steps.js

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const StepConfig = require('./step/config')
2-
2+
const Section = require('./step/section')
33
function stepOpts(opts = {}) {
44
return new StepConfig(opts)
55
}
@@ -12,12 +12,39 @@ function stepRetry(retry) {
1212
return new StepConfig().retry(retry)
1313
}
1414

15+
function section(name) {
16+
if (!name) return endSection()
17+
return new Section(name).start()
18+
}
19+
20+
function endSection() {
21+
return Section.current().end()
22+
}
23+
1524
// Section function to be added here
1625

1726
const step = {
27+
// steps.opts syntax
1828
opts: stepOpts,
1929
timeout: stepTimeout,
2030
retry: stepRetry,
31+
32+
// one-function syntax
33+
stepTimeout,
34+
stepRetry,
35+
stepOpts,
36+
37+
// sections
38+
section,
39+
endSection,
40+
41+
Section: section,
42+
EndSection: endSection,
43+
44+
// shortcuts
45+
Given: () => section('Given'),
46+
When: () => section('When'),
47+
Then: () => section('Then'),
2148
}
2249

2350
module.exports = step

runok.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ describe('CodeceptJS ${featureName}', function () {
607607
console.log(`Created test files for feature: ${featureName}`)
608608

609609
console.log('Run codecept tests with:')
610-
console.log(`./bin/codecept.js run --config ${configDir}/codecept.${featureName}.conf.js`)
610+
console.log(`./bin/codecept.js run --config ${configDir}/codecept.conf.js`)
611611

612612
console.log('')
613613
console.log('Run tests with:')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
exports.config = {
2+
tests: './*_test.js',
3+
output: './output',
4+
helpers: {
5+
FileSystem: {},
6+
CustomHelper: {
7+
require: './customHelper.js',
8+
},
9+
},
10+
include: {
11+
userPage: './userPage.js',
12+
},
13+
bootstrap: false,
14+
mocha: {},
15+
name: 'step-sections tests',
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class CustomHelper extends Helper {
2+
act() {
3+
this.debug(JSON.stringify(arguments))
4+
}
5+
}
6+
7+
module.exports = CustomHelper
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const { Section, EndSection } = require('codeceptjs/steps')
2+
3+
Feature('step-sections')
4+
5+
Scenario('test using of basic step-sections', ({ I }) => {
6+
I.amInPath('.')
7+
8+
Section('User Journey')
9+
I.act('Hello, World!')
10+
11+
Section()
12+
I.act('Nothing to say')
13+
})
14+
15+
Scenario('test using of step-sections and page objects', ({ I, userPage }) => {
16+
Section('User Journey')
17+
userPage.actOnPage()
18+
19+
I.act('One more step')
20+
21+
Section()
22+
23+
I.act('Nothing to say')
24+
})
25+
26+
Scenario('test using of hidden step-sections', ({ I, userPage }) => {
27+
Section('User Journey').hidden()
28+
userPage.actOnPage()
29+
I.act('One more step')
30+
31+
EndSection()
32+
33+
I.act('Nothing to say')
34+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const { I } = inject()
2+
3+
module.exports = {
4+
actOnPage: () => {
5+
I.act('actOnPage')
6+
I.act('see on this page')
7+
},
8+
}

0 commit comments

Comments
 (0)