Browse Source

[refactor] Up to 0.3.1

0.7.0-breaking-rewrite
Muthu Kumar 6 years ago
parent
commit
c2d5bf19b7
  1. 14
      .vscode/launch.json
  2. 6
      gunner/lib/constants.js
  3. 67
      gunner/lib/runTests.js
  4. 2
      index.js
  5. 4
      package.json
  6. 34
      sample.test.js
  7. 8
      shrinkwrap.yaml
  8. 19
      src/gunner.js
  9. 0
      src/lib/assertPromise.js
  10. 3
      src/lib/expect.js
  11. 74
      src/lib/runTests.js
  12. 9
      src/util/index.js
  13. 9
      src/util/symbols.js

14
.vscode/launch.json

@ -0,0 +1,14 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/sample.test.js"
}
]
}

6
gunner/lib/constants.js

@ -1,6 +0,0 @@
const constants = {
pass: 'pass',
fail: 'fail',
};
module.exports = constants;

67
gunner/lib/runTests.js

@ -1,67 +0,0 @@
'use strict';
const { isPromise } = require('../../util/helpers');
const { pass, fail } = require('./constants');
const runTests = instance => {
const beforeAll = () => Promise.map(
instance.__hooks__.before['@start'],
hook => hook.run(),
);
const beforeEvery = () => Promise.mapSeries(
instance.__hooks__.before['*'] || [],
hook => hook.run(),
);
const runner = () => Promise.mapSeries(instance.__tests__, each => {
const beforeThis = () => Promise.mapSeries(
instance.__hooks__.before[each.description] || [],
hook => hook.run(),
);
const afterThis = () => Promise.mapSeries(
instance.__hooks__.after[each.description] || [],
hook => hook.run(),
);
return beforeEvery().then(() => beforeThis()).then(() => {
const pred = each.test();
/* 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 toTest
.then(() => ({ description: each.description, result: pass }))
.catch(e => ({ description: each.description, result: fail, error: e }));
})
.then(result => afterThis().then(() => result));
});
const afterAll = () => Promise.mapSeries(
instance.__hooks__.before['@end'],
hook => hook.run(),
);
return beforeAll()
.then(() => runner())
.then(results => afterAll().then(() => results));
};
module.exports = runTests;

2
index.js

@ -1 +1 @@
module.exports = require('./gunner');
module.exports = require('./src/gunner');

4
package.json

@ -1,6 +1,6 @@
{
"name": "@klenty/gunner",
"version": "0.3.0",
"version": "0.3.1",
"description": "Zero magic, fast test-runner and assertion framework. No magic globals.",
"main": "index.js",
"repository": {
@ -22,7 +22,9 @@
"homepage": "https://github.com/klenty/gunner#readme",
"dependencies": {
"@codefeathers/iseq": "^1.2.1",
"@codefeathers/promise.object": "^0.9.5",
"bluebird": "^3.5.1",
"chalk": "^2.4.1",
"eslint": "^5.2.0",
"json-stringify-safe": "^5.0.1"
}

34
sample.test.js

@ -1,7 +1,17 @@
const Gunner = require('./gunner');
/**
* 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 }));
@ -16,6 +26,16 @@ gunner.test('should be a Promise (rejected)', expect =>
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('./hello.txt', { encoding: 'utf8' });
@ -25,6 +45,12 @@ gunner.test('file must have hello as content', async expect => {
];
});
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 =>
@ -52,7 +78,9 @@ gunner.test('(should fail) should catch error', expect => {
});
gunner.test('(should fail) should not resolve to 5', expect =>
expect(Promise.resolve({})).resolvesTo(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: true});
gunner.run({ trace, log });

8
shrinkwrap.yaml

@ -1,6 +1,8 @@
dependencies:
'@codefeathers/iseq': 1.2.1
'@codefeathers/promise.object': 0.9.5
bluebird: 3.5.1
chalk: 2.4.1
eslint: 5.2.0
json-stringify-safe: 5.0.1
packages:
@ -8,6 +10,10 @@ packages:
dev: false
resolution:
integrity: sha1-zUHiKGdKZQlWBfKVacbdVtlodsw=
/@codefeathers/promise.object/0.9.5:
dev: false
resolution:
integrity: sha1-YBDLXpC4vhz12WrDHJKr/F8K/zA=
/acorn-jsx/4.1.1:
dependencies:
acorn: 5.7.1
@ -1043,6 +1049,8 @@ shrinkwrapMinorVersion: 8
shrinkwrapVersion: 3
specifiers:
'@codefeathers/iseq': ^1.2.1
'@codefeathers/promise.object': ^0.9.5
bluebird: ^3.5.1
chalk: ^2.4.1
eslint: ^5.2.0
json-stringify-safe: ^5.0.1

19
gunner/index.js → src/gunner.js

@ -1,21 +1,24 @@
'use strict';
const { log } = console;
const chalk = require('chalk');
Promise = require('bluebird');
Promise.object = require('@codefeathers/promise.object');
const _runTests = require('./lib/runTests');
const _expect = require('./lib/expect');
const { stringify, hasProp } = require('../util/helpers');
const { stringify, hasProp } = require('./util');
const symbols = require('./util/symbols');
class Gunner {
constructor (options = {}) {
this.__hooks__ = {
before: {
'@start': [],
'@end': [],
[symbols.Start]: [],
[symbols.Stop]: [],
'*': [],
},
after: {
@ -37,9 +40,9 @@ class Gunner {
this.__tests__.push({
description,
test: () => {
test: (state) => {
try {
return test(_expect);
return test(_expect, state);
} catch (e) {
// If errors are thrown, reject them
return Promise.reject(e);
@ -85,7 +88,7 @@ class Gunner {
results.passing = success.length;
const successPercent = Math.floor(success.length/results.length * 100);
log(
`\n${success.length} tests passed of ${results.length}`,
chalk`\n{green ${success.length}} tests passed of ${results.length}`,
`[${successPercent}% success]\n`
);
results.forEach(r => {
@ -93,7 +96,7 @@ class Gunner {
? `\n Traceback:\n ${stringify(r.error)}`
: '';
log(`${r.result === 'pass' ? '✅' : '❌'} ::`,
log(`${r.result === 'pass' ? chalk`{green ✅}` : chalk`{red ❌}`} ::`,
`${r.description}`,
`${trace}`);
});
@ -115,3 +118,5 @@ class Gunner {
module.exports = Gunner;
module.exports.expect = _expect;
module.exports.Start = symbols.Start;
module.exports.End = symbols.End;

0
gunner/lib/assertPromise.js → src/lib/assertPromise.js

3
gunner/lib/expect.js → src/lib/expect.js

@ -1,9 +1,8 @@
const isEq = require('@codefeathers/iseq');
const { liftPromise, stringify, isPromise } = require('../../util/helpers');
const { liftPromise, stringify, isPromise } = require('../util');
const _assertPromise = require('./assertPromise');
const expectPromise = (pred, statement, options = {}) =>
toTest =>
(...testValues) =>

74
src/lib/runTests.js

@ -0,0 +1,74 @@
'use strict';
const { isPromise } = require('../util');
const constants = require('../util/symbols');
const runTests = instance => {
const beforeAll = () => Promise.map(
instance.__hooks__.before[constants.Start] || [],
hook => hook.run(),
);
const beforeEvery = state => Promise.mapSeries(
instance.__hooks__.before['*'] || [],
hook => hook.run(state),
);
const runner = state => Promise.mapSeries(instance.__tests__, each => {
const beforeThis = state => Promise.mapSeries(
instance.__hooks__.before[each.description] || [],
hook => hook.run(state),
);
const afterThis = state => Promise.mapSeries(
instance.__hooks__.after[each.description] || [],
hook => hook.run(state),
);
return beforeEvery(state)
.then(newState => ({ ...state, '@every': newState }))
.then(state => Promise.object({ ...state, '@this': beforeThis() }))
.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(() => ({ description: each.description, result: constants.pass }))
.catch(e => ({ description: each.description, result: constants.fail, error: e })),
];
})
.spread((state, result) => afterThis(state).then(() => result));
});
const afterAll = state => Promise.mapSeries(
instance.__hooks__.before[constants.End] || [],
hook => hook.run(state, state['@results']),
);
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;

9
util/helpers.js → src/util/index.js

@ -1,9 +1,12 @@
const stringify = require('json-stringify-safe');
/* Returns true if a promise is passed */
const isPromise = prom => prom && (typeof prom.then === 'function');
module.exports = {
/* Returns true if a promise is passed */
isPromise : prom => prom && (typeof prom.then === 'function'),
isPromise,
/* Flattens an array of arrays to an array */
flatten : arrData => [].concat.apply([], arrData),
@ -26,7 +29,7 @@ module.exports = {
/* Pipe a value or promise through any number of unary functions */
pipe: (...fns) =>
arg => fns.reduce((acc, fn) =>
typeof acc.then === 'function'
isPromise(acc)
? acc.then(fn)
: fn(acc), arg),
@ -43,7 +46,7 @@ module.exports = {
/* Lift promises into a function */
liftPromise : (fn, thing) =>
typeof thing.then === 'function'
isPromise(thing)
? thing.then(fn)
: fn(thing),

9
src/util/symbols.js

@ -0,0 +1,9 @@
module.exports = {
Start : Symbol('Start'),
End : Symbol('End'),
pass: 'pass',
fail: 'fail',
};
Loading…
Cancel
Save