| /*! |
| * Nodeunit |
| * Copyright (c) 2010 Caolan McMahon |
| * MIT Licensed |
| */ |
| |
| /** |
| * Module dependencies |
| */ |
| |
| var nodeunit = require('../nodeunit'), |
| utils = require('../utils'), |
| fs = require('fs'), |
| path = require('path'), |
| async = require('../../deps/async'), |
| AssertionError = require('assert').AssertionError, |
| child_process = require('child_process'), |
| ejs = require('../../deps/ejs'); |
| |
| |
| /** |
| * Reporter info string |
| */ |
| |
| exports.info = "jUnit XML test reports"; |
| |
| |
| /** |
| * Ensures a directory exists using mkdir -p. |
| * |
| * @param {String} path |
| * @param {Function} callback |
| * @api private |
| */ |
| |
| var ensureDir = function (path, callback) { |
| var mkdir = child_process.spawn('mkdir', ['-p', path]); |
| mkdir.on('error', function (err) { |
| callback(err); |
| callback = function(){}; |
| }); |
| mkdir.on('exit', function (code) { |
| if (code === 0) callback(); |
| else callback(new Error('mkdir exited with code: ' + code)); |
| }); |
| }; |
| |
| |
| /** |
| * Returns absolute version of a path. Relative paths are interpreted |
| * relative to process.cwd() or the cwd parameter. Paths that are already |
| * absolute are returned unaltered. |
| * |
| * @param {String} p |
| * @param {String} cwd |
| * @return {String} |
| * @api public |
| */ |
| |
| var abspath = function (p, /*optional*/cwd) { |
| if (p[0] === '/') return p; |
| cwd = cwd || process.cwd(); |
| return path.normalize(path.resolve(p)); |
| }; |
| |
| |
| /** |
| * Run all tests within each module, reporting the results to the command-line, |
| * then writes out junit-compatible xml documents. |
| * |
| * @param {Array} files |
| * @api public |
| */ |
| |
| exports.run = function (files, opts, callback) { |
| if (!opts.output) { |
| console.error( |
| 'Error: No output directory defined.\n' + |
| '\tEither add an "output" property to your nodeunit.json config ' + |
| 'file, or\n\tuse the --output command line option.' |
| ); |
| return; |
| } |
| opts.output = abspath(opts.output); |
| var error = function (str) { |
| return opts.error_prefix + str + opts.error_suffix; |
| }; |
| var ok = function (str) { |
| return opts.ok_prefix + str + opts.ok_suffix; |
| }; |
| var bold = function (str) { |
| return opts.bold_prefix + str + opts.bold_suffix; |
| }; |
| |
| var start = new Date().getTime(); |
| var paths = files.map(function (p) { |
| return path.resolve(p); |
| }); |
| |
| var modules = {} |
| var curModule; |
| |
| nodeunit.runFiles(paths, { |
| testspec: opts.testspec, |
| testFullSpec: opts.testFullSpec, |
| moduleStart: function (name) { |
| curModule = { |
| errorCount: 0, |
| failureCount: 0, |
| tests: 0, |
| testcases: [], |
| name: name |
| }; |
| modules[name] = curModule; |
| }, |
| testDone: function (name, assertions) { |
| var testcase = {name: name}; |
| for (var i=0; i<assertions.length; i++) { |
| var a = assertions[i]; |
| if (a.failed()) { |
| a = utils.betterErrors(a); |
| testcase.failure = { |
| message: a.message, |
| backtrace: a.error.stack |
| }; |
| |
| if (a.error instanceof AssertionError) { |
| curModule.failureCount++; |
| } |
| else { |
| curModule.errorCount++; |
| } |
| break; |
| } |
| } |
| curModule.tests++; |
| curModule.testcases.push(testcase); |
| }, |
| done: function (assertions) { |
| var end = new Date().getTime(); |
| var duration = end - start; |
| |
| ensureDir(opts.output, function (err) { |
| var tmpl = __dirname + "/../../share/junit.xml.ejs"; |
| fs.readFile(tmpl, function (err, data) { |
| if (err) throw err; |
| var tmpl = data.toString(); |
| for(var k in modules) { |
| var module = modules[k]; |
| var rendered = ejs.render(tmpl, { |
| locals: {suites: [module]} |
| }); |
| var filename = path.resolve( |
| opts.output, |
| module.name + '.xml' |
| ); |
| console.log('Writing ' + filename); |
| fs.writeFileSync(filename, rendered, 'utf8'); |
| } |
| if (assertions.failures()) { |
| console.log( |
| '\n' + bold(error('FAILURES: ')) + |
| assertions.failures() + '/' + |
| assertions.length + ' assertions failed (' + |
| assertions.duration + 'ms)' |
| ); |
| } |
| else { |
| console.log( |
| '\n' + bold(ok('OK: ')) + assertions.length + |
| ' assertions (' + assertions.duration + 'ms)' |
| ); |
| } |
| |
| if (callback) callback(assertions.failures() ? new Error('We have got test failures.') : undefined); |
| }); |
| }); |
| } |
| }); |
| } |