150 lines
3.1 KiB
JavaScript
150 lines
3.1 KiB
JavaScript
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var Base = require('./base')
|
|
, utils = require('../utils')
|
|
, fs = require('fs')
|
|
, escape = utils.escape;
|
|
|
|
/**
|
|
* Save timer references to avoid Sinon interfering (see GH-237).
|
|
*/
|
|
|
|
var Date = global.Date
|
|
, setTimeout = global.setTimeout
|
|
, setInterval = global.setInterval
|
|
, clearTimeout = global.clearTimeout
|
|
, clearInterval = global.clearInterval;
|
|
|
|
/**
|
|
* Expose `XUnit`.
|
|
*/
|
|
|
|
exports = module.exports = XUnit;
|
|
|
|
/**
|
|
* Initialize a new `XUnit` reporter.
|
|
*
|
|
* @param {Runner} runner
|
|
* @api public
|
|
*/
|
|
|
|
function XUnit(runner, options) {
|
|
Base.call(this, runner);
|
|
var stats = this.stats
|
|
, tests = []
|
|
, self = this;
|
|
|
|
if (options.reporterOptions && options.reporterOptions.output) {
|
|
if (! fs.createWriteStream) {
|
|
throw new Error('file output not supported in browser');
|
|
}
|
|
self.fileStream = fs.createWriteStream(options.reporterOptions.output);
|
|
}
|
|
|
|
runner.on('pending', function(test){
|
|
tests.push(test);
|
|
});
|
|
|
|
runner.on('pass', function(test){
|
|
tests.push(test);
|
|
});
|
|
|
|
runner.on('fail', function(test){
|
|
tests.push(test);
|
|
});
|
|
|
|
runner.on('end', function(){
|
|
self.write(tag('testsuite', {
|
|
name: 'Mocha Tests'
|
|
, tests: stats.tests
|
|
, failures: stats.failures
|
|
, errors: stats.failures
|
|
, skipped: stats.tests - stats.failures - stats.passes
|
|
, timestamp: (new Date).toUTCString()
|
|
, time: (stats.duration / 1000) || 0
|
|
}, false));
|
|
|
|
tests.forEach(function(t) { self.test(t); });
|
|
self.write('</testsuite>');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Override done to close the stream (if it's a file).
|
|
*/
|
|
XUnit.prototype.done = function(failures, fn) {
|
|
if (this.fileStream) {
|
|
this.fileStream.end(function() {
|
|
fn(failures);
|
|
});
|
|
} else {
|
|
fn(failures);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Inherit from `Base.prototype`.
|
|
*/
|
|
|
|
XUnit.prototype.__proto__ = Base.prototype;
|
|
|
|
/**
|
|
* Write out the given line
|
|
*/
|
|
XUnit.prototype.write = function(line) {
|
|
if (this.fileStream) {
|
|
this.fileStream.write(line + '\n');
|
|
} else {
|
|
console.log(line);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Output tag for the given `test.`
|
|
*/
|
|
|
|
XUnit.prototype.test = function(test, ostream) {
|
|
var attrs = {
|
|
classname: test.parent.fullTitle()
|
|
, name: test.title
|
|
, time: (test.duration / 1000) || 0
|
|
};
|
|
|
|
if ('failed' == test.state) {
|
|
var err = test.err;
|
|
this.write(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack))));
|
|
} else if (test.pending) {
|
|
this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
|
|
} else {
|
|
this.write(tag('testcase', attrs, true) );
|
|
}
|
|
};
|
|
|
|
/**
|
|
* HTML tag helper.
|
|
*/
|
|
|
|
function tag(name, attrs, close, content) {
|
|
var end = close ? '/>' : '>'
|
|
, pairs = []
|
|
, tag;
|
|
|
|
for (var key in attrs) {
|
|
pairs.push(key + '="' + escape(attrs[key]) + '"');
|
|
}
|
|
|
|
tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
|
|
if (content) tag += content + '</' + name + end;
|
|
return tag;
|
|
}
|
|
|
|
/**
|
|
* Return cdata escaped CDATA `str`.
|
|
*/
|
|
|
|
function cdata(str) {
|
|
return '<![CDATA[' + escape(str) + ']]>';
|
|
}
|