@herbsjs/aloe
Version:
Scenario description and test runner for Herbs
205 lines (167 loc) • 5.6 kB
JavaScript
const { builtinWhen } = require('./builtin/when')
const { samples } = require('./samples')
const { state } = require('./runningState')
const stages = {
none: 'none',
samples: 'samples',
given: 'given',
when: 'when',
check: 'check'
}
const addBuiltinWhen = (scenario) => {
if (!scenario.usecase) return
if (scenario.whens.length > 0) return
const when = builtinWhen()
scenario.whens.push(when)
}
class ScenarioWithSample {
constructor(scenario, sample) {
this.scenario = scenario
this.sample = sample
this.stage = stages.none
this._auditTrail = { sample, stage: this.stages }
}
async run() {
const exec = async (list, stages, context) => {
for (const item of list) {
await item.run(context)
}
this.state = list.find((check) => check.state === state.failed) ? state.failed : state.passed
this._auditTrail.state = this.state
this.stage = stages
return this.state
}
this.build()
this.context = { sample: this.sample, usecase: this.usecase }
let ret
ret = await exec(this.givens, stages.given, this.context)
if (ret === state.failed) return ret
ret = await exec(this.whens, stages.when, this.context)
if (ret === state.failed) return ret
ret = await exec(this.checks, stages.check, this.context)
if (ret === state.failed) return ret
}
build() {
const clone = (scenario) => {
this.usecase = scenario.usecase
this.info = scenario.info
this.body = scenario._body
}
clone(this.scenario)
const entries = Object.entries(this.body)
const intialized = entries.map(([k, v]) => v.create ? v.create(k) : {})
this.givens = intialized.filter(g => g.isGiven)
this.whens = intialized.filter(w => w.isWhen)
this.checks = intialized.filter(c => c.isCheck)
addBuiltinWhen(this)
}
get auditTrail() {
const audit = { ... this._auditTrail }
audit.stage = this.stage
audit.givens = this.givens.map(givens => givens.auditTrail)
audit.whens = this.whens.map(whens => whens.auditTrail)
audit.checks = this.checks.map(checks => checks.auditTrail)
return audit
}
}
class SamplesExecution {
constructor(scenario, samples) {
this.scenario = scenario
this.samples = samples
this.scenarios = []
this._auditTrail = { builtin: this.samples.builtin }
}
async run() {
const samples = this.samples
const ret = await samples.run()
if (ret === state.failed) return ret
const scenarioWithSample = this.scenarios
for (const sample of samples.value) {
const instance = new ScenarioWithSample(this.scenario, sample)
scenarioWithSample.push(instance)
const ret = await instance.run()
}
this.state = scenarioWithSample.find((ss) => ss.state === state.failed) ? state.failed : state.passed
return this.state
}
get auditTrail() {
const audit = { ... this._auditTrail }
audit.executions = this.scenarios.map(scenarios => scenarios.auditTrail)
return audit
}
}
class Scenario {
constructor(description, body, options = {}) {
this.type = 'scenario'
this.state = state.ready
this.description = description
this.ignore = false
this._auditTrail = { type: this.type, state: this.state, description: this.description }
this._body = body
this.only = options.only
}
async run() {
const addBuiltinSample = () => {
if (this.samples.length > 0) return
const factory = samples([{}])
const instance = factory.create('')
instance.builtin = true
this.samples.push(instance)
}
this.info = this._body.info
const entries = Object.entries(this._body)
const intialized = entries.map(([k, v]) => v.create ? v.create(k) : {})
this.samples = intialized.filter(s => s.isSamples)
addBuiltinSample()
if(this.ignore) {
this.state = state.ignored
this._auditTrail.state = this.state
return this.state
}
for (const samples of this.samples) {
const execution = new SamplesExecution(this, samples)
samples.execution = execution
const ret = await execution.run()
}
const run = this.samples.find((sc) => sc.execution.state === state.failed) ? state.failed : state.passed
this.state = run
this._auditTrail.state = run
return run
}
doc() {
const build = () => {
this.info = this._body.info
const entries = Object.entries(this._body)
const intialized = entries.map(([k, v]) => v.create ? v.create(k) : {})
this.samples = intialized.filter(s => s.isSamples)
this.givens = intialized.filter(g => g.isGiven)
this.whens = intialized.filter(w => w.isWhen)
this.checks = intialized.filter(c => c.isCheck)
addBuiltinWhen(this)
}
build()
const doc = {
type: this.type,
description: this.description,
info: this.info,
samples: this.samples.map(sample => sample.doc()),
givens: this.givens.map(given => given.doc()),
whens: this.whens.map(when => when.doc()).filter(Boolean),
checks: this.checks.map(check => check.doc())
}
return doc
}
get auditTrail() {
const audit = { ... this._auditTrail }
audit.samples = this.samples.map(s => s.execution.auditTrail)
return audit
}
get isScenario() {
return true
}
}
const scenario = (body, options) => ({
create: (description) => { return new Scenario(description, body, options) }
})
scenario.only = (body, options) => scenario(body, Object.assign({}, options, { only: true }))
module.exports = { scenario }