UNPKG

node-qunit

Version:

QUnit testing framework for Node.js

264 lines (216 loc) 6.55 kB
var Table = require('cli-table'); var data, log = console.log, fileColWidth = 50; data = { assertions: [], tests: [], summaries: [], coverages: [] }; /** * Add data to the log report. * * @param {String} type * @param {Object} obj * @return {Array} */ exports.add = function(type, obj) { if (obj) { data[type].push(obj); } return data[type]; }; /** * Get global tests stats in unified format */ exports.stats = function() { var stats = { files: 0, assertions: 0, failed: 0, passed: 0, runtime: 0 }; data.summaries.forEach(function(file) { stats.files++; stats.assertions += file.total; stats.failed += file.failed; stats.passed += file.passed; stats.runtime += file.runtime; }); stats.tests = data.tests.length; stats.coverage = { files: 0, statements: { covered: 0, total: 0 }, branches: { covered: 0, total: 0 }, functions: { covered: 0, total: 0 }, lines: { covered: 0, total: 0 } }; data.coverages.forEach(function(file) { stats.coverage.files++; stats.coverage.statements.covered += file.statements.covered; stats.coverage.statements.total += file.statements.total; stats.coverage.branches.covered += file.branches.covered; stats.coverage.branches.total += file.branches.total; stats.coverage.functions.covered += file.functions.covered; stats.coverage.functions.total += file.functions.total; stats.coverage.lines.covered += file.lines.covered; stats.coverage.lines.total += file.lines.total; }); return stats; }; /** * Reset global stats data */ exports.reset = function() { data = { assertions: [], tests: [], summaries: [], coverages: [] }; }; var print = exports.print = {}; print.assertions = function() { var table, currentModule, module, currentTest, test; table = new Table({ head: ['Module', 'Test', 'Assertion', 'Result'] }); data.assertions.forEach(function(data) { // just easier to read the table if (data.module === currentModule) { module = ''; } else { module = currentModule = data.module; } // just easier to read the table if (data.test === currentTest) { test = ''; } else { test = currentTest = data.test; } table.push([module, test, data.message || '', data.result ? 'ok' : 'fail']); }); log('\nAssertions:\n' + table.toString()); }; print.errors = function() { var errors = []; data.assertions.forEach(function(data) { if (!data.result) { errors.push(data); } }); if (errors.length) { log('\n\nErrors:'); errors.forEach(function(data) { log('\nModule: ' + data.module + ' Test: ' + data.test); if (data.message) { log(data.message); } if (data.source) { log(data.source); } if (data.expected != null || data.actual != null) { //it will be an error if data.expected !== data.actual, but if they're //both undefined, it means that they were just not filled out because //no assertions were hit (likely due to code error that would have been logged as source or message). log('Actual value:'); log(data.actual); log('Expected value:'); log(data.expected); } }); } }; print.tests = function() { var table, currentModule, module; table = new Table({ head: ['Module', 'Test', 'Failed', 'Passed', 'Total'] }); data.tests.forEach(function(data) { // just easier to read the table if (data.module === currentModule) { module = ''; } else { module = currentModule = data.module; } table.push([module, data.name, data.failed, data.passed, data.total]); }); log('\nTests:\n' + table.toString()); }; // truncate file name function truncFile(code) { if (code && code.length > fileColWidth) { code = '...' + code.slice(code.length - fileColWidth + 3); } return code; } print.summary = function() { var table; table = new Table({ head: ['File', 'Failed', 'Passed', 'Total', 'Runtime'] }); data.summaries.forEach(function(data) { table.push([truncFile(data.code), data.failed, data.passed, data.total, data.runtime]); }); log('\nSummary:\n' + table.toString()); }; print.globalSummary = function() { var table, data = exports.stats(); table = new Table({ head: ['Files', 'Tests', 'Assertions', 'Failed', 'Passed', 'Runtime'] }); table.push([data.files, data.tests, data.assertions, data.failed, data.passed, data.runtime]); log('\nGlobal summary:\n' + table.toString()); }; function getMet(metric) { function percent(covered, total) { var tmp; if (total > 0) { tmp = 1000 * 100 * covered / total + 5; return Math.floor(tmp / 10) / 100; } else { return 100.00; } } if (!metric.pct) metric.pct = percent(metric.covered, metric.total); return metric.pct + '% (' + metric.covered + '/' + metric.total + ')'; } print.coverage = function() { var table; if (!data.coverages.length) return; table = new Table({ head: ['File', 'Statements', 'Branches', 'Functions', 'Lines'] }); data.coverages.forEach(function(coverage) { table.push([ truncFile(coverage.code), getMet(coverage.statements), getMet(coverage.branches), getMet(coverage.functions), getMet(coverage.lines)]); }); log('\nCoverage:\n' + table.toString()); }; print.globalCoverage = function() { var coverage, table; if (!data.coverages.length) return; coverage = exports.stats().coverage; table = new Table({ head: ['Files', 'Statements', 'Branches', 'Functions', 'Lines'] }); table.push([ coverage.files, getMet(coverage.statements), getMet(coverage.branches), getMet(coverage.functions), getMet(coverage.lines) ]); log('\nGlobal coverage:\n' + table.toString()); };