Skip to content

added sections for steps #4777

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 60 additions & 9 deletions lib/listener/steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@ const debug = require('debug')('codeceptjs:steps')
const event = require('../event')
const store = require('../store')
const output = require('../output')
const { BeforeHook, AfterHook, BeforeSuiteHook, AfterSuiteHook } = require('../mocha/hooks')

let currentTest
let currentHook

/**
* Register steps inside tests
*/
module.exports = function () {
event.dispatcher.on(event.test.before, test => {
test.startedAt = +new Date()
test.artifacts = {}
})

event.dispatcher.on(event.test.started, test => {
test.startedAt = +new Date()
currentTest = test
currentTest.steps = []
if (!('retryNum' in currentTest)) currentTest.retryNum = 0
Expand All @@ -36,13 +30,13 @@ module.exports = function () {

output.hook.started(hook)

if (hook.ctx && hook.ctx.test) debug(`--- STARTED ${hook.ctx.test.title} ---`)
if (hook.ctx && hook.ctx.test) debug(`--- STARTED ${hook.title} ---`)
})

event.dispatcher.on(event.hook.passed, hook => {
currentHook = null
output.hook.passed(hook)
if (hook.ctx && hook.ctx.test) debug(`--- ENDED ${hook.ctx.test.title} ---`)
if (hook.ctx && hook.ctx.test) debug(`--- ENDED ${hook.title} ---`)
})

event.dispatcher.on(event.test.failed, () => {
Expand Down Expand Up @@ -88,4 +82,61 @@ module.exports = function () {
store.currentStep = null
store.stepOptions = null
})

// listeners to output steps
let currentMetaStep = []

event.dispatcher.on(event.bddStep.started, step => {
if (!printSteps()) return

output.stepShift = 2
output.step(step)
})

event.dispatcher.on(event.step.started, step => {
if (!printSteps()) return

let processingStep = step
const metaSteps = []
let isHidden = false
while (processingStep.metaStep) {
metaSteps.unshift(processingStep.metaStep)
processingStep = processingStep.metaStep
if (processingStep.collapsed) isHidden = true
}
const shift = metaSteps.length

for (let i = 0; i < Math.max(currentMetaStep.length, metaSteps.length); i++) {
if (currentMetaStep[i] !== metaSteps[i]) {
output.stepShift = 3 + 2 * i
if (!metaSteps[i]) continue
// bdd steps are handled by bddStep.started
if (metaSteps[i].isBDD()) continue
output.step(metaSteps[i])
}
}
currentMetaStep = metaSteps

if (isHidden) return
output.stepShift = 3 + 2 * shift
output.step(step)
})

event.dispatcher.on(event.step.finished, () => {
if (!printSteps()) return
output.stepShift = 0
})
}

let areStepsPrinted = false
function printSteps() {
if (output.level() < 1) return false

// if executed first time, print debug message
if (!areStepsPrinted) {
debug('Printing steps', 'Output level', output.level())
areStepsPrinted = true
}

return true
}
38 changes: 0 additions & 38 deletions lib/mocha/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,44 +79,6 @@ class Cli extends Base {
output.test.started(test)
}
})

if (!codeceptjsEventDispatchersRegistered) {
codeceptjsEventDispatchersRegistered = true

event.dispatcher.on(event.bddStep.started, step => {
output.stepShift = 2
output.step(step)
})

event.dispatcher.on(event.step.started, step => {
let processingStep = step
const metaSteps = []
while (processingStep.metaStep) {
metaSteps.unshift(processingStep.metaStep)
processingStep = processingStep.metaStep
}
const shift = metaSteps.length

for (let i = 0; i < Math.max(currentMetaStep.length, metaSteps.length); i++) {
if (currentMetaStep[i] !== metaSteps[i]) {
output.stepShift = 3 + 2 * i
if (!metaSteps[i]) continue
// bdd steps are handled by bddStep.started
if (metaSteps[i].isBDD()) continue
output.step(metaSteps[i])
}
}
currentMetaStep = metaSteps
output.stepShift = 3 + 2 * shift
if (step.helper.constructor.name !== 'ExpectHelper') {
output.step(step)
}
})

event.dispatcher.on(event.step.finished, () => {
output.stepShift = 0
})
}
}

runner.on('suite end', suite => {
Expand Down
1 change: 1 addition & 0 deletions lib/mocha/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Hook {
this.runnable = context?.ctx?.test
this.ctx = context.ctx
this.error = error
this.steps = []
}

get hookName() {
Expand Down
5 changes: 5 additions & 0 deletions lib/plugin/commentStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ let currentCommentStep
const defaultGlobalName = '__'

/**
* @deprecated
*
* Add descriptive nested steps for your tests:
*
* ```js
Expand Down Expand Up @@ -100,6 +102,9 @@ const defaultGlobalName = '__'
* ```
*/
module.exports = function (config) {
console.log('commentStep is deprecated, disable it and use Section instead')
console.log('const { Section: __ } = require("codeceptjs/steps")')

event.dispatcher.on(event.test.started, () => {
currentCommentStep = null
})
Expand Down
4 changes: 2 additions & 2 deletions lib/step/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const Secret = require('../secret')
const { getCurrentTimeout } = require('./timeout')
const { ucfirst, humanizeString } = require('../utils')

const STACK_LINE = 4
const STACK_LINE = 5

/**
* Each command in test executed through `I.` object is wrapped in Step.
Expand Down Expand Up @@ -166,7 +166,7 @@ class Step {
processingStep = this

while (processingStep.metaStep) {
if (processingStep.metaStep.actor.match(/^(Given|When|Then|And)/)) {
if (processingStep.metaStep.actor?.match(/^(Given|When|Then|And)/)) {
hasBDD = true
break
} else {
Expand Down
10 changes: 9 additions & 1 deletion lib/step/meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ class MetaStep extends Step {
constructor(actor, method) {
if (!method) method = ''
super(method)

/** @member {boolean} collsapsed hide children steps from output */
this.collapsed = false

this.actor = actor
}

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

return `On ${this.prefix}${actorText}: ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`
if (!this.actor) {
return `${this.name} ${this.humanizeArgs()}${this.suffix}`.trim()
}

return `On ${this.prefix}${actorText}: ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`.trim()
}

humanize() {
Expand Down
55 changes: 55 additions & 0 deletions lib/step/section.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const MetaStep = require('./meta')
const event = require('../event')

let currentSection

class Section {
constructor(name = '') {
this.name = name

this.metaStep = new MetaStep(null, name)

this.attachMetaStep = step => {
if (currentSection !== this) return
if (!step) return
const metaStep = getRootMetaStep(step)

if (metaStep !== this.metaStep) {
metaStep.metaStep = this.metaStep
}
}
}

hidden() {
this.metaStep.collapsed = true
return this
}

start() {
if (currentSection) currentSection.end()
currentSection = this
event.dispatcher.prependListener(event.step.before, this.attachMetaStep)
event.dispatcher.once(event.test.finished, () => this.end())
return this
}

end() {
currentSection = null
event.dispatcher.off(event.step.started, this.attachMetaStep)
return this
}

/**
* @returns {Section}
*/
static current() {
return currentSection
}
}

function getRootMetaStep(step) {
if (step.metaStep) return getRootMetaStep(step.metaStep)
return step
}

module.exports = Section
29 changes: 28 additions & 1 deletion lib/steps.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const StepConfig = require('./step/config')

const Section = require('./step/section')
function stepOpts(opts = {}) {
return new StepConfig(opts)
}
Expand All @@ -12,12 +12,39 @@ function stepRetry(retry) {
return new StepConfig().retry(retry)
}

function section(name) {
if (!name) return endSection()
return new Section(name).start()
}

function endSection() {
return Section.current().end()
}

// Section function to be added here

const step = {
// steps.opts syntax
opts: stepOpts,
timeout: stepTimeout,
retry: stepRetry,

// one-function syntax
stepTimeout,
stepRetry,
stepOpts,

// sections
section,
endSection,

Section: section,
EndSection: endSection,

// shortcuts
Given: () => section('Given'),
When: () => section('When'),
Then: () => section('Then'),
}

module.exports = step
2 changes: 1 addition & 1 deletion runok.js
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,7 @@ describe('CodeceptJS ${featureName}', function () {
console.log(`Created test files for feature: ${featureName}`)

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

console.log('')
console.log('Run tests with:')
Expand Down
16 changes: 16 additions & 0 deletions test/data/sandbox/configs/step-sections/codecept.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
exports.config = {
tests: './*_test.js',
output: './output',
helpers: {
FileSystem: {},
CustomHelper: {
require: './customHelper.js',
},
},
include: {
userPage: './userPage.js',
},
bootstrap: false,
mocha: {},
name: 'step-sections tests',
}
7 changes: 7 additions & 0 deletions test/data/sandbox/configs/step-sections/customHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class CustomHelper extends Helper {
act() {
this.debug(JSON.stringify(arguments))
}
}

module.exports = CustomHelper
34 changes: 34 additions & 0 deletions test/data/sandbox/configs/step-sections/step-sections_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const { Section, EndSection } = require('codeceptjs/steps')

Feature('step-sections')

Scenario('test using of basic step-sections', ({ I }) => {
I.amInPath('.')

Section('User Journey')
I.act('Hello, World!')

Section()
I.act('Nothing to say')
})

Scenario('test using of step-sections and page objects', ({ I, userPage }) => {
Section('User Journey')
userPage.actOnPage()

I.act('One more step')

Section()

I.act('Nothing to say')
})

Scenario('test using of hidden step-sections', ({ I, userPage }) => {
Section('User Journey').hidden()
userPage.actOnPage()
I.act('One more step')

EndSection()

I.act('Nothing to say')
})
8 changes: 8 additions & 0 deletions test/data/sandbox/configs/step-sections/userPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const { I } = inject()

module.exports = {
actOnPage: () => {
I.act('actOnPage')
I.act('see on this page')
},
}
Loading
Loading