Files
psf-memo/psf-memo-client/acceptance/acceptance.js
T

100 lines
2.9 KiB
JavaScript

/*
Normal acceptance runner for psf-memo-client.
Orchestrates the acceptance pipeline:
feature file -> bb gherkin-parser -> JSON IR -> acceptance entrypoint
generator -> generated test entry points -> node test runner
It procures the latest Babashka APS tools from the Acceptance-Pipeline-
Specification repository on first use, then parses, generates, and runs every
Gherkin feature under specs/.
Exit code 0 when all acceptance tests pass; non-zero otherwise.
*/
'use strict'
const { execFileSync } = require('node:child_process')
const fs = require('node:fs')
const path = require('node:path')
const root = path.resolve(__dirname, '..')
const specsDir = path.join(root, 'specs')
const buildDir = path.join(root, 'build', 'acceptance')
const irDir = path.join(buildDir, 'ir')
const genDir = path.join(buildDir, 'generated')
const apsDir = path.join(root, 'tmp', 'aps-spec')
function sh (cmd, args, opts = {}) {
return execFileSync(cmd, args, {
stdio: ['pipe', 'pipe', 'pipe'],
...opts
}).toString()
}
// Procure the latest APS tools if not already present in the worktree.
function ensureAps () {
if (fs.existsSync(apsDir)) return
fs.mkdirSync(path.dirname(apsDir), { recursive: true })
sh('git', ['clone', '--depth', '1',
'https://github.com/unclebob/Acceptance-Pipeline-Specification.git', apsDir])
}
function main () {
ensureAps()
const features = fs
.readdirSync(specsDir)
.filter((f) => f.endsWith('.feature'))
.sort()
if (features.length === 0) {
console.log('No feature files found under specs/.')
return
}
fs.mkdirSync(irDir, { recursive: true })
fs.mkdirSync(genDir, { recursive: true })
for (const featureFile of features) {
const base = featureFile.replace(/\.feature$/i, '')
const featurePath = path.join(specsDir, featureFile)
const irPath = path.join(irDir, `${base}.json`)
// 1) Parse the feature to JSON IR using the Babashka APS gherkin-parser.
sh('bb', ['gherkin-parser', featurePath, irPath], { cwd: apsDir })
// 2) Generate executable acceptance entry points from the IR.
sh('node', [path.join(root, 'acceptance', 'lib', 'generate.js'), irPath, genDir])
}
// 3) Run every generated acceptance test.
const tests = fs
.readdirSync(genDir)
.filter((f) => f.endsWith('.acceptance.test.js'))
.sort()
let failures = 0
for (const testFile of tests) {
try {
const out = sh('node', [path.join(genDir, testFile)])
process.stdout.write(out)
console.log(`ACCEPTANCE PASS: ${testFile}`)
} catch (err) {
failures++
process.stdout.write(err.stdout || '')
process.stderr.write(err.stderr || '')
console.error(`ACCEPTANCE FAIL: ${testFile}`)
}
}
if (failures > 0) {
console.error(`ACCEPTANCE: ${failures} failing test file(s)`)
process.exit(1)
} else {
console.log(`ACCEPTANCE: all ${tests.length} generated test file(s) passed`)
}
}
main()