Browse Source

[rewrite] Added caller, snipStack, testrunner

master
Muthu Kumar 6 years ago
parent
commit
565b37c08c
  1. 25
      src/gunner.js
  2. 0
      src/lib/caller.js
  3. 1
      src/lib/expect.js
  4. 150
      src/lib/runTests.js
  5. 21
      src/lib/snipStack.js
  6. 124
      src/lib/testrunner.js

25
src/gunner.js

@ -67,23 +67,18 @@ class Gunner {
}
run (options = {}) {
return testrunner(this, options);
// .then(results => {
// const success = results.filter(r => r.result === 'pass');
// const successPercent = Math.floor(
// success.length/results.length * 100
// );
return testrunner(this, options)
.then(results => {
const success = results.filter(r => r.status === 'ok');
const successPercent = Math.floor(
success.length/results.length * 100
);
// if((successPercent !== 100) && typeof process !== 'undefined')
// process.exitCode = 1;
if((successPercent !== 100) && typeof process !== 'undefined')
process.exitCode = 1;
// return results;
// })
// .then(results => {
// if (options.exit && typeof process !== 'undefined')
// process.exit();
// return results;
// });
return results;
});
}
}

0
src/lib/unit/caller.js → src/lib/caller.js

1
src/lib/expect.js

@ -25,6 +25,7 @@ const expectPromise = (pred, statement, options = {}) =>
const library = require('./assertionsLibrary');
const expects = Object.keys(library).reduce((acc, e) => {
const [ pred, statement, options ] = library[e];
acc[e] = expectPromise(

150
src/lib/runTests.js

@ -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;

21
src/lib/snipStack.js

@ -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;

124
src/lib/testrunner.js

@ -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…
Cancel
Save