codeceptjs
Version:
Supercharged End 2 End Testing Framework for NodeJS
244 lines (215 loc) • 5 kB
JavaScript
const fs = require('fs')
const path = require('path')
const { serializeTest } = require('./mocha/test')
/**
* @typedef {Object} Stats Statistics for a test result.
* @property {number} passes Number of passed tests.
* @property {number} failures Number of failed tests.
* @property {number} tests Total number of tests.
* @property {number} pending Number of pending tests.
* @property {number} failedHooks Number of failed hooks.
* @property {Date} start Start time of the test run.
* @property {Date} end End time of the test run.
* @property {number} duration Duration of the test run, in milliseconds.
*/
/**
* @typedef {Array<string|number>} Failure
* A detailed formatted report for a failed test.
*/
/**
* Result of a test run. Will be emitted for example in "event.all.result" events.
*/
class Result {
constructor() {
this._startTime = new Date()
this._endTime = null
this.reset()
this.start()
}
/**
* Resets all collected stats, tests, and failure reports.
*/
reset() {
this._stats = {
passes: 0,
failures: 0,
tests: 0,
pending: 0,
failedHooks: 0,
start: null,
end: null,
duration: 0,
}
/**
* @type {CodeceptJS.Test[]}
* @private
*/
this._tests = []
/**
* @type {Failure[]}
* @private
*/
this._failures = []
}
/**
* Sets the start time to the current time.
*/
start() {
this._startTime = new Date()
}
/**
* Sets the end time to the current time.
*/
finish() {
this._endTime = new Date()
}
/**
* Whether this result contains any failed tests.
*
* @type {boolean}
* @readonly
*/
get hasFailed() {
return this._stats.failures > 0
}
/**
* All collected tests.
*
* @type {CodeceptJS.Test[]}
* @readonly
*/
get tests() {
return this._tests
}
/**
* The failure reports (array of strings per failed test).
*
* @type {Failure[]}
* @readonly
*/
get failures() {
return this._failures.filter(f => f && (!Array.isArray(f) || f.length > 0))
}
/**
* The test statistics.
*
* @type {Stats}
* @readonly
*/
get stats() {
return this._stats
}
/**
* The start time of the test run.
*
* @type {Date}
* @readonly
*/
get startTime() {
return this._startTime
}
/**
* Adds a test to this result.
*
* @param {CodeceptJS.Test} test
*/
addTest(test) {
const existingTestIndex = this._tests.findIndex(t => !!t.uid && t.uid === test.uid)
if (existingTestIndex >= 0) {
this._tests[existingTestIndex] = test
return
}
this._tests.push(test)
}
/**
* Adds failure reports to this result.
*
* @param {Failure[]} newFailures
*/
addFailures(newFailures) {
this._failures.push(...newFailures)
}
/**
* Whether this result contains any failed tests.
*
* @type {boolean}
* @readonly
*/
get hasFailures() {
return this.stats.failures > 0
}
/**
* The duration of the test run, in milliseconds.
*
* @type {number}
* @readonly
*/
get duration() {
return this._endTime ? +this._endTime - +this._startTime : 0
}
/**
* All failed tests.
*
* @type {CodeceptJS.Test[]}
* readonly
*/
get failedTests() {
return this._tests.filter(test => test.state === 'failed')
}
/**
* All passed tests.
*
* @type {CodeceptJS.Test[]}
* @readonly
*/
get passedTests() {
return this._tests.filter(test => test.state === 'passed')
}
/**
* All skipped tests.
*
* @type {CodeceptJS.Test[]}
* @readonly
*/
get skippedTests() {
return this._tests.filter(test => test.state === 'skipped' || test.state === 'pending')
}
/**
* @returns {object} The JSON representation of this result.
*/
simplify() {
return {
hasFailed: this.hasFailed,
stats: this.stats,
duration: this.duration,
tests: this._tests.map(test => serializeTest(test)),
failures: this._failures,
}
}
/**
* Saves this result to a JSON file.
*
* @param {string} [fileName] Path to the JSON file, relative to `output_dir`. Defaults to "result.json".
*/
save(fileName) {
if (!fileName) fileName = 'result.json'
fs.writeFileSync(path.join(global.output_dir, fileName), JSON.stringify(this.simplify(), null, 2))
}
/**
* Adds stats to this result.
*
* @param {Partial<Stats>} [newStats]
*/
addStats(newStats = {}) {
this._stats.passes += newStats.passes || 0
this._stats.failures += newStats.failures || 0
this._stats.tests += newStats.tests || 0
this._stats.pending += newStats.pending || 0
this._stats.failedHooks += newStats.failedHooks || 0
// do not override start time
this._stats.start = this._stats.start || newStats.start
this._stats.end = newStats.end || this._stats.end
this._stats.duration = newStats.duration
}
}
module.exports = Result