Skip to content

Commit

Permalink
added sections for steps
Browse files Browse the repository at this point in the history
  • Loading branch information
DavertMik committed Jan 14, 2025
1 parent 7b97a55 commit 4c97322
Show file tree
Hide file tree
Showing 14 changed files with 278 additions and 52 deletions.
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,
SectionEnd: 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, SectionEnd } = 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')

SectionEnd()

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

0 comments on commit 4c97322

Please sign in to comment.