Files
elasticsearch-js/test/utils/jenkins-reporter.js
2016-05-19 14:23:33 -07:00

209 lines
5.1 KiB
JavaScript

/**
* ESJS reporter for running and collecting mocha test results.
*
* @param {Runner} runner
* @api public
*/
module.exports = JenkinsReporter;
var Base = require('mocha/lib/reporters/base');
// var _ = require('lodash');
var chalk = require('chalk');
var makeJUnitXml = require('./make_j_unit_xml');
var fs = require('fs');
var path = require('path');
var inspect = require('util').inspect;
var log = (function () {
var locked = _v4.bind(process.stdout.write, process.stdout);
return function (str) {
if (typeof str !== 'string') {
str = inspect(str);
}
locked(str);
};
}());
var integration = _v4.find(process.argv, function (arg) { return arg.indexOf('test/integration') > -1; });
var unit = _v4.find(process.argv, function (arg) { return arg.indexOf('test/unit') > -1; });
var output;
if (unit) {
output = path.join(__dirname, '../junit-node-unit.xml');
} else if (integration) {
output = path.join(__dirname, '../junit-node-integration.xml');
} else {
throw new Error('unable to detect unit or integration tests');
}
function JenkinsReporter(runner) {
Base.call(this, runner);
var stats = this.stats;
var pass = 0;
var pending = 0;
var fail = 0;
var rootSuite = {
results: [],
suites: []
};
var stack = [rootSuite];
function indt() {
return (new Array(stack.length + 1)).join(' ');
}
runner.on('suite', function (suite) {
if (suite.root) {
return;
}
// suite
suite = {
name: suite.fullTitle(),
results: [],
start: Date.now(),
stdout: '',
stderr: ''
};
// append to the previous stack leader
if (!stack[0].suites) {
stack[0].suites = [];
}
stack[0].suites.push(suite);
// push the suite onto the top of the stack
stack.unshift(suite);
});
runner.on('suite end', function (suite) {
if (suite.root) {
return;
}
stack[0].time = Date.now() - stack[0].start;
stack.shift();
});
runner.on('fail', function (test) {
if ('hook' === test.type) {
runner.emit('test end', test);
}
});
runner.on('test end', function (test) {
if (test.state === 'passed') {
pass++;
log(chalk.green('.'));
} else if (test.pending) {
pending++;
log(chalk.grey('.'));
return;
} else {
fail++;
log(chalk.red('x'));
}
var errMsg = void 0;
if (test.err) {
errMsg = test.err.stack || test.err.toString();
// FF / Opera do not add the message
if (!~errMsg.indexOf(test.err.message)) {
errMsg = test.err.message + '\n' + errMsg;
}
// <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
// check for the result of the stringifying.
if ('[object Error]' === errMsg) {
errMsg = test.err.message;
}
// Safari doesn't give you a stack. Let's at least provide a source line.
if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) {
errMsg += '\n(' + test.err.sourceURL + ':' + test.err.line + ')';
}
console.error(_v4.map(errMsg.split('\n'), function (line) {
return indt() + ' ' + line;
}).join('\n'));
}
if (stack[0]) {
stack[0].results.push({
name: test.title,
time: test.duration,
pass: test.state === 'passed',
test: test,
stdout: stack[0].stdout,
stderr: stack[0].stderr
});
stack[0].stdout = stack[0].stderr = '';
}
});
runner.on('hook end', function (hook) {
if (hook.title.indexOf('"after each"') > -1 && stack[0] && stack[0].results.length) {
var result = _v4.last(stack[0].results);
result.stdout += stack[0].stdout;
result.stderr += stack[0].stderr;
stack[0].stdout = stack[0].stderr = '';
}
});
runner.on('end', function () {
restoreStdio();
var xml = makeJUnitXml('node ' + process.version, {
stats: stats,
suites: _v4.map(rootSuite.suites, function removeElements(suite) {
var s = {
name: suite.name,
start: suite.start,
time: suite.time || 0,
results: suite.results,
stdout: suite.stdout,
stderr: suite.stderr
};
if (suite.suites) {
s.suites = _v4.map(suite.suites, removeElements);
}
return s;
})
});
fs.writeFileSync(output, xml, 'utf8');
console.log('\n' + [
'tests complete in ' + (Math.round(stats.duration / 10) / 100) + ' seconds',
' fail: ' + chalk.red(stats.failures),
' pass: ' + chalk.green(stats.passes),
' pending: ' + chalk.grey(stats.pending)
].join('\n'));
});
// overload the write methods on stdout and stderr
['stdout', 'stderr'].forEach(function (name) {
var obj = process[name];
var orig = obj.write;
obj.write = function (chunk) {
if (stack[0]) {
stack[0][name] = (stack[0][name] || '') + chunk;
}
// orig.apply(obj, arguments);
};
obj.__restore = function () {
this.write = orig;
};
});
function restoreStdio() {
process.stdout.__restore();
process.stderr.__restore();
}
}