diff --git a/package.json b/package.json index 51f4778..2eb6e85 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@klenty/gunner", - "version": "0.9.4", + "version": "0.9.6", "description": "Zero magic, fast test-runner and assertion framework. No magic globals.", "main": "index.js", "repository": { @@ -23,7 +23,8 @@ "dependencies": { "@codefeathers/iseq": "^1.2.1", "@codefeathers/promise.object": "^0.9.5", - "json-stringify-safe": "^5.0.1" + "json-stringify-safe": "^5.0.1", + "tap-xunit": "^2.3.0" }, "devDependencies": { "eslint": "^5.2.0" diff --git a/sample/sample7.test.js b/sample/sample7.test.js index 091e1ff..ba934de 100644 --- a/sample/sample7.test.js +++ b/sample/sample7.test.js @@ -9,10 +9,10 @@ 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!')); +// 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.before('*', () => console.log(`Running test ${runCount++}`)); gunner.test('should automatically pass', () => expect().done()); gunner.test(`should be equal`, () => expect(1).equal(1)); @@ -37,17 +37,17 @@ gunner.test('wait and resolve', () => { 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.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.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; @@ -78,10 +78,10 @@ gunner.test('(should fail) multiple expect', () => { a.b = 1; a.c = 2; - return expectMany([ + return expectMany( expect(a).hasProp('b'), expect(a).hasPair('c', 3), - ]); + ); }); @@ -97,6 +97,6 @@ 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; +const reporter = process.argv.slice(2).indexOf('--log') !== -1; -gunner.run({ trace, log }); +gunner.run({ trace, reporter }); diff --git a/shrinkwrap.yaml b/shrinkwrap.yaml index 44fa457..21b534e 100644 --- a/shrinkwrap.yaml +++ b/shrinkwrap.yaml @@ -2,6 +2,7 @@ dependencies: '@codefeathers/iseq': 1.2.1 '@codefeathers/promise.object': 0.9.5 json-stringify-safe: 5.0.1 + tap-xunit: 2.3.0 devDependencies: eslint: 5.2.0 packages: @@ -79,7 +80,6 @@ packages: /argparse/1.0.10: dependencies: sprintf-js: 1.0.3 - dev: true resolution: integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== /array-union/1.0.2: @@ -191,6 +191,10 @@ packages: dev: true resolution: integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + /core-util-is/1.0.2: + dev: false + resolution: + integrity: sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= /cross-spawn/6.0.5: dependencies: nice-try: 1.0.4 @@ -244,6 +248,11 @@ packages: node: '>=0.10.0' resolution: integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + /duplexer/0.1.1: + dev: false + resolution: + integrity: sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= + tarball: 'http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz' /es-abstract/1.12.0: dependencies: es-to-primitive: 1.1.1 @@ -350,7 +359,6 @@ packages: resolution: integrity: sha512-kapdTCt1bjmspxStVKX6huolXVV5ZfyZguY1lcfhVVZstce3bqxH9mcLzNn3/mlgW6wQ732+0fuG9v7h0ZQoKg== /esprima/4.0.1: - dev: true engines: node: '>=4' hasBin: true @@ -384,6 +392,10 @@ packages: node: '>=0.10.0' resolution: integrity: sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + /events-to-array/1.1.2: + dev: false + resolution: + integrity: sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y= /external-editor/2.2.0: dependencies: chardet: 0.4.2 @@ -542,7 +554,6 @@ packages: resolution: integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= /inherits/2.0.3: - dev: true resolution: integrity: sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= /inquirer/5.2.0: @@ -627,6 +638,10 @@ packages: node: '>= 0.4' resolution: integrity: sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI= + /isarray/1.0.0: + dev: false + resolution: + integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= /isexe/2.0.0: dev: true resolution: @@ -639,7 +654,6 @@ packages: dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: true hasBin: true resolution: integrity: sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A== @@ -668,6 +682,10 @@ packages: dev: true resolution: integrity: sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== + /lodash/4.17.11: + dev: false + resolution: + integrity: sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== /mimic-fn/1.2.0: dev: true engines: @@ -684,6 +702,11 @@ packages: dev: true resolution: integrity: sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + /minimist/1.2.0: + dev: false + resolution: + integrity: sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + tarball: 'http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz' /mkdirp/0.5.1: dependencies: minimist: 0.0.8 @@ -800,6 +823,10 @@ packages: node: '>= 0.8.0' resolution: integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + /process-nextick-args/2.0.0: + dev: false + resolution: + integrity: sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== /progress/2.0.0: dev: true engines: @@ -812,6 +839,19 @@ packages: node: '>=6' resolution: integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + /readable-stream/2.3.6: + dependencies: + core-util-is: 1.0.2 + inherits: 2.0.3 + isarray: 1.0.0 + process-nextick-args: 2.0.0 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: false + resolution: + integrity: sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + tarball: 'http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz' /regexp.prototype.flags/1.2.0: dependencies: define-properties: 1.1.2 @@ -873,6 +913,10 @@ packages: npm: '>=2.0.0' resolution: integrity: sha512-3bjO7UwWfA2CV7lmwYMBzj4fQ6Cq+ftHc2MvUe+WMS7wcdJ1LosDWmdjPQanYp2dBRj572p7PeU81JUxHKOcBA== + /safe-buffer/5.1.2: + dev: false + resolution: + integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== /safer-buffer/2.1.2: dev: true resolution: @@ -909,7 +953,6 @@ packages: resolution: integrity: sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== /sprintf-js/1.0.3: - dev: true resolution: integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= /string-width/2.1.1: @@ -931,6 +974,12 @@ packages: dev: true resolution: integrity: sha512-WoZ+B2ypng1dp4iFLF2kmZlwwlE19gmjgKuhL1FJfDgCREWb3ye3SDVHSzLH6bxfnvYmkCxbzkmWcQZHA4P//Q== + /string_decoder/1.1.1: + dependencies: + safe-buffer: 5.1.2 + dev: false + resolution: + integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== /strip-ansi/3.0.1: dependencies: ansi-regex: 2.1.1 @@ -986,6 +1035,29 @@ packages: node: '>=4.0.0' resolution: integrity: sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg== + /tap-parser/1.2.2: + dependencies: + events-to-array: 1.1.2 + inherits: 2.0.3 + js-yaml: 3.12.0 + dev: false + hasBin: true + optionalDependencies: + readable-stream: 2.3.6 + resolution: + integrity: sha1-Xi9pcGEfB5x8+FfeHceqG0gN56U= + /tap-xunit/2.3.0: + dependencies: + duplexer: 0.1.1 + minimist: 1.2.0 + tap-parser: 1.2.2 + through2: 2.0.3 + xmlbuilder: 4.2.1 + xtend: 4.0.1 + dev: false + hasBin: true + resolution: + integrity: sha512-YVsURNvn1wfVUWb5wjansxhfbfeo2hOBTUbVgZoaMO8lyZzpiSi9IiZTZ7JG56m6A49LeWjfJIx/SnAre41V/A== /text-table/0.2.0: dev: true resolution: @@ -994,6 +1066,13 @@ packages: dev: true resolution: integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + /through2/2.0.3: + dependencies: + readable-stream: 2.3.6 + xtend: 4.0.1 + dev: false + resolution: + integrity: sha1-AARWmzfHx0ujnEPzzteNGtlBQL4= /tmp/0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -1016,6 +1095,10 @@ packages: dev: true resolution: integrity: sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + /util-deprecate/1.0.2: + dev: false + resolution: + integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= /which/1.3.1: dependencies: isexe: 2.0.0 @@ -1039,6 +1122,20 @@ packages: node: '>=0.10.0' resolution: integrity: sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c= + /xmlbuilder/4.2.1: + dependencies: + lodash: 4.17.11 + dev: false + engines: + node: '>=0.8.0' + resolution: + integrity: sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU= + /xtend/4.0.1: + dev: false + engines: + node: '>=0.4' + resolution: + integrity: sha1-pcbVMr5lbiPbgg77lDofBJmNY68= registry: 'https://registry.npmjs.org/' shrinkwrapMinorVersion: 9 shrinkwrapVersion: 3 @@ -1047,3 +1144,4 @@ specifiers: '@codefeathers/promise.object': ^0.9.5 eslint: ^5.2.0 json-stringify-safe: ^5.0.1 + tap-xunit: ^2.3.0 diff --git a/src/gunner.js b/src/gunner.js index 59f7d13..d8bd263 100644 --- a/src/gunner.js +++ b/src/gunner.js @@ -4,7 +4,7 @@ const { arrayOrPush } = require('./util'); const caller = require('./lib/caller'); const emitter = require('./lib/emitter'); -const reporter = require('./reporters/default'); +const reporters = require('./reporters'); const testrunner = require('./lib/testrunner'); const expect = require('./lib/expect'); @@ -69,7 +69,13 @@ class Gunner { } run (options = {}) { - (options.reporter || reporter)(emitter, options); + + if (options.reporter === true) + reporters.default(emitter, options); + else if (typeof options.reporter === 'function') + options.reporter(emitter, options); + else if (reporters[options.reporter]) + reporters[options.reporter](emitter, options); emitter.emit('start'); return testrunner(this, options) diff --git a/src/reporters/default.js b/src/reporters/default.js index 07f5667..8e0a400 100644 --- a/src/reporters/default.js +++ b/src/reporters/default.js @@ -6,13 +6,13 @@ const statusMap = { }; -function Default (runner, options) { +const Default = (runner, options) => { runner.on('start', () => console.log('Started tests')); runner.on('test end', results => { - results.map(x => { + results.forEach(x => { const s = statusMap[x.status]; @@ -37,6 +37,6 @@ function Default (runner, options) { }); -} +}; module.exports = Default; diff --git a/src/reporters/index.js b/src/reporters/index.js new file mode 100644 index 0000000..6e1bdd4 --- /dev/null +++ b/src/reporters/index.js @@ -0,0 +1,7 @@ +module.exports = { + + default: require('./default'), + tap: require('./tap'), + xunit: require('./xunit'), + +}; diff --git a/src/reporters/tap.js b/src/reporters/tap.js new file mode 100644 index 0000000..4df903d --- /dev/null +++ b/src/reporters/tap.js @@ -0,0 +1,35 @@ +const statusMap = { + + 'ok': 'ok', + 'notOk': 'not ok', + 'skip': 'skip', + +}; + +const convert = (results, options) => ` +TAP version 13 +${results.length ? '1' : 0}..${results.length} +${ + results.map((r, i) => { + + const status = statusMap[r.status]; + const message = options.trace + && r.reason + && (r.reason.stack ? r.reason.stack : r.reason) + || ''; + return (`${status} ${i + 1} - ${r.description}` + + (message + && ('\n ---\n message: |\n ' + message + '\n ---\n'))); + }).join('\n') +} +`; + +const TAP = (runner, options) => { + + runner.on('end', + results => console.log(convert(results, options))); + +}; + +module.exports = TAP; +module.exports.convert = convert; diff --git a/src/reporters/xunit.js b/src/reporters/xunit.js new file mode 100644 index 0000000..d57328e --- /dev/null +++ b/src/reporters/xunit.js @@ -0,0 +1,22 @@ +const Readable = require('stream').Readable; +const TAP = require('./tap'); +const xUnitConverter = require('tap-xunit'); + +const streamify = text => { + const s = new Readable(); + s._read = () => {}; + s.push(text); + s.push(null); + return s; +}; + +const xunit = (runner) => { + + runner.on('end', results => + streamify(TAP.convert(results, { trace: false })) + .pipe(xUnitConverter()) + .pipe(process.stdout)); + +}; + +module.exports = xunit;