lab
Version:
Test utility
1,360 lines (1,016 loc) • 66.1 kB
JavaScript
// Load modules
var Crypto = require('crypto');
var Fs = require('fs');
var Os = require('os');
var Path = require('path');
var Stream = require('stream');
var Tty = require('tty');
var Code = require('code');
var Hoek = require('hoek');
var _Lab = require('../test_runner');
var Lab = require('../');
var Reporters = require('../lib/reporters');
// Declare internals
var internals = {};
// Test shortcuts
var lab = exports.lab = _Lab.script();
var describe = lab.describe;
var it = lab.it;
var expect = Code.expect;
describe('Reporter', function () {
Lab.coverage.instrument({ coveragePath: Path.join(__dirname, './coverage/'), coverageExclude: 'exclude' });
it('outputs to a stream', function (done) {
var Recorder = function () {
Stream.Writable.call(this);
this.content = '';
};
Hoek.inherits(Recorder, Stream.Writable);
Recorder.prototype._write = function (chunk, encoding, next) {
this.content += chunk.toString();
next();
};
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
finished();
});
});
var recorder = new Recorder();
Lab.report(script, { output: recorder }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(0);
expect(output).to.equal(recorder.content);
done();
});
});
it('outputs to a file', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
finished();
});
});
var filename = Path.join(Os.tmpDir(), [Date.now(), process.pid, Crypto.randomBytes(8).toString('hex')].join('-'));
Lab.report(script, { output: filename }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(0);
expect(output).to.equal(Fs.readFileSync(filename).toString());
Fs.unlinkSync(filename);
done();
});
});
it('outputs to a file in a directory', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
finished();
});
});
var randomname = [Date.now(), process.pid, Crypto.randomBytes(8).toString('hex')].join('-');
var folder = Path.join(Os.tmpDir(), randomname);
var filename = Path.join(folder, randomname);
Lab.report(script, { output: filename }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(0);
expect(output).to.equal(Fs.readFileSync(filename).toString());
Fs.unlinkSync(filename);
Fs.rmdirSync(folder);
done();
});
});
it('exits with error code when leak detected', function (done) {
var reporter = Reporters.generate({ reporter: 'console' });
var notebook = {
tests: [],
coverage: {
percent: 30,
files: []
},
leaks: ['something']
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(code).to.equal(1);
done();
});
});
it('exits with error code when coverage threshold is not met', function (done) {
var reporter = Reporters.generate({ reporter: 'console', coverage: true, threshold: 50 });
var notebook = {
tests: [],
coverage: {
percent: 30,
files: []
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(code).to.equal(1);
done();
});
});
it('exits with success code when coverage threshold is met', function (done) {
var reporter = Reporters.generate({ reporter: 'console', coverage: true, threshold: 50 });
var notebook = {
tests: [],
coverage: {
percent: 60,
files: []
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(code).to.equal(0);
done();
});
});
it('exits with error code when linting error threshold is met', function (done) {
var reporter = Reporters.generate({ reporter: 'console', lint: true, 'lint-errors-threshold': 5 });
var notebook = {
tests: [],
lint: {
lint: [
{ errors: [{ severity: 'WARNING' }, { severity: 'ERROR' }] },
{ errors: [{ severity: 'ERROR' }, { severity: 'ERROR' }] },
{ errors: [{ severity: 'WARNING' }, { severity: 'ERROR' }] },
{ errors: [{ severity: 'WARNING' }, { severity: 'ERROR' }] }
]
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(code).to.equal(1);
done();
});
});
it('exits with error code when linting error threshold is met and threshold is 0', function (done) {
var reporter = Reporters.generate({ reporter: 'console', lint: true, 'lint-errors-threshold': 0 });
var notebook = {
tests: [],
lint: {
lint: [
{ errors: [{ severity: 'WARNING' }, { severity: 'ERROR' }] }
]
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(code).to.equal(1);
done();
});
});
it('exits with success code when linting error threshold is not met', function (done) {
var reporter = Reporters.generate({ reporter: 'console', lint: true, 'lint-errors-threshold': 5 });
var notebook = {
tests: [],
lint: {
lint: [
{ errors: [{ severity: 'WARNING' }, { severity: 'ERROR' }] },
{ errors: [{ severity: 'ERROR' }, { severity: 'ERROR' }] },
{ errors: [{ severity: 'WARNING' }, { severity: 'ERROR' }] }
]
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(code).to.equal(0);
done();
});
});
it('exits with error code when linting warning threshold is met', function (done) {
var reporter = Reporters.generate({ reporter: 'console', lint: true, 'lint-warnings-threshold': 5 });
var notebook = {
tests: [],
lint: {
lint: [
{ errors: [{ severity: 'ERROR' }, { severity: 'WARNING' }] },
{ errors: [{ severity: 'WARNING' }, { severity: 'WARNING' }] },
{ errors: [{ severity: 'ERROR' }, { severity: 'WARNING' }] },
{ errors: [{ severity: 'ERROR' }, { severity: 'WARNING' }] }
]
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(code).to.equal(1);
done();
});
});
it('exits with error code when linting warning threshold is met and threshold is 0', function (done) {
var reporter = Reporters.generate({ reporter: 'console', lint: true, 'lint-warnings-threshold': 0 });
var notebook = {
tests: [],
lint: {
lint: [
{ errors: [{ severity: 'WARNING' }, { severity: 'ERROR' }] }
]
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(code).to.equal(1);
done();
});
});
it('exits with success code when linting warning threshold is not met', function (done) {
var reporter = Reporters.generate({ reporter: 'console', lint: true, 'lint-warnings-threshold': 5 });
var notebook = {
tests: [],
lint: {
lint: [
{ errors: [{ severity: 'ERROR' }, { severity: 'WARNING' }] },
{ errors: [{ severity: 'WARNING' }, { severity: 'WARNING' }] },
{ errors: [{ severity: 'ERROR' }, { severity: 'WARNING' }] }
]
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(code).to.equal(0);
done();
});
});
describe('console', function () {
it('generates a report', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
expect(true).to.equal(true);
finished();
});
});
Lab.report(script, { reporter: 'console' }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(0);
expect(output).to.contain('1 tests complete');
expect(output).to.contain('Test duration:');
expect(output).to.contain('No global variable leaks detected');
done();
});
});
it('generates a report with errors', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
expect(true).to.equal(false);
finished();
});
});
global.x1 = true;
Lab.report(script, { reporter: 'console', colors: false }, function (err, code, output) {
delete global.x1;
expect(err).to.not.exist();
expect(code).to.equal(1);
var result = output.replace(/at.*\.js\:\d+\:\d+\)?/g, 'at <trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test works:\n\n actual expected\n\n truefalse\n\n Expected true to equal specified value\n\n(?: at <trace>\n)+\n\n1 of 1 tests failed\nTest duration: \d+ ms\nThe following leaks were detected:x1\n\n$/);
done();
});
});
it('generates a report with multi-line diff', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
expect(['a', 'b']).to.deep.equal(['a', 'c']);
finished();
});
});
global.x1 = true;
Lab.report(script, { reporter: 'console', colors: false }, function (err, code, output) {
delete global.x1;
expect(err).to.not.exist();
expect(code).to.equal(1);
var result = output.replace(/at.*\.js\:\d+\:\d+\)?/g, 'at <trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test works:\n\n actual expected\n\n \[\n \"a\",\n \"bc\"\n \]\n\n Expected \[ 'a', 'b' \] to equal specified value\n\n(?: at <trace>\n)+\n\n1 of 1 tests failed\nTest duration: \d+ ms\nThe following leaks were detected:x1\n\n$/);
done();
});
});
it('generates a report with caught error', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
expect(function () {
throw new Error('boom');
}).to.not.throw();
finished();
});
});
Lab.report(script, { reporter: 'console', colors: false, leaks: false }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
var result = output.replace(/at.*\.js\:\d+\:\d+\)?/g, 'at <trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test works:\n\n Expected \[Function\] to not throw an error but got \[Error: boom\]\n\n(?: at <trace>\n)+\n\n1 of 1 tests failed\nTest duration: \d+ ms\n\n$/);
done();
});
});
it('generates a report with caught error (data plain)', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
var error = new Error('boom');
error.data = 'abc';
throw error;
});
});
Lab.report(script, { reporter: 'console', colors: false, leaks: false }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
var result = output.replace(/at.*\.js\:\d+\:\d+\)?/g, 'at <trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test works:\n\n boom\n\n at <trace>\n at <trace>\n at <trace>\n\n Additional error data:\n "abc"\n\n\n1 of 1 tests failed\nTest duration: \d+ ms\n\n$/);
done();
});
});
it('generates a report with caught error (data array)', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
var error = new Error('boom');
error.data = [1, 2, 3];
throw error;
});
});
Lab.report(script, { reporter: 'console', colors: false, leaks: false }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
var result = output.replace(/at.*\.js\:\d+\:\d+\)?/g, 'at <trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test works:\n\n boom\n\n at <trace>\n at <trace>\n at <trace>\n\n Additional error data:\n \[1,2,3\]\n\n\n1 of 1 tests failed\nTest duration: \d+ ms\n\n$/);
done();
});
});
it('generates a report with caught error (data object)', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
var error = new Error('boom');
error.data = { a: 1 };
throw error;
});
});
Lab.report(script, { reporter: 'console', colors: false, leaks: false }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
var result = output.replace(/at.*\.js\:\d+\:\d+\)?/g, 'at <trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test works:\n\n boom\n\n at <trace>\n at <trace>\n at <trace>\n\n Additional error data:\n a: 1\n\n\n1 of 1 tests failed\nTest duration: \d+ ms\n\n$/);
done();
});
});
it('generates a report with plain Error', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('fails', function (finished) {
throw new Error('Error Message');
});
});
Lab.report(script, { reporter: 'console', colors: false }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
var result = output.replace(/at.*\.js\:\d+\:\d+\)?/g, 'at <trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test fails:\n\n Error Message\n\n(?: at <trace>\n)+(?: at <trace>\n)+(?: at <trace>\n)+\n\n1 of 1 tests failed\nTest duration: \d+ ms\nNo global variable leaks detected\n\n$/);
done();
});
});
describe('timeouts', function () {
it('generates a report with timeout', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) { });
});
Lab.report(script, { reporter: 'console', colors: false, timeout: 1 }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
var result = output.replace(/\/[\/\w]+\.js\:\d+\:\d+/g, '<trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test works:\n\n Timed out \(\d+ms\) - test works\n\n\n\n1 of 1 tests failed\nTest duration: \d+ ms\nNo global variable leaks detected\n\n$/);
done();
});
});
var tests = [
{
type: 'before',
expect: 'Timed out (1ms) - Before test'
},
{
type: 'after',
expect: 'Timed out (1ms) - After test'
},
{
type: 'beforeEach',
expect: 'Timed out (1ms) - Before each test'
},
{
type: 'afterEach',
expect: 'Timed out (1ms) - After each test'
}
];
tests.forEach(function (test) {
it('generates a report with timeout on ' + test.type, function (done) {
var script = Lab.script();
script.experiment('test', function () {
script[test.type](function (finished) { });
script.test('works', function (finished) {
finished();
});
});
Lab.report(script, { reporter: 'console', colors: false, 'context-timeout': 1 }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
expect(output).to.contain(test.expect);
done();
});
});
it('doesn\'t generates a report with timeout on ' + test.type, function (done) {
var script = Lab.script();
script.experiment('test', function () {
script[test.type](function (finished) {
setTimeout(finished, 500);
});
script.test('works', function (finished) {
finished();
});
});
Lab.report(script, { reporter: 'console', colors: false, 'context-timeout': 1000 }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(0);
done();
});
});
it('generates a report with inline timeout on ' + test.type, function (done) {
var script = Lab.script();
script.experiment('test', function () {
script[test.type]({ timeout: 1 }, function (finished) { });
script.test('works', function (finished) {
finished();
});
});
Lab.report(script, { reporter: 'console', colors: false }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
expect(output).to.contain(test.expect);
done();
});
});
});
});
it('generates a report without progress', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
finished();
});
});
Lab.report(script, { reporter: 'console', progress: 0 }, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.match(/^\u001b\[32m1 tests complete\u001b\[0m\nTest duration: \d+ ms\n\u001b\[32mNo global variable leaks detected\u001b\[0m\n\n$/);
done();
});
});
it('generates a report with verbose progress', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
finished();
});
});
Lab.report(script, { reporter: 'console', progress: 2 }, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.match(/^test\n \u001b\[32m✔\u001b\[0m \u001b\[90m1\) works \(\d+ ms\)\u001b\[0m\n\n\n\u001b\[32m1 tests complete\u001b\[0m\nTest duration: \d+ ms\n\u001b\[32mNo global variable leaks detected\u001b\[0m\n\n$/);
done();
});
});
it('generates a report with verbose progress that displays well on windows', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
finished();
});
});
var oldPlatform = process.platform;
Object.defineProperty(process, 'platform', { writable: true, value: 'win32' });
Lab.report(script, { reporter: 'console', progress: 2 }, function (err, code, output) {
process.platform = oldPlatform;
expect(err).not.to.exist();
expect(output).to.contain('\u221A');
done();
});
});
it('generates a coverage report (verbose)', function (done) {
var Test = require('./coverage/console');
var Full = require('./coverage/console-full');
var script = Lab.script();
script.experiment('test', function () {
script.test('something', function (finished) {
Test.method(1, 2, 3);
Full.method(1);
finished();
});
script.test('diff', function (finished) {
expect('abcd').to.equal('cdfg');
finished();
});
});
Lab.report(script, { reporter: 'console', coverage: true, coveragePath: Path.join(__dirname, './coverage/console') }, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.contain('Coverage: 78.95% (4/19)');
expect(output).to.contain('test/coverage/console.js missing coverage on line(s): 12, 15, 16, 19');
expect(output).to.not.contain('console-full');
done();
});
});
it('reports 100% coverage', function (done) {
var reporter = Reporters.generate({ reporter: 'console', coverage: true });
var notebook = {
tests: [],
coverage: {
percent: 100,
files: []
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.contain('Coverage: 100.00%');
done();
});
});
it('reports correct lines with sourcemaps enabled', function (done) {
var Test = require('./coverage/sourcemaps-external');
var script = Lab.script();
script.experiment('test', function () {
script.test('something', function (finished) {
Test.method(false);
finished();
});
});
Lab.report(script, { reporter: 'console', coverage: true, coveragePath: Path.join(__dirname, './coverage/sourcemaps-external'), sourcemaps: true }, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.contain('test/coverage/sourcemaps-external.js missing coverage from file(s):');
expect(output).to.contain('test/coverage/while.js on line(s): 11, 12');
done();
});
});
it('doesn\'t report lines on a fully covered file with sourcemaps enabled', function (done) {
var Test = require('./coverage/sourcemaps-covered');
var script = Lab.script();
script.experiment('test', function () {
script.test('something', function (finished) {
Test.method(false);
finished();
});
});
Lab.report(script, { reporter: 'console', coverage: true, coveragePath: Path.join(__dirname, './coverage/'), sourcemaps: true }, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.not.contain('sourcemaps-covered');
done();
});
});
it('generates a report with multi-line progress', function (done) {
var script = Lab.script();
script.experiment('test', function () {
var works = function (finished) {
expect(true).to.equal(true);
finished();
};
var fails = function (finished) {
expect(true).to.equal(false);
finished();
};
var skips = function (finished) {
finished();
};
for (var i = 0; i < 30; ++i) {
script.test('works', works);
script.test('fails', fails);
script.test('skips', { skip: true }, skips);
}
});
Lab.report(script, { reporter: 'console', colors: false }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
expect(output).to.contain('.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-.x\n -.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-.x-');
done();
});
});
it('generates a report with verbose progress', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
finished();
});
script.test('fails', function (finished) {
finished('boom');
});
script.test('skips', { skip: true }, function (finished) {
finished();
});
});
Lab.report(script, { reporter: 'console', colors: false, progress: 2 }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
expect(output).to.match(/test\n ✔ 1\) works \(\d+ ms\)\n ✖2\) fails\n \- 3\) skips \(\d+ ms\)\n/);
done();
});
});
it('excludes colors when terminal does not support', { parallel: false }, function (done) {
var orig = Tty.isatty;
Tty.isatty = function () {
Tty.isatty = orig;
return false;
};
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
expect(true).to.equal(true);
finished();
});
});
Lab.report(script, { reporter: 'console' }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(0);
expect(output).to.match(/^\n \n \.\n\n1 tests complete\nTest duration: \d+ ms\nNo global variable leaks detected\n\n$/);
done();
});
});
it('displays custom error messages in expect', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
expect(true, 'Not working right').to.equal(false);
finished();
});
});
Lab.report(script, { reporter: 'console', colors: false }, function (err, code, output) {
expect(err).not.to.exist();
var result = output.replace(/at.*\.js\:\d+\:\d+\)?/g, 'at <trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test works:\n\n actual expected\n\n truefalse\n\n Not working right: Expected true to equal specified value\n\n(?: at <trace>\n)+\n\n1 of 1 tests failed\nTest duration: \d+ ms\nNo global variable leaks detected\n\n$/);
done();
});
});
it('displays session errors if there in an error in "before"', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.before(function (testDone) {
testDone(new Error('there was an error in the before function'));
});
script.test('works', function (testDone) {
expect(true).to.equal(true);
testDone();
});
});
Lab.report(script, { reporter: 'console', colors: false }, function (err, code, output) {
expect(err).not.to.exist();
var result = output.replace(/\/[\/\w]+\.js\:\d+\:\d+/g, '<trace>');
expect(code).to.equal(1);
expect(result).to.contain('There were 1 test script error(s).');
expect(result).to.contain('there was an error in the before function');
done();
});
});
it('displays session errors if there in an error in "afterEach"', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.afterEach(function (testDone) {
testDone('there was an error in the afterEach function');
});
script.test('works', function (testDone) {
expect(true).to.equal(true);
testDone();
});
});
Lab.report(script, { reporter: 'console', colors: false }, function (err, code, output) {
expect(err).not.to.exist();
var result = output.replace(/\/[\/\w]+\.js\:\d+\:\d+/g, '<trace>');
expect(code).to.equal(1);
expect(result).to.contain('There were 1 test script error(s).');
expect(result).to.contain('there was an error in the afterEach function');
done();
});
});
it('generates a report with linting enabled', function (done) {
var reporter = Reporters.generate({ reporter: 'console', coverage: true });
var notebook = {
tests: [],
lint: {
'lint': [
{
filename: 'test.js',
errors: [
{
severity: 'ERROR',
line: 10,
message: 'missing ;'
}
]
}
]
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.contain('missing ;');
done();
});
});
it('displays a success message for lint when no issues found', function (done) {
var reporter = Reporters.generate({ reporter: 'console', coverage: true });
var notebook = {
tests: [],
lint: {
'lint': [
{
filename: 'test.js',
errors: []
}
]
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.contain('No issues');
done();
});
});
it('displays a success message for lint when errors are null', function (done) {
var reporter = Reporters.generate({ reporter: 'console', coverage: true });
var notebook = {
tests: [],
lint: {
'lint': [
{
filename: 'test.js',
errors: null
}
]
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.contain('No issues');
done();
});
});
it('reports with circular JSON', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
var err = new Error('Fail');
err.actual = {
a: 1
};
err.actual.b = err.actual;
err.expected = {
a: 2
};
err.expected.b = err.expected;
throw err;
});
});
Lab.report(script, { reporter: 'console', colors: false }, function (err, code, output) {
expect(err).not.to.exist();
var result = output.replace(/at.*\.js\:\d+\:\d+\)?/g, 'at <trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test works:\n\n actual expected\n\n {\n "a": 12,\n "b": "\[Circular ~\]"\n }\n\n Fail\n\n(?: at <trace>\n)+\n\n1 of 1 tests failed\nTest duration: \d+ ms\nNo global variable leaks detected\n\n$/);
done();
});
});
it('reports with undefined values', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.test('works', function (finished) {
var err = new Error('Fail');
err.actual = { a: 1 };
err.expected = {
a: 1,
b: undefined,
c: function () {
return 'foo';
},
d: Infinity,
e: -Infinity
};
throw err;
});
});
Lab.report(script, { reporter: 'console', colors: false }, function (err, code, output) {
expect(err).not.to.exist();
var result = output.replace(/at.*\.js\:\d+\:\d+\)?/g, 'at <trace>');
expect(result).to.match(/^\n \n x\n\nFailed tests:\n\n 1\) test works:\n\n actual expected\n\n {\n\s+"a": 1,\n\s+"b": "\[undefined\]",\n\s+"c": "\[function \(\) \{\\n\\n\s+return 'foo';\\n\s+\}\]",\n\s+"d": "\[Infinity\]",\n\s+"e": "\[-Infinity\]"\n\s+}\n\n Fail\n\n(?: at <trace>\n)+\n\n1 of 1 tests failed\nTest duration: \d+ ms\nNo global variable leaks detected\n\n$/);
done();
});
});
});
describe('json', function () {
it('generates a report', function (done) {
var script = Lab.script();
script.experiment('group', function () {
script.test('works', function (finished) {
expect(true).to.equal(true);
finished();
});
script.test('fails', function (finished) {
expect(true).to.equal(false);
finished();
});
script.test('fails with non-error', function (finished) {
finished('boom');
finished('kaboom');
});
});
Lab.report(script, { reporter: 'json', lint: true, linter: 'eslint' }, function (err, code, output) {
var result = JSON.parse(output);
expect(err).to.not.exist();
expect(code).to.equal(1);
expect(result.tests.group.length).to.equal(3);
expect(result.tests.group[0].title).to.equal('works');
expect(result.tests.group[0].err).to.equal(false);
expect(result.tests.group[1].title).to.equal('fails');
expect(result.tests.group[1].err).to.equal('Expected true to equal specified value');
expect(result.tests.group[2].title).to.equal('fails with non-error');
expect(result.tests.group[2].err).to.equal(true);
expect(result.leaks.length).to.equal(0);
expect(result.duration).to.exist();
expect(result.errors).to.have.length(1);
expect(result.lint.length).to.be.greaterThan(1);
expect(result.lint[0].filename).to.exist();
expect(result.lint[0].errors).to.exist();
done();
});
});
it('generates a report with coverage', function (done) {
var Test = require('./coverage/json');
var script = Lab.script({ schedule: false });
script.experiment('test', function () {
script.test('value of a', function (finished) {
expect(Test.method(1)).to.equal(1);
finished();
});
});
Lab.report(script, { reporter: 'json', coverage: true, coveragePath: Path.join(__dirname, './coverage/json') }, function (err, code, output) {
expect(err).not.to.exist();
var result = JSON.parse(output);
expect(result.coverage.percent).to.equal(100);
done();
});
});
});
describe('html', function () {
it('generates a coverage report', function (done) {
var Test = require('./coverage/html');
var script = Lab.script({ schedule: false });
script.experiment('test', function () {
script.test('something', function (finished) {
Test.method(1, 2, 3);
finished();
});
});
Lab.report(script, { reporter: 'html', coverage: true, coveragePath: Path.join(__dirname, './coverage/html') }, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.contain('<div class="stats medium">');
expect(output).to.contain('<span class="cov medium">69.23</span>');
delete global.__$$testCovHtml;
done();
});
});
it('generates a coverage report including sourcemaps information', function (done) {
var Test = require('./coverage/sourcemaps-external');
var script = Lab.script({ schedule: false });
script.experiment('test', function () {
script.test('something', function (finished) {
Test.method(false);
finished();
});
});
Lab.report(script, { reporter: 'html', coverage: true, coveragePath: Path.join(__dirname, './coverage/sourcemaps-external'), sourcemaps: true }, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.contain([
'<th>Original filename</th>',
'<th>Original line</th>',
'<td class="sourcemaps file" data-tooltip>test/coverage/sourcemaps-external.js</td>',
'<td class="sourcemaps line" data-tooltip>1</td>',
'<td class="sourcemaps line" data-tooltip>6</td>',
'<td class="sourcemaps line" data-tooltip>9</td>',
'<td class="sourcemaps line" data-tooltip>11</td>',
'<td class="sourcemaps line" data-tooltip>12</td>',
'<td class="sourcemaps line" data-tooltip>13</td>',
'<td class="sourcemaps line" data-tooltip>16</td>'
]);
delete global.__$$testCovHtml;
done();
});
});
it('generates a coverage report with linting enabled and multiple files', function (done) {
var Test1 = require('./coverage/html-lint/html-lint.1');
var Test2 = require('./coverage/html-lint/html-lint.2');
var script = Lab.script({ schedule: false });
script.experiment('test', function () {
script.test('something', function (finished) {
Test1.method(1, 2, 3);
finished();
});
script.test('something', function (finished) {
Test2.method(1, 2, 3);
finished();
});
});
Lab.report(script, { reporter: 'html', coverage: true, coveragePath: Path.join(__dirname, './coverage/html-lint/'), lint: true, linter: 'eslint', lintingPath: Path.join(__dirname, './coverage/html-lint') }, function (err, code, output) {
expect(err).not.to.exist();
expect(output)
.to.contain('<div class="stats medium">')
.and.to.contain('<span class="errors" data-tooltip="indent - Expected indentation of 4 space characters but found 0.
eqeqeq - Expected '===' and instead saw '=='.
semi - Missing semicolon."></span>')
.and.to.contain('<span class="warnings" data-tooltip="no-eq-null - Use ‘===’ to compare with ‘null’."></span>')
.and.to.contain('<span class="lint-errors low">8</span>')
.and.to.contain('<span class="lint-warnings low">1</span>')
.and.to.contain('<li class="lint-entry">L11 - <span class="level-ERROR">ERROR</span> - indent - Expected indentation of 4 space characters but found 0.</li>')
.and.to.contain('<li class="lint-entry">L12 - <span class="level-ERROR">ERROR</span> - indent - Expected indentation of 4 space characters but found 0.</li>')
.and.to.contain('<li class="lint-entry">L13 - <span class="level-ERROR">ERROR</span> - indent - Expected indentation of 4 space characters but found 0.</li>')
.and.to.contain('<li class="lint-entry">L16 - <span class="level-ERROR">ERROR</span> - indent - Expected indentation of 4 space characters but found 0.</li>')
.and.to.contain('<li class="lint-entry">L19 - <span class="level-ERROR">ERROR</span> - indent - Expected indentation of 4 space characters but found 0.</li>')
.and.to.contain('<li class="lint-entry">L19 - <span class="level-WARNING">WARNING</span> - no-eq-null - Use ‘===’ to compare with ‘null’.</li>')
.and.to.contain('<li class="lint-entry">L19 - <span class="level-ERROR">ERROR</span> - eqeqeq - Expected '===' and instead saw '=='.</li>')
.and.to.contain('<li class="lint-entry">L19 - <span class="level-ERROR">ERROR</span> - semi - Missing semicolon.</li>')
.and.to.contain('<li class="lint-entry">L21 - <span class="level-ERROR">ERROR</span> - indent - Expected indentation of 4 space characters but found 0.</li>');
delete global.__$$testCovHtml;
done();
});
});
it('generates a coverage report with linting enabled with thresholds', function (done) {
var Test1 = require('./coverage/html-lint/html-lint.1');
var Test2 = require('./coverage/html-lint/html-lint.2');
var script = Lab.script({ schedule: false });
script.experiment('test', function () {
script.test('something', function (finished) {
Test1.method(1, 2, 3);
finished();
});
script.test('something', function (finished) {
Test2.method(1, 2, 3);
finished();
});
});
Lab.report(script, { reporter: 'html', coverage: true, coveragePath: Path.join(__dirname, './coverage/html-lint/'), lint: true, linter: 'eslint', lintingPath: Path.join(__dirname, './coverage/html-lint'), 'lint-errors-threshold': 2, 'lint-warnings-threshold': 2 }, function (err, code, output) {
expect(err).not.to.exist();
expect(output)
.to.contain('<span class="lint-errors low">8</span>')
.and.to.contain('<span class="lint-warnings medium">1</span>');
delete global.__$$testCovHtml;
done();
});
});
it('generates a report with test script errors', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.before(function (finished) { });
script.test('works', function (finished) {
finished();
});
});
Lab.report(script, { reporter: 'html', 'context-timeout': 1 }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
expect(output)
.to.contain('Timed out (1ms) - Before test')
.and.to.contain('at Timer.listOnTimeout');
done();
});
});
it('generates a report with test script errors that are not Error', function (done) {
var script = Lab.script();
script.experiment('test', function () {
script.before(function (finished) { throw 'abc'; });
script.test('works', function (finished) {
finished();
});
});
Lab.report(script, { reporter: 'html', 'context-timeout': 1 }, function (err, code, output) {
expect(err).to.not.exist();
expect(code).to.equal(1);
expect(output).to.contain('<div>abc</div>');
done();
});
});
it('tags file percentile based on levels', function (done) {
var reporter = Reporters.generate({ reporter: 'html' });
var notebook = {
coverage: {
percent: 30,
files: [
{
filename: 'a',
percent: 10
},
{
filename: 'b',
percent: 10.1234
},
{
filename: 'c',
percent: 76
},
{
filename: 'd',
percent: 26
}
]
}
};
reporter.finalize(notebook, function (err, code, output) {
expect(err).not.to.exist();
expect(output).to.contain('<span class="cov terrible">10</span>');
expect(output).to.contain('<span class="cov terrible">10.12</span>');
expect(output).to.contain('<span class="cov high">76</span>');
expect(output).to.contai