Browse Source

[feature] Added support for before and after hooks

0.7.0-breaking-rewrite
Muthu Kumar 6 years ago
parent
commit
f81adb1554
  1. 1
      .eslintrc.js
  2. 56
      gunner/index.js
  3. 72
      gunner/lib/runTests.js
  4. 53
      package.json
  5. 3836
      shrinkwrap.yaml
  6. 4
      util/helpers.js

1
.eslintrc.js

@ -25,5 +25,6 @@ module.exports = {
"linebreak-style": [ "error", "unix" ],
"semi": [ "error", "always" ],
"eqeqeq": [ "error", "always", {"null": "ignore"} ],
"no-global-assign": 0,
}
};

56
gunner/index.js

@ -1,5 +1,9 @@
'use strict';
const { log } = console;
Promise = require('bluebird');
const _runTests = require('./lib/runTests');
const _expect = require('./lib/expect');
@ -8,12 +12,30 @@ const { stringify, hasProp } = require('../util/helpers');
class Gunner {
constructor (options = {}) {
this.tests = [];
this.__hooks__ = {
before: {
'@start': [],
'@end': [],
'*': [],
},
after: {
'*': [],
},
};
this.__state__ = [];
this.__tests__ = [];
this.name = options.name;
}
test (description, test) {
this.tests.push({
const existing = (
this.__tests__
.find(x => x.description === description)
);
if (existing)
throw new Error(`Test '${description}' already exists!`);
this.__tests__.push({
description,
test: () => {
try {
@ -24,11 +46,39 @@ class Gunner {
}
},
});
return this;
}
before (description, run) {
const hook = {
description,
run,
};
this.__hooks__.before[description]
? this.__hooks__.before[description].push(hook)
: this.__hooks__.before[description] = [ hook ];
return this;
}
after (description, run) {
const hook = {
description,
run,
};
this.__hooks__.after[description]
? this.__hooks__.after[description].push(hook)
: this.__hooks__.after[description] = [ hook ];
return this;
}
run (options = {}) {
const shouldLog = (hasProp(options)('log') && options.log) || !(hasProp(options)('log'));
return _runTests(this.tests)
return _runTests(this)
.then(results => {
if (shouldLog) {
const success = results.filter(r => r.result === 'pass');

72
gunner/lib/runTests.js

@ -3,27 +3,65 @@
const { isPromise } = require('../../util/helpers');
const { pass, fail } = require('./constants');
const runTests = tests => Promise.all(tests.map(each => {
const runTests = instance => {
const pred = each.test();
const beforeAll = () => Promise.map(
instance.__hooks__.before['@start'],
hook => hook.run(),
);
/* 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 */
const beforeEvery = () => Promise.mapSeries(
instance.__hooks__.before['*'] || [],
hook => hook.run(),
);
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);
const runner = () => Promise.mapSeries(instance.__tests__, each => {
return toTest
.then(() => ({ description: each.description, result: pass }))
.catch(e => ({ description: each.description, result: fail, error: e }));
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;

53
package.json

@ -1,28 +1,29 @@
{
"name": "@klenty/gunner",
"version": "0.2.5",
"description": "Zero magic, fast test-runner and assertion framework. No magic globals.",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/vengatkrishnaraj/gunner.git"
},
"keywords": [
"klenty",
"gunner",
"test",
"tdd",
"unit testing"
],
"author": "Muthu Kumar <@MKRhere> (https://mkr.pw)",
"license": "MIT",
"bugs": {
"url": "https://github.com/vengatkrishnaraj/testsuite/issues"
},
"homepage": "https://github.com/vengatkrishnaraj/testsuite#readme",
"dependencies": {
"@codefeathers/iseq": "^1.2.1",
"eslint": "^5.2.0",
"fs-extra": "^7.0.0"
}
"name": "@klenty/gunner",
"version": "0.3.0",
"description": "Zero magic, fast test-runner and assertion framework. No magic globals.",
"main": "index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/klenty/gunner.git"
},
"keywords": [
"klenty",
"gunner",
"test",
"tdd",
"unit testing"
],
"author": "Muthu Kumar <@MKRhere> (https://mkr.pw)",
"license": "MIT",
"bugs": {
"url": "https://github.com/klenty/gunner/issues"
},
"homepage": "https://github.com/klenty/gunner#readme",
"dependencies": {
"@codefeathers/iseq": "^1.2.1",
"bluebird": "^3.5.1",
"eslint": "^5.2.0",
"json-stringify-safe": "^5.0.1"
}
}

3836
shrinkwrap.yaml

File diff suppressed because it is too large

4
util/helpers.js

@ -1,3 +1,5 @@
const stringify = require('json-stringify-safe');
module.exports = {
/* Returns true if a promise is passed */
@ -48,7 +50,7 @@ module.exports = {
/* Stringifies object or coerces to string */
stringify : obj =>
typeof obj === 'object'
? (obj.stack || JSON.stringify(obj))
? (obj.stack || stringify(obj))
: obj,
/* Short circuits with given value on pred. Else calls function */

Loading…
Cancel
Save