import EventHandler from '../EventHandler.js'
/**
A test object that holds state.
*/
const Test = class extends EventHandler {
constructor(name, testFunction, setupFunction = null, teardownFunction = null) {
super()
this.name = new String(name || '')
this.testFunction = testFunction
this.setupFunction = setupFunction
this.teardownFunction = teardownFunction
this.assertionCount = 0
}
/**
@return {Object}
@property {bool} passed
@property {Object} [context] - a set of key:value pairs for communicating more info to test harnasses
*/
async run() {
this.trigger(Test.Started, this)
if (typeof this.setupFunction == 'function') {
try {
this.setupFunction(this)
this.trigger(Test.SetupSecceeded, this)
} catch (e) {
const context = {
message: 'Failed during setup',
error: e,
}
this.trigger(Test.SetupFailed, this, context)
return {
passed: false,
context: context,
}
}
}
try {
const context = this.testFunction(this)
this.trigger(Test.Passed, this, context)
return {
passed: true,
context: context || null,
}
} catch (e) {
const context = {
error: e,
}
this.trigger(Test.Failed, this, context)
return {
passed: false,
context: context,
}
} finally {
if (typeof this.teardownFunction == 'function') {
try {
this.teardownFunction(this)
this.trigger(Test.TeardownSucceeded, this)
} catch (e) {
this.trigger(Test.TeardownFailed, this, e)
console.error('Teardown error', e)
}
}
}
}
/**
assert*(...) functions return nothing if the assertion is true and throw an Error if the assertion is false
*/
assertTrue(value) {
this.assertionCount += 1
if (!value) {
throw new Error(`${value} is not true`)
}
}
assertType(value, typeName) {
this.assertionCount += 1
if (value == null) {
throw new Error(`${value} is null, so it not of type ${typeName}`)
}
if (typeof value !== typeName) {
throw new Error(`${value} is of type ${typeof value}, not ${typeName}`)
}
}
assertInstanceOf(value, clazz) {
this.assertionCount += 1
if (value instanceof clazz) {
return
}
throw new Error(`${value} is not an instance of ${clazz}`)
}
assertNull(value) {
this.assertionCount += 1
if (value !== null) {
throw new Error(`${value} is not null`)
}
}
assertEqual(val1, val2) {
this.assertionCount += 1
if (val1 === null) {
if (val2 !== null) {
throw new Error(`${val1} != ${val2}`)
}
}
if (val2 === null) {
if (val1 !== null) {
throw new Error(`${val1} != ${val2}`)
}
}
if (val1 == null) {
return
}
if (typeof val1 == 'undefined') {
if (typeof val2 !== 'undefined') {
throw new Error(`${val1} != ${val2}`)
}
}
if (typeof val2 == 'undefined') {
if (typeof val1 !== 'undefined') {
throw new Error(`${val1} != ${val2}`)
}
}
if (typeof val1 == 'undefined') {
return
}
if (typeof val1.equals == 'function') {
if (val1.equals(val2) == false) {
throw new Error(`${val1} != ${val2}`)
}
} else if (val1 != val2) {
throw new Error(`${val1} != ${val2}`)
}
return
}
assertNotEqual(val1, val2) {
if (val1 == val2) {
throw new Error(`${val1} == ${val2} (and it should not)`)
}
}
assertRegExpMatchCount(regExp, value, matchCount = 1, flags = '') {
if (typeof regExp === 'string') {
regExp = new RegExp(regExp)
}
const result = value.match(regExp)
if (result === null) {
if (matchCount === 0) return
throw new Error(`Expected ${matchCount} match(es) but received none: '${value}'.match(${regExp})`)
}
if (result.length !== matchCount) throw new Error(`Expected ${matchCount} matches: ${result}`)
}
assertRegExpMatches(regExp, value, matches = [], flags = '') {
if (typeof regExp === 'string') {
regExp = new RegExp(regExp, flags)
}
const result = value.match(regExp)
if (result === null) {
if (matches.length === 0) return
throw new Error(`Expected ${matches.length} match(es) but received none: '${value}'.match(${regExp})`)
}
if (result.length !== matches.length) throw new Error(`${result} !== ${matches} for '${value}'.match(${regExp})`)
for (let i = 0; i < matches.length; i++) {
if (matches[i] !== result[i]) throw new Error(`${result} !== ${matches} for '${value}'.match(${regExp})`)
}
}
}
// Events
Test.Started = Symbol('test-started')
Test.SetupSucceeded = Symbol('test-setup-succeeded')
Test.SetupFailed = Symbol('test-setup-failed')
Test.Passed = Symbol('test-passed')
Test.Failed = Symbol('test-failed')
Test.TeardownSucceeded = Symbol('test-teardown-succeeded')
Test.TeardownFailed = Symbol('test-teardown-failed')
export default Test