Muthu Kumar
6 years ago
19 changed files with 639 additions and 521 deletions
@ -1,98 +0,0 @@ |
|||||
/** |
|
||||
* This file contains random tests |
|
||||
* used during development |
|
||||
*/ |
|
||||
|
|
||||
const Gunner = require('../index.js'); |
|
||||
const gunner = new Gunner({ name: 'sample tests' }); |
|
||||
const a = 1; |
|
||||
|
|
||||
// gunner.before(Gunner.Start, () => console.log('Started tests!'));
|
|
||||
// gunner.before(Gunner.End, () => console.log('Ended tests!'));
|
|
||||
// let runCount = 1;
|
|
||||
// gunner.before('*', () => console.log(`Running test ${runCount++}`));
|
|
||||
|
|
||||
gunner.test('should automatically pass', expect => expect().done()); |
|
||||
gunner.test(`should be equal`, expect => expect(1).equal(1)); |
|
||||
gunner.test(`objects are deep equal`, expect => expect({ a: 1 }).deepEqual({ a: 1 })); |
|
||||
gunner.test('expression should be true', expect => expect(a === 1).isTrue()); |
|
||||
|
|
||||
gunner.test('should be a Promise (resolved)', expect => |
|
||||
expect(Promise.resolve()).isPromise()); |
|
||||
|
|
||||
gunner.test('should be a Promise (rejected)', expect => |
|
||||
expect(Promise.reject()).isPromise()); |
|
||||
|
|
||||
gunner.test('wait and resolve', () => { |
|
||||
return new Promise(r => { |
|
||||
setTimeout( |
|
||||
() => r('ok'), |
|
||||
500 |
|
||||
); |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
gunner.test('should resolve to 5', expect => |
|
||||
expect(Promise.resolve(5)).resolvesTo(5)); |
|
||||
|
|
||||
// gunner.before(
|
|
||||
// 'file must have hello as content',
|
|
||||
// () => console.log('>> starting test! file must have hello as content'),
|
|
||||
// );
|
|
||||
|
|
||||
// gunner.after(
|
|
||||
// 'file must have hello as content',
|
|
||||
// () => console.log('>> finished test! file must have hello as content'),
|
|
||||
// );
|
|
||||
|
|
||||
gunner.test('file must have hello as content', async expect => { |
|
||||
const { readFile } = require('fs').promises; |
|
||||
const file = await readFile(__dirname + '/hello.txt', { encoding: 'utf8' }); |
|
||||
return [ |
|
||||
expect(file).equal('hello'), |
|
||||
expect(file.length).equal(5), |
|
||||
]; |
|
||||
}); |
|
||||
|
|
||||
gunner.test('(should fail) Should automatically fail', expect => |
|
||||
expect().fail()); |
|
||||
|
|
||||
gunner.test('(should fail) Value is not a Promise', expect => |
|
||||
expect(5).isPromise()); |
|
||||
|
|
||||
gunner.test('(should fail) Error is not a Promise', expect => |
|
||||
expect(flamethrower()).isPromise()); |
|
||||
|
|
||||
gunner.test(`(should fail) objects aren't deeply equal`, expect => expect({a : 1}).deepEqual({ a: 2 })); |
|
||||
|
|
||||
gunner.test('(should fail) promise must reject', expect => |
|
||||
expect(Promise.reject(new Error('Promise Rejected'))).equal('no rejection')); |
|
||||
|
|
||||
gunner.test('(should fail) multiple expect', expect => { |
|
||||
|
|
||||
const a = { }; |
|
||||
a.b = 1; |
|
||||
a.c = 2; |
|
||||
|
|
||||
return [ |
|
||||
expect(a).hasProp('b'), |
|
||||
expect(a).hasPair('c', 3), |
|
||||
]; |
|
||||
|
|
||||
}); |
|
||||
|
|
||||
const flamethrower = () => { |
|
||||
throw new Error('This burns!'); |
|
||||
}; |
|
||||
|
|
||||
gunner.test('(should fail) should catch error', expect => { |
|
||||
return expect(flamethrower()).equal(5); |
|
||||
}); |
|
||||
|
|
||||
gunner.test('(should fail) should not resolve to 5', expect => |
|
||||
expect(Promise.resolve()).resolvesTo(5)); |
|
||||
|
|
||||
const trace = process.argv.slice(2).indexOf('--trace') !== -1; |
|
||||
const log = process.argv.slice(2).indexOf('--log') !== -1; |
|
||||
|
|
||||
gunner.run({ trace, log }); |
|
@ -0,0 +1,102 @@ |
|||||
|
/** |
||||
|
* This file contains random tests |
||||
|
* used during development |
||||
|
*/ |
||||
|
|
||||
|
const Gunner = require('../index.js'); |
||||
|
const expect = Gunner.expect; |
||||
|
const expectMany = Gunner.expectMany; |
||||
|
const gunner = new Gunner({ name: 'sample tests' }); |
||||
|
const a = 1; |
||||
|
|
||||
|
gunner.before(Gunner.Start, () => console.log('Started tests!')); |
||||
|
gunner.before(Gunner.End, () => console.log('Ended tests!')); |
||||
|
let runCount = 1; |
||||
|
gunner.before('*', () => console.log(`Running test ${runCount++}`)); |
||||
|
|
||||
|
gunner.test('should automatically pass', () => expect().done()); |
||||
|
gunner.test(`should be equal`, () => expect(1).equal(1)); |
||||
|
gunner.test(`objects are deep equal`, () => expect({ a: 1 }).deepEqual({ a: 1 })); |
||||
|
gunner.test('expression should be true', () => expect(a === 1).isTrue()); |
||||
|
|
||||
|
gunner.test('should be a Promise (resolved)', () => |
||||
|
expect(Promise.resolve()).isPromise()); |
||||
|
|
||||
|
gunner.test('should be a Promise (rejected)', () => |
||||
|
expect(Promise.reject()).isPromise()); |
||||
|
|
||||
|
gunner.test('wait and resolve', () => { |
||||
|
return new Promise(r => { |
||||
|
setTimeout( |
||||
|
() => r('ok'), |
||||
|
50 |
||||
|
); |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
gunner.test('should resolve to 5', () => |
||||
|
expect(Promise.resolve(5)).resolvesTo(5)); |
||||
|
|
||||
|
gunner.before( |
||||
|
'file must have hello as content', |
||||
|
() => console.log('>> starting test! file must have hello as content'), |
||||
|
'helloContentBefore', |
||||
|
); |
||||
|
|
||||
|
gunner.after( |
||||
|
'file must have hello as content', |
||||
|
() => console.log('>> finished test! file must have hello as content'), |
||||
|
'helloContentAfter', |
||||
|
); |
||||
|
|
||||
|
gunner.test('file must have hello as content', async () => { |
||||
|
const { readFile } = require('fs').promises; |
||||
|
const file = await readFile(__dirname + '/hello.txt', { encoding: 'utf8' }); |
||||
|
return [ |
||||
|
expect(file).equal('hello'), |
||||
|
expect(file.length).equal(5), |
||||
|
]; |
||||
|
}); |
||||
|
|
||||
|
gunner.test('(should fail) Should automatically fail', () => |
||||
|
expect().fail()); |
||||
|
|
||||
|
gunner.test('(should fail) Value is not a Promise', () => |
||||
|
expect(5).isPromise()); |
||||
|
|
||||
|
gunner.test('(should fail) Error is not a Promise', () => |
||||
|
expect(flamethrower()).isPromise()); |
||||
|
|
||||
|
gunner.test(`(should fail) objects aren't deeply equal`, () => expect({a : 1}).deepEqual({ a: 2 })); |
||||
|
|
||||
|
gunner.test('(should fail) promise must reject', () => |
||||
|
expect(Promise.reject(new Error('Promise Rejected'))).equal('no rejection')); |
||||
|
|
||||
|
gunner.test('(should fail) multiple expect', () => { |
||||
|
|
||||
|
const a = { }; |
||||
|
a.b = 1; |
||||
|
a.c = 2; |
||||
|
|
||||
|
return expectMany([ |
||||
|
expect(a).hasProp('b'), |
||||
|
expect(a).hasPair('c', 3), |
||||
|
]); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
const flamethrower = () => { |
||||
|
throw new Error('This burns!'); |
||||
|
}; |
||||
|
|
||||
|
gunner.test('(should fail) should catch error', () => { |
||||
|
return expect(flamethrower, []).equal(5); |
||||
|
}); |
||||
|
|
||||
|
gunner.test('(should fail) should not resolve to 5', () => |
||||
|
expect(Promise.resolve()).resolvesTo(5)); |
||||
|
|
||||
|
const trace = process.argv.slice(2).indexOf('--trace') !== -1; |
||||
|
const log = process.argv.slice(2).indexOf('--log') !== -1; |
||||
|
|
||||
|
gunner.run({ trace, log }).then(console.log); |
File diff suppressed because it is too large
@ -1,126 +1,91 @@ |
|||||
'use strict'; |
'use strict'; |
||||
|
|
||||
const { EOL } = require('os'); |
const { arrayOrPush } = require('./util'); |
||||
const chalk = require('chalk'); |
const caller = require('./lib/caller'); |
||||
|
|
||||
const Promise = require('bluebird'); |
const testrunner = require('./lib/testrunner'); |
||||
Promise.object = require('@codefeathers/promise.object'); |
const { expect, expectMany } = require('./lib/expect'); |
||||
|
|
||||
const _runTests = require('./lib/runTests'); |
|
||||
const _expect = require('./lib/expect'); |
|
||||
const logger = require('./lib/logger'); |
|
||||
|
|
||||
const symbols = require('./util/symbols'); |
const symbols = require('./util/symbols'); |
||||
|
|
||||
class Gunner { |
class Gunner { |
||||
|
|
||||
constructor (options = {}) { |
constructor (name) { |
||||
this.__hooks__ = { |
this.name = name; |
||||
before: { |
this.__suite__ = { |
||||
|
tests: [], |
||||
|
beforeHooks: { |
||||
[symbols.Start]: [], |
[symbols.Start]: [], |
||||
[symbols.End]: [], |
[symbols.End]: [], |
||||
'*': [], |
'*': [], |
||||
}, |
}, |
||||
after: { |
afterHooks: { |
||||
[symbols.Start]: [], |
[symbols.Start]: [], |
||||
[symbols.End]: [], |
[symbols.End]: [], |
||||
'*': [], |
'*': [], |
||||
}, |
} |
||||
}; |
}; |
||||
this.__state__ = []; |
|
||||
this.__tests__ = []; |
|
||||
this.name = options.name; |
|
||||
} |
} |
||||
|
|
||||
test (description, test) { |
test (description, test) { |
||||
const existing = ( |
const existing = ( |
||||
this.__tests__ |
this.__suite__.tests |
||||
.find(x => x.description === description) |
.find(x => x.description === description) |
||||
); |
); |
||||
if (existing) |
if (existing) |
||||
throw new Error(`Test '${description}' already exists!`); |
throw new Error(`Test '${description}' already exists!`); |
||||
|
|
||||
this.__tests__.push({ |
const unit = { |
||||
description, |
description, |
||||
test: state => { |
type: 'test', |
||||
try { |
run: state => caller(test, state), |
||||
return test(_expect, state); |
}; |
||||
} catch (e) { |
this.__suite__.tests.push(unit); |
||||
// If errors are thrown, reject them
|
|
||||
return Promise.reject(e); |
|
||||
} |
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
return this; |
return this; |
||||
} |
} |
||||
|
|
||||
before (description, run) { |
before (description, run, label) { |
||||
const hook = { |
const unit = { |
||||
description, |
description, |
||||
run, |
label, |
||||
|
type: 'hook', |
||||
|
run: state => caller(run, state), |
||||
}; |
}; |
||||
|
arrayOrPush(this.__suite__.beforeHooks, description, unit); |
||||
this.__hooks__.before[description] |
|
||||
? this.__hooks__.before[description].push(hook) |
|
||||
: this.__hooks__.before[description] = [ hook ]; |
|
||||
|
|
||||
return this; |
return this; |
||||
} |
} |
||||
|
|
||||
after (description, run) { |
after (description, run, label) { |
||||
const hook = { |
const unit = { |
||||
description, |
description, |
||||
run, |
label, |
||||
|
type: 'hook', |
||||
|
run: state => caller(run, state), |
||||
}; |
}; |
||||
|
arrayOrPush(this.__suite__.afterHooks, description, unit); |
||||
this.__hooks__.after[description] |
|
||||
? this.__hooks__.after[description].push(hook) |
|
||||
: this.__hooks__.after[description] = [ hook ]; |
|
||||
|
|
||||
return this; |
return this; |
||||
} |
} |
||||
|
|
||||
run (options = {}) { |
run (options = {}) { |
||||
return _runTests(this, options) |
return testrunner(this, options) |
||||
.then(results => { |
.then(results => { |
||||
const success = results.filter(r => r.result === 'pass'); |
const success = results.filter(r => r.status === 'ok'); |
||||
const successPercent = Math.floor( |
const successPercent = Math.floor( |
||||
success.length/results.length * 100 |
success.length/results.length * 100 |
||||
); |
); |
||||
|
|
||||
const beforeAfterLine = |
|
||||
successPercent === 100 |
|
||||
? chalk`{green ------------------------------------}` |
|
||||
: chalk`{red ------------------------------------}`; |
|
||||
|
|
||||
const log = logger.create(options); |
|
||||
log( |
|
||||
EOL, |
|
||||
beforeAfterLine, |
|
||||
EOL, EOL, |
|
||||
chalk`{green ${success.length}}`, |
|
||||
`tests passed of ${results.length}`, |
|
||||
`[${successPercent}% success]`, |
|
||||
EOL, EOL, |
|
||||
beforeAfterLine |
|
||||
); |
|
||||
|
|
||||
if((successPercent !== 100) && typeof process !== 'undefined') |
if((successPercent !== 100) && typeof process !== 'undefined') |
||||
process.exitCode = 1; |
process.exitCode = 1; |
||||
|
|
||||
return results; |
return results; |
||||
}) |
|
||||
.then(results => { |
|
||||
if (options.exit && typeof process !== 'undefined') |
|
||||
process.exit(); |
|
||||
return results; |
|
||||
}); |
}); |
||||
} |
} |
||||
|
|
||||
} |
} |
||||
|
|
||||
module.exports = Gunner; |
module.exports = Gunner; |
||||
module.exports.expect = _expect; |
module.exports.Gunner = Gunner; |
||||
|
module.exports.expect = expect; |
||||
|
module.exports.expectMany = expectMany; |
||||
module.exports.Start = symbols.Start; |
module.exports.Start = symbols.Start; |
||||
module.exports.End = symbols.End; |
module.exports.End = symbols.End; |
||||
|
@ -1,17 +1,19 @@ |
|||||
const Promise = require('bluebird'); |
|
||||
const { isPromise } = require('../util'); |
const { isPromise } = require('../util'); |
||||
|
|
||||
const createRejectionStatement = (statement, ...args) => |
const createRejectionStatement = (statement, ...args) => |
||||
Promise.reject(statement ? statement(...args) : ''); |
Promise.reject(statement ? statement(...args) : ''); |
||||
|
|
||||
const _assertPromise = (bool, statementTuple) => { |
const _assertPromise = (bool, statementTuple) => { |
||||
|
|
||||
const [ statement, ...args ] = statementTuple; |
const [ statement, ...args ] = statementTuple; |
||||
if(isPromise(bool)) |
if(isPromise(bool)) |
||||
return bool.catch(() => |
return bool.catch(() => |
||||
createRejectionStatement(statement, ...args)); |
createRejectionStatement(statement, ...args)); |
||||
|
|
||||
return bool |
return bool |
||||
? Promise.resolve() |
? Promise.resolve() |
||||
: createRejectionStatement(statement, ...args); |
: createRejectionStatement(statement, ...args); |
||||
|
|
||||
}; |
}; |
||||
|
|
||||
module.exports = _assertPromise; |
module.exports = _assertPromise; |
||||
|
@ -0,0 +1,49 @@ |
|||||
|
// Only imported for JSDoc
|
||||
|
/* eslint-disable-next-line */ |
||||
|
const Gunner = require('../gunner'); |
||||
|
const symbols = require('../util/symbols'); |
||||
|
|
||||
|
const wrap = type => unit => ({ type, unit }); |
||||
|
|
||||
|
/** |
||||
|
* runs the test suite |
||||
|
* @param {Gunner} instance |
||||
|
*/ |
||||
|
const buildTestTree = instance => { |
||||
|
|
||||
|
const testQueue = []; |
||||
|
|
||||
|
Array.prototype.push.apply(testQueue, |
||||
|
instance.__suite__.beforeHooks[symbols.Start].map(wrap('@start'))); |
||||
|
testQueue.push.apply( |
||||
|
instance.__suite__.afterHooks[symbols.Start].map(wrap('@start'))); |
||||
|
|
||||
|
instance.__suite__.tests.forEach(test => ( |
||||
|
|
||||
|
Array.prototype.push.apply(testQueue, |
||||
|
instance.__suite__.beforeHooks['*'] |
||||
|
.map(wrap('@every'))), |
||||
|
Array.prototype.push.apply(testQueue, |
||||
|
(instance.__suite__.beforeHooks[test.description] || []) |
||||
|
.map(wrap('@this'))), |
||||
|
testQueue.push(wrap('@test')(test)), |
||||
|
Array.prototype.push.apply(testQueue, |
||||
|
(instance.__suite__.afterHooks[test.description] || []) |
||||
|
.map(wrap('@afterTest'))), |
||||
|
Array.prototype.push.apply(testQueue, |
||||
|
(instance.__suite__.afterHooks['*']).map(wrap('@afterEvery'))) |
||||
|
|
||||
|
)); |
||||
|
|
||||
|
testQueue.push.apply( |
||||
|
instance.__suite__.beforeHooks[symbols.End] |
||||
|
.map(wrap('@end'))); |
||||
|
testQueue.push.apply( |
||||
|
instance.__suite__.afterHooks[symbols.End] |
||||
|
.map(wrap(symbols.End))); |
||||
|
|
||||
|
return testQueue; |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
module.exports = buildTestTree; |
@ -0,0 +1,30 @@ |
|||||
|
const { isPromise } = require('../util'); |
||||
|
|
||||
|
const caller = (test, state) => { |
||||
|
|
||||
|
let value, error, errored; |
||||
|
try { |
||||
|
value = test(state); |
||||
|
} catch (e) { |
||||
|
errored = true; |
||||
|
error = e; |
||||
|
} |
||||
|
|
||||
|
const promise = isPromise(value); |
||||
|
|
||||
|
if (promise) { |
||||
|
return value |
||||
|
.then(res => ({ status: 'ok', resolve: res, promise: true })) |
||||
|
.catch(rej => ({ status: 'notOk', rejection: rej, promise: true })); |
||||
|
} else { |
||||
|
return Promise.resolve({ |
||||
|
status: errored ? 'notOk' : 'ok', |
||||
|
...(!errored && { value }), |
||||
|
...(errored && { error }), |
||||
|
promise: false, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
module.exports = caller; |
@ -1,150 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
const Promise = require('bluebird'); |
|
||||
Promise.object = require('@codefeathers/promise.object'); |
|
||||
const chalk = require('chalk'); |
|
||||
|
|
||||
const logger = require('./logger'); |
|
||||
const { isPromise, taggedStringify: _ } = require('../util'); |
|
||||
const constants = require('../util/symbols'); |
|
||||
|
|
||||
const snipStack = e => { |
|
||||
|
|
||||
if (e.stack) |
|
||||
e.stack = e.stack |
|
||||
.split('\n') |
|
||||
.reduceRight( |
|
||||
(acc, x) => |
|
||||
/* eslint-disable-next-line */ |
|
||||
acc.done |
|
||||
? acc.cur |
|
||||
: x.match(/at Object\.test.*\/src\/gunner\.js/) |
|
||||
? { cur: x, done: true } |
|
||||
: { cur: [x, acc.cur].join('\n') }, |
|
||||
{ cur: '' }) |
|
||||
.cur.trim(); |
|
||||
|
|
||||
return e; |
|
||||
|
|
||||
}; |
|
||||
|
|
||||
const unitReducer = |
|
||||
(units = [], stateMark) => |
|
||||
(state = {}) => |
|
||||
units.reduce( |
|
||||
(accumulator, unit) => |
|
||||
accumulator |
|
||||
.then(thisState => |
|
||||
Promise.resolve( |
|
||||
unit.run({ ...state, [stateMark]: thisState }) |
|
||||
) |
|
||||
.then(newState => |
|
||||
[ ...thisState, newState ])), |
|
||||
Promise.resolve(state[stateMark] || []), |
|
||||
); |
|
||||
|
|
||||
const runTests = (instance, options) => { |
|
||||
|
|
||||
const log = logger.create(options); |
|
||||
|
|
||||
const beforeAll = () => |
|
||||
unitReducer( |
|
||||
[ |
|
||||
...(instance.__hooks__.before[constants.Start] || []), |
|
||||
...(instance.__hooks__.after[constants.Start] || []), |
|
||||
], |
|
||||
'@start', |
|
||||
)(); |
|
||||
|
|
||||
const beforeEvery = state => |
|
||||
unitReducer( |
|
||||
instance.__hooks__.before['*'], |
|
||||
'@every', |
|
||||
)(state); |
|
||||
|
|
||||
const runner = state => Promise.mapSeries(instance.__tests__, each => { |
|
||||
|
|
||||
const beforeThis = |
|
||||
unitReducer( |
|
||||
instance.__hooks__.before[each.description], |
|
||||
'@this' |
|
||||
); |
|
||||
|
|
||||
const afterThis = |
|
||||
unitReducer( |
|
||||
instance.__hooks__.after[each.description], |
|
||||
'@afterThis' |
|
||||
); |
|
||||
|
|
||||
return Promise.object({ ...state, '@every': beforeEvery(state) }) |
|
||||
.then(state => Promise.object({ ...state, '@this': beforeThis(state) })) |
|
||||
.then(state => { |
|
||||
|
|
||||
const pred = each.test(state); |
|
||||
|
|
||||
/* There are 4 different cases at play: |
|
||||
1. A plain expect() is returned. |
|
||||
2. An array of [ expect() ] is returned |
|
||||
3. A plain expect() is wrapped in a promise |
|
||||
4. An array of [ expect() ] is wrapped in a promise. |
|
||||
Here we normalise all of them into something we can process */ |
|
||||
|
|
||||
if (!isPromise(pred) && !(pred && isPromise(pred[0]))) |
|
||||
throw new Error(`Malformed test '${each.description}'`); |
|
||||
const toTest = Array.isArray(pred) |
|
||||
? Promise.all(pred) |
|
||||
: pred.then(x => Array.isArray(x) ? Promise.all(x) : x); |
|
||||
|
|
||||
return ([ |
|
||||
state, |
|
||||
toTest |
|
||||
.then(() => { |
|
||||
log( |
|
||||
`${chalk`{green ✅}`} :: `, |
|
||||
`${each.description}` |
|
||||
); |
|
||||
return { |
|
||||
description: each.description, |
|
||||
result: constants.pass |
|
||||
}; |
|
||||
}) |
|
||||
.catch(e => { |
|
||||
const error = (e && e.stack) ? snipStack(e) : e; |
|
||||
const trace = (options.trace && error) |
|
||||
? `\n Traceback:\n ` + _`${error}` |
|
||||
: ''; |
|
||||
log( |
|
||||
`${chalk`{red ❌}`} :: `, |
|
||||
`${each.description}`, |
|
||||
`${trace}` |
|
||||
); |
|
||||
return { |
|
||||
description: each.description, |
|
||||
result: constants.fail, |
|
||||
error, |
|
||||
}; |
|
||||
}), |
|
||||
]); |
|
||||
|
|
||||
}) |
|
||||
.then(([state, result]) => afterThis(state).then(() => result)); |
|
||||
|
|
||||
}); |
|
||||
|
|
||||
const afterAll = |
|
||||
unitReducer( |
|
||||
[ |
|
||||
...(instance.__hooks__.before[constants.End] || []), |
|
||||
...(instance.__hooks__.after[constants.End] || []), |
|
||||
], |
|
||||
'@after-all', |
|
||||
); |
|
||||
|
|
||||
return Promise.object({ '@start': beforeAll() }) |
|
||||
.then(state => Promise.object({ ...state, '@results': runner(state)})) |
|
||||
.then(state => Promise.object({ ...state, '@end': afterAll(state) })) |
|
||||
.then(state => state['@results']); |
|
||||
|
|
||||
}; |
|
||||
|
|
||||
module.exports = runTests; |
|
@ -0,0 +1,21 @@ |
|||||
|
const snipStack = e => { |
||||
|
|
||||
|
if (e.stack) |
||||
|
e.stack = e.stack |
||||
|
.split('\n') |
||||
|
.reduceRight( |
||||
|
(acc, x) => |
||||
|
/* eslint-disable-next-line */ |
||||
|
acc.done |
||||
|
? acc.cur |
||||
|
: x.match(/at Object\.test.*\/src\/gunner\.js/) |
||||
|
? { cur: x, done: true } |
||||
|
: { cur: [x, acc.cur].join('\n') }, |
||||
|
{ cur: '' }) |
||||
|
.cur.trim(); |
||||
|
|
||||
|
return e; |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
module.exports = snipStack; |
@ -0,0 +1,124 @@ |
|||||
|
// Only imported for JSDoc
|
||||
|
/* eslint-disable-next-line */ |
||||
|
const Gunner = require('../gunner'); |
||||
|
Promise.object = require('@codefeathers/promise.object'); |
||||
|
|
||||
|
const { last, pipe, pick, assignToObject } = require('../util'); |
||||
|
|
||||
|
const buildTestQueue = require('./buildTestQueue'); |
||||
|
|
||||
|
const findSkip = (skip, unit) => { |
||||
|
|
||||
|
const startFailed = skip.findIndex(x => |
||||
|
x.type === '@start'); |
||||
|
const everyFailed = skip.findIndex(x => |
||||
|
x.type === '@every'); |
||||
|
const beforeFailed = skip.findIndex(x => |
||||
|
x.description === unit.description); |
||||
|
|
||||
|
return (startFailed !== -1 |
||||
|
&& 'A start hook failed\n' |
||||
|
+ skip[startFailed].error) |
||||
|
|| (everyFailed !== -1 |
||||
|
&& 'An every hook failed\n' |
||||
|
+ skip[everyFailed].error) |
||||
|
|| (beforeFailed !== -1 |
||||
|
&& 'A before test hook failed\n' |
||||
|
+ skip[beforeFailed].error); |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
const reduceQueue = |
||||
|
queue => queue.reduce( |
||||
|
(acc, item) => |
||||
|
Promise.resolve(acc) |
||||
|
.then(acc => { |
||||
|
|
||||
|
return Promise.all([last(acc.results), Promise.object(acc.state)]) |
||||
|
.then(([, state]) => { |
||||
|
|
||||
|
const toSkip = findSkip(acc.skip, item.unit); |
||||
|
return [toSkip, state]; |
||||
|
|
||||
|
}) |
||||
|
.then(([toSkip, state]) => { |
||||
|
|
||||
|
return toSkip |
||||
|
? { status: 'skip', description: toSkip } |
||||
|
: item.unit.run(state); |
||||
|
|
||||
|
}) |
||||
|
.then(result => { |
||||
|
|
||||
|
const { status } = result; |
||||
|
|
||||
|
const identifier = (item.unit.label) |
||||
|
|| (queue |
||||
|
.filter(i => i.type === item.type) |
||||
|
.filter(i => (i.unit.description |
||||
|
=== item.unit.description)) |
||||
|
.length); |
||||
|
|
||||
|
if (item.type === '@test') { |
||||
|
|
||||
|
const resultObject = { |
||||
|
status, |
||||
|
description: item.unit.description, |
||||
|
...((status === 'notOk' || status === 'skip') |
||||
|
&& {reason : result.error |
||||
|
|| result.rejection |
||||
|
|| result.description}) |
||||
|
}; |
||||
|
acc.results.push(resultObject); |
||||
|
|
||||
|
} else { |
||||
|
|
||||
|
const stateAddition = |
||||
|
/* eslint-disable-next-line */ |
||||
|
status === 'ok' |
||||
|
? result.promise ? result.resolve : result.value |
||||
|
: null; |
||||
|
|
||||
|
if (stateAddition) |
||||
|
assignToObject( |
||||
|
acc.state, item.type |
||||
|
)(identifier, stateAddition); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
if (status === 'notOk') { |
||||
|
|
||||
|
acc.skip.push({ |
||||
|
type: item.type, |
||||
|
description: item.unit.description, |
||||
|
error: result.promise |
||||
|
? result.rejection |
||||
|
: result.error, |
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
return acc; |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
}), |
||||
|
{ results: [], state: {}, skip: [] }, |
||||
|
); |
||||
|
|
||||
|
/** |
||||
|
* runs the test suite |
||||
|
* @param {Gunner} instance |
||||
|
* @param {object} options |
||||
|
*/ |
||||
|
const testrunner = (instance) => { |
||||
|
|
||||
|
return pipe( |
||||
|
buildTestQueue, |
||||
|
reduceQueue, |
||||
|
pick('results'), |
||||
|
)(instance); |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
module.exports = testrunner; |
Loading…
Reference in new issue