Eltro: Added both before() and after() support and functionality

This commit is contained in:
Jonatan Nilsson 2021-06-18 02:06:08 +00:00
parent 3bd8d4ba51
commit 084b751b5b
4 changed files with 517 additions and 26 deletions

View file

@ -28,11 +28,19 @@ Next in your favourite editor, create `test/test.mjs`:
import { Eltro as t, assert} from 'eltro' import { Eltro as t, assert} from 'eltro'
t.describe('Array', function() { t.describe('Array', function() {
t.before(function() {
// Prepare our test if needed
})
t.describe('#indexOf()', function() { t.describe('#indexOf()', function() {
t.test('should return -1 when value is not present', function() { t.test('should return -1 when value is not present', function() {
assert.equal([1,2,3].indexOf(4), -1) assert.equal([1,2,3].indexOf(4), -1)
}) })
}) })
t.after(function() {
// Cleanup after if needed
})
}) })
``` ```
@ -140,12 +148,12 @@ import { Eltro as t, assert} from 'eltro'
function someFunction() { return true } function someFunction() { return true }
t.test('#someFunction()', function() { t.describe('#someFunction()', function() {
t.test('should always return true', function() { t.test('should always return true', function() {
assert.strictEqual(someFunction(), true) assert.strictEqual(someFunction(), true)
assert.strictEqual(someFunction(), true) assert.strictEqual(someFunction(), true)
assert.strictEqual(someFunction(), true) assert.strictEqual(someFunction(), true)
}).skip() })
}) })
``` ```
@ -155,6 +163,70 @@ will output:
#someFunction() should always return true #someFunction() should always return true
``` ```
### t.before(func)
Queue up the `func` to run before any test or groups within current active group.
```node
import { Eltro as t, assert} from 'eltro'
t.before(function() {
// Prepare something before we start any of the below tests
})
t.describe('#myTest()', function() {
t.before(function() {
// Runs before the test below
})
t.test('true should always be true', function() {
assert.strictEqual(true, true)
})
})
t.describe('#anotherTest()', function() {
t.before(function() {
// Runs before the test below
})
t.test('false should always be false', function() {
assert.strictEqual(false, false)
})
})
```
### t.after(func)
Queue up the `func` to run after any test or groups within current active group.
```node
import { Eltro as t, assert} from 'eltro'
t.after(function() {
// After we finish all the tests below, this gets run
})
t.describe('#myTest()', function() {
t.after(function() {
// Runs after the test below
})
t.test('true should always be true', function() {
assert.strictEqual(true, true)
})
})
t.describe('#anotherTest()', function() {
t.after(function() {
// Runs after the test below
})
t.test('false should always be false', function() {
assert.strictEqual(false, false)
})
})
```
### t.only() ### t.only()
Eltro supports exclusivity when running tests. When specified, only tests marked with only will be run. Eltro supports exclusivity when running tests. When specified, only tests marked with only will be run.

View file

@ -10,6 +10,8 @@ function Group(e, name) {
this.customTimeout = null this.customTimeout = null
this.skipTest = false this.skipTest = false
this.isExclusive = false this.isExclusive = false
this.before = null
this.after = null
} }
Group.prototype.timeout = function(time) { Group.prototype.timeout = function(time) {
@ -53,6 +55,7 @@ function Test(e, group, name, func) {
this.skipTest = false this.skipTest = false
this.isExclusive = false this.isExclusive = false
this.customTimeout = null this.customTimeout = null
this.isBasic = false
this.name = name this.name = name
this.func = func this.func = func
this.error = null this.error = null
@ -108,7 +111,7 @@ Eltro.prototype.begin = function() {
this.fileGroupMap.clear() this.fileGroupMap.clear()
} }
Eltro.prototype.__runTest = async function(stats, test) { Eltro.prototype.__runTest = async function(stats, test, prefix = 'Test') {
if (this.reporter === 'list') { if (this.reporter === 'list') {
process.stdout.write(' \x1b[90m? ' + test.name + '\x1b[0m') process.stdout.write(' \x1b[90m? ' + test.name + '\x1b[0m')
} }
@ -187,16 +190,18 @@ Eltro.prototype.__runTest = async function(stats, test) {
} }
}) })
.then(function() { .then(function() {
if (prefix === 'Test') {
stats.passed++ stats.passed++
}
}, function(err) { }, function(err) {
let saveError = err let saveError = err
if (!saveError) { if (!saveError) {
saveError = new Error('Test promise rejected with empty message') saveError = new Error(prefix + ' promise rejected with empty message')
} else if (typeof(saveError) !== 'object' || saveError.message == null || saveError.stack == null) { } else if (typeof(saveError) !== 'object' || saveError.message == null || saveError.stack == null) {
try { try {
saveError = new Error('Test promise rejected with ' + JSON.stringify(saveError)) saveError = new Error(prefix + ' promise rejected with ' + JSON.stringify(saveError))
} catch (parseError) { } catch (parseError) {
saveError = new Error('Test promise rejected with ' + saveError + ' (Error stringifying: ' + parseError.message + ')') saveError = new Error(prefix + ' promise rejected with ' + saveError + ' (Error stringifying: ' + parseError.message + ')')
} }
saveError.originalError = err saveError.originalError = err
} }
@ -219,7 +224,7 @@ Eltro.prototype.__runTest = async function(stats, test) {
process.stdout.write(' \x1b[94m- ' + test.name + '\x1b[0m\n') process.stdout.write(' \x1b[94m- ' + test.name + '\x1b[0m\n')
} else if (!test.error) { } else if (!test.error) {
process.stdout.write(' \x1b[32m√\x1b[90m ' + test.name + '\x1b[0m\n') process.stdout.write(' \x1b[32m√\x1b[90m ' + test.name + '\x1b[0m\n')
} else { } else if (prefix === 'Test') {
process.stdout.write(' \x1b[31m' + this.failedTests.length + ') ' + test.name + '\x1b[0m\n') process.stdout.write(' \x1b[31m' + this.failedTests.length + ') ' + test.name + '\x1b[0m\n')
} }
} else if (this.reporter === 'dot') { } else if (this.reporter === 'dot') {
@ -227,7 +232,7 @@ Eltro.prototype.__runTest = async function(stats, test) {
process.stdout.write('\x1b[94m.\x1b[0m') process.stdout.write('\x1b[94m.\x1b[0m')
} else if (!test.error) { } else if (!test.error) {
process.stdout.write('\x1b[32m.\x1b[0m') process.stdout.write('\x1b[32m.\x1b[0m')
} else { } else if (prefix === 'Test') {
process.stdout.write('\x1b[31m.\x1b[0m') process.stdout.write('\x1b[31m.\x1b[0m')
} }
} }
@ -239,6 +244,10 @@ Eltro.prototype.__runGroup = async function(g, stats) {
console.log(' ' + g.name) console.log(' ' + g.name)
} }
} }
if (g.before) {
await this.__runTest(stats, g.before, 'Before')
if (g.before.error) return
}
for (let x = 0; x < g.tests.length; x++) { for (let x = 0; x < g.tests.length; x++) {
if (!g.tests[x].skipTest && g.tests[x].isExclusive === g.hasExclusive) { if (!g.tests[x].skipTest && g.tests[x].isExclusive === g.hasExclusive) {
await this.__runTest(stats, g.tests[x]) await this.__runTest(stats, g.tests[x])
@ -248,6 +257,9 @@ Eltro.prototype.__runGroup = async function(g, stats) {
if (!g.groups[x].skipTest && g.hasExclusive === (g.groups[x].hasExclusive || g.groups[x].isExclusive)) if (!g.groups[x].skipTest && g.hasExclusive === (g.groups[x].hasExclusive || g.groups[x].isExclusive))
await this.__runGroup(g.groups[x], stats) await this.__runGroup(g.groups[x], stats)
} }
if (g.after) {
await this.__runTest(stats, g.after, 'After')
}
} }
Eltro.prototype.run = async function() { Eltro.prototype.run = async function() {
@ -293,6 +305,7 @@ Eltro.prototype.run = async function() {
} }
} }
} }
return stats
} }
Eltro.prototype.setFilename = function(filename) { Eltro.prototype.setFilename = function(filename) {
@ -308,6 +321,38 @@ Eltro.prototype.resetFilename = function() {
this.activeGroup = null this.activeGroup = null
} }
Eltro.prototype.before = function(func) {
if (!this.activeGroup) {
throw new Error('Tests outside groups are not allowed.')
}
let test = new Test(this, this.activeGroup, 'Before: ' + this.activeGroup.name, func)
if (this.temporary.timeout || this.activeGroup.customTimeout) {
test.timeout(this.temporary.timeout || this.activeGroup.customTimeout)
this.temporary.timeout = 0
}
this.activeGroup.before = test
return test
}
Eltro.prototype.after = function(func) {
if (!this.activeGroup) {
throw new Error('Tests outside groups are not allowed.')
}
let test = new Test(this, this.activeGroup, 'After: ' + this.activeGroup.name, func)
if (this.temporary.timeout || this.activeGroup.customTimeout) {
test.timeout(this.temporary.timeout || this.activeGroup.customTimeout)
this.temporary.timeout = 0
}
this.activeGroup.after = test
return test
}
Eltro.prototype.describe = function(name, func) { Eltro.prototype.describe = function(name, func) {
let before = this.activeGroup let before = this.activeGroup

View file

@ -1,6 +1,6 @@
{ {
"name": "eltro", "name": "eltro",
"version": "1.0.2", "version": "1.1.0",
"description": "Eltro is a tiny no-dependancy test framework for node", "description": "Eltro is a tiny no-dependancy test framework for node",
"main": "index.mjs", "main": "index.mjs",
"scripts": { "scripts": {

View file

@ -224,6 +224,22 @@ e.test('Eltro should support timed out tests on late tests', async function() {
assert.match(t.failedTests[0].error.message, /50ms/) assert.match(t.failedTests[0].error.message, /50ms/)
}) })
e.test('Eltro should support timed out tests in front', async function() {
testsWereRun = true
const t = CreateT()
t.begin()
t.describe('', function() {
t.timeout(25).test('', function(cb) { setTimeout(cb, 50) })
t.test('', function(cb) { setTimeout(cb, 50) })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.ok(t.failedTests[0].error)
assert.match(t.failedTests[0].error.message, /25ms/)
})
e.test('Eltro should support skipped tests', async function() { e.test('Eltro should support skipped tests', async function() {
testsWereRun = true testsWereRun = true
const t = CreateT() const t = CreateT()
@ -252,22 +268,6 @@ e.test('Eltro should support only tests', async function() {
assert.strictEqual(assertIsTrue, true) assert.strictEqual(assertIsTrue, true)
}) })
e.test('Eltro should support timed out tests in front', async function() {
testsWereRun = true
const t = CreateT()
t.begin()
t.describe('', function() {
t.timeout(25).test('', function(cb) { setTimeout(cb, 50) })
t.test('', function(cb) { setTimeout(cb, 50) })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.ok(t.failedTests[0].error)
assert.match(t.failedTests[0].error.message, /25ms/)
})
e.test('Eltro should support skipped tests in front of the test', async function() { e.test('Eltro should support skipped tests in front of the test', async function() {
testsWereRun = true testsWereRun = true
let assertIsTrue = false let assertIsTrue = false
@ -283,6 +283,380 @@ e.test('Eltro should support skipped tests in front of the test', async function
assert.strictEqual(assertIsTrue, true) assert.strictEqual(assertIsTrue, true)
}) })
e.test('Eltro should support before() functions in describe group', async function() {
testsWereRun = true
let assertRan = 0
let firstBefore = 0
let secondBefore = 0
let thirdBefore = 0
const t = CreateT()
t.begin()
t.describe('', function() {
t.before(function() {
firstBefore = assertRan
})
t.describe('', function() {
t.before(function() {
secondBefore = assertRan
})
t.test('', function() { assertRan++ })
t.test('', function() { assertRan++ })
t.test('', function() { assertRan++ })
})
t.describe('', function() {
t.before(function() {
thirdBefore = assertRan
})
t.test('', function() { assertRan++ })
})
t.test('', function() { assertRan++ })
})
let stats = await t.run()
assert.strictEqual(t.failedTests.length, 0)
assert.strictEqual(assertRan, 5)
assert.strictEqual(stats.passed, 5)
assert.strictEqual(firstBefore, 0)
assert.strictEqual(secondBefore, 1)
assert.strictEqual(thirdBefore, 4)
})
e.test('Eltro should support before() functions in describe, timing out', async function() {
testsWereRun = true
let assertRan = 0
const t = CreateT()
t.begin()
t.describe('', function() {
t.before(function(cb) { }).timeout(50)
t.test('', function() { assertRan++ })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.ok(t.failedTests[0].error)
assert.match(t.failedTests[0].error.message, /50ms/)
assert.strictEqual(assertRan, 0)
})
e.test('Eltro should support before() functions in describe, late timing out', async function() {
testsWereRun = true
let assertRan = 0
const t = CreateT()
t.begin()
t.describe('', function() {
t.before(function(cb) {
setTimeout(cb, 100)
}).timeout(50)
t.test('', function() { assertRan++ })
})
t.describe('', function() {
t.test('', function(cb) { assertRan++; setTimeout(cb, 25) })
t.test('', function(cb) { assertRan++; setTimeout(cb, 25) })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.ok(t.failedTests[0].error)
assert.match(t.failedTests[0].error.message, /50ms/)
assert.strictEqual(assertRan, 2)
})
e.test('Eltro should support before() functions in describe, timing out in front', async function() {
testsWereRun = true
let assertRan = 0
const t = CreateT()
t.begin()
t.describe('', function() {
t.timeout(25).before(function(cb) { setTimeout(cb, 50) })
t.test('', function() { assertRan++ })
})
t.describe('', function() {
t.test('', function(cb) { assertRan++; setTimeout(cb, 25) })
t.test('', function(cb) { assertRan++; setTimeout(cb, 25) })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.ok(t.failedTests[0].error)
assert.match(t.failedTests[0].error.message, /25ms/)
assert.strictEqual(assertRan, 2)
})
e.test('Eltro should support before() functions in describe, being promised', async function() {
testsWereRun = true
let assertIsTrue = false
const t = CreateT()
t.begin()
t.describe('', function() {
t.before(function() {
return new Promise(function(res) {
assertIsTrue = true
res()
})
})
t.test('', function() { })
})
await t.run()
assert.strictEqual(t.failedTests.length, 0)
assert.strictEqual(assertIsTrue, true)
})
e.test('Eltro should support before() functions in describe, support callback', async function() {
testsWereRun = true
let assertIsTrue = false
const t = CreateT()
t.begin()
t.describe('', function() {
t.before(function(cb) {
setTimeout(function() {
assertIsTrue = true
cb()
}, 25)
})
t.test('', function() { })
})
await t.run()
assert.strictEqual(t.failedTests.length, 0)
assert.strictEqual(assertIsTrue, true)
})
e.test('Eltro should support before() functions in describe, support directly thrown errors', async function() {
testsWereRun = true
const assertError = new Error()
const t = CreateT()
t.begin()
t.describe('', function() {
t.before(function() {
throw assertError
})
t.test('', function() { })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.strictEqual(t.failedTests[0].error, assertError)
})
e.test('Eltro should support before() functions in describe, support rejected promises', async function() {
testsWereRun = true
const assertError = new Error()
const t = CreateT()
t.begin()
t.describe('', function() {
t.before(function() {
return new Promise(function(res, rej) {
rej(assertError)
})
})
t.test('', function() {})
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.strictEqual(t.failedTests[0].error, assertError)
})
e.test('Eltro should support before() functions in describe, support callback rejected', async function() {
testsWereRun = true
const assertError = new Error()
const t = CreateT()
t.begin()
t.describe('', function() {
t.before(function(cb) { cb(assertError) })
t.test('', function() { })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.strictEqual(t.failedTests[0].error, assertError)
})
e.test('Eltro should support after() functions in describe group', async function() {
testsWereRun = true
let assertRan = 0
let firstAfter = 0
let secondAfter = 0
let thirdAfter = 0
const t = CreateT()
t.begin()
t.describe('', function() {
t.after(function() {
firstAfter = assertRan
})
t.describe('', function() {
t.after(function() {
secondAfter = assertRan
})
t.test('', function() { assertRan++ })
t.test('', function() { assertRan++ })
t.test('', function() { assertRan++ })
})
t.describe('', function() {
t.after(function() {
thirdAfter = assertRan
})
t.test('', function() { assertRan++ })
})
t.test('', function() { assertRan++ })
})
let stats = await t.run()
assert.strictEqual(t.failedTests.length, 0)
assert.strictEqual(stats.passed, 5)
assert.strictEqual(assertRan, 5)
assert.strictEqual(firstAfter, 5)
assert.strictEqual(secondAfter, 4)
assert.strictEqual(thirdAfter, 5)
})
e.test('Eltro should support after() functions in describe, timing out', async function() {
testsWereRun = true
let assertRan = 0
const t = CreateT()
t.begin()
t.describe('', function() {
t.after(function(cb) { }).timeout(50)
t.test('', function() { assertRan++ })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.ok(t.failedTests[0].error)
assert.match(t.failedTests[0].error.message, /50ms/)
assert.strictEqual(assertRan, 1)
})
e.test('Eltro should support after() functions in describe, late timing out', async function() {
testsWereRun = true
let assertRan = 0
const t = CreateT()
t.begin()
t.describe('', function() {
t.after(function(cb) {
setTimeout(cb, 100)
}).timeout(50)
t.test('', function() { assertRan++ })
})
t.describe('', function() {
t.test('', function(cb) { assertRan++; setTimeout(cb, 25) })
t.test('', function(cb) { assertRan++; setTimeout(cb, 25) })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.ok(t.failedTests[0].error)
assert.match(t.failedTests[0].error.message, /50ms/)
assert.strictEqual(assertRan, 3)
})
e.test('Eltro should support after() functions in describe, timing out in front', async function() {
testsWereRun = true
let assertRan = 0
const t = CreateT()
t.begin()
t.describe('', function() {
t.timeout(25).after(function(cb) { setTimeout(cb, 50) })
t.test('', function() { assertRan++ })
})
t.describe('', function() {
t.test('', function(cb) { assertRan++; setTimeout(cb, 25) })
t.test('', function(cb) { assertRan++; setTimeout(cb, 25) })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.ok(t.failedTests[0].error)
assert.match(t.failedTests[0].error.message, /25ms/)
assert.strictEqual(assertRan, 3)
})
e.test('Eltro should support after() functions in describe, being promised', async function() {
testsWereRun = true
let assertIsTrue = false
const t = CreateT()
t.begin()
t.describe('', function() {
t.after(function() {
return new Promise(function(res) {
assertIsTrue = true
res()
})
})
t.test('', function() { })
})
await t.run()
assert.strictEqual(t.failedTests.length, 0)
assert.strictEqual(assertIsTrue, true)
})
e.test('Eltro should support after() functions in describe, support callback', async function() {
testsWereRun = true
let assertIsTrue = false
const t = CreateT()
t.begin()
t.describe('', function() {
t.after(function(cb) {
setTimeout(function() {
assertIsTrue = true
cb()
}, 25)
})
t.test('', function() { })
})
await t.run()
assert.strictEqual(t.failedTests.length, 0)
assert.strictEqual(assertIsTrue, true)
})
e.test('Eltro should support after() functions in describe, support directly thrown errors', async function() {
testsWereRun = true
const assertError = new Error()
const t = CreateT()
t.begin()
t.describe('', function() {
t.after(function() {
throw assertError
})
t.test('', function() { })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.strictEqual(t.failedTests[0].error, assertError)
})
e.test('Eltro should support after() functions in describe, support rejected promises', async function() {
testsWereRun = true
const assertError = new Error()
const t = CreateT()
t.begin()
t.describe('', function() {
t.after(function() {
return new Promise(function(res, rej) {
rej(assertError)
})
})
t.test('', function() {})
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.strictEqual(t.failedTests[0].error, assertError)
})
e.test('Eltro should support after() functions in describe, support callback rejected', async function() {
testsWereRun = true
const assertError = new Error()
const t = CreateT()
t.begin()
t.describe('', function() {
t.after(function(cb) { cb(assertError) })
t.test('', function() { })
})
await t.run()
assert.strictEqual(t.failedTests.length, 1)
assert.strictEqual(t.failedTests[0].error, assertError)
})
e.test('Eltro should support only tests in front of the test', async function() { e.test('Eltro should support only tests in front of the test', async function() {
testsWereRun = true testsWereRun = true
let assertIsTrue = false let assertIsTrue = false