sl-node-mocha
Version:
SeaLights mocha reporter
232 lines (206 loc) • 8.52 kB
JavaScript
/**
* Module dependencies.
*/
var mocha = require("mocha"),
Base = mocha.reporters.Base,
utils = mocha.utils,
inherits = utils.inherits,
log = console.log,
sealights = require('sl-node'),
slProcess = null,
executionId = null,
fs = require('fs');
/**
* Expose `SeaLightsReporter`.
*/
exports = module.exports = SeaLightsReporter;
/**
* Initialize a new `SeaLightsReporter` reporter.
*
* @param {Runner} runner
* @api public
*/
function SeaLightsReporter(runner, options) {
Base.call(this, runner, options);
var reporter = this,
slProcess = null,
executionId = null,
shutDownTimeout = 60 * 1000, //Allow 1 minute to send all remaining footprints and events
counters = { start:0, fail:0, pass:0, end:0, skipped:0 },
warnedOnce = false,
reporterName = (options && options.reporterOptions && options.reporterOptions.reporter) || "spec",
mochaReporters = mocha.reporters, ChainedReporterType = mochaReporters.spec,
chainedReporter = null;
if (mochaReporters.hasOwnProperty(reporterName)) {
ChainedReporterType = mochaReporters[reporterName];
} else {
try {
ChainedReporterType = require(reporterName);
}
catch(e) {
log.warn('[SeaLights for Mocha] Cannot find reporter ' + reporterName + ', using default Spec reporter');
//ChainedReporterType = mochaReporters.spec; //default
}
}
chainedReporter = new ChainedReporterType(runner, options);
// Before running any suite, initialize SL and create a test execution ID
runner.suite.beforeAll(function(done) {
console.log('[SeaLights for Mocha] Version ' + reporter.getVersion() + ", agent version " + sealights.getVersion());
console.log('[SeaLights for Mocha] Initializing');
sealights.init({ instrument: false }).then(function (_slProcess) {
console.log('[SeaLights for Mocha] Initialized')
slProcess = _slProcess;
if (slProcess) {
executionId = slProcess.createTestSuiteId();
slProcess.pushEvent({ type: 'executionIdStarted', executionId: executionId, framework: 'mocha', reporterVersion: reporter.getVersion() });
var __initTestId = slProcess.createTestId(executionId, '__init');
slProcess.setCurrentTestIdentifier(__initTestId, true);
}
done();
}).catch(function(e) {
console.log('[SeaLights for Mocha] Initialization error');
console.error(e);
done();
});
});
// After all tests have been executed, wait for the SL process to shut down
runner.suite.afterAll(function(done){
if (!slProcess) return done();
slProcess.pushEvent({ type: 'executionIdEnded', executionId: executionId, meta:{counters:clone(counters)} });
slProcess.resume && slProcess.resume();
executionId = null;
var doneCallbackInvoked = false;
function invokeDoneCallback(err) {
if (doneCallbackInvoked) return;
if (handle)
{
try {
clearTimeout(handle); //Don't keep the process running because of this timeout
handle = null;
} catch(e){
console.error(e);
}
}
doneCallbackInvoked = true;
if (done) {
done(err);
}
}
var handle = setTimeout(function() {
if (doneCallbackInvoked) return; //callback already called
handle = null;
console.warn('\n[SeaLights for Mocha] Send operation timed out.');
invokeDoneCallback();
}, shutDownTimeout);
this.timeout(0); //Disable mocha's timeout, since we handle the timeout here^^.
try {
console.log('\n[SeaLights for Mocha] Sending remaining data to server');
slProcess.shutDown(invokeDoneCallback);
} catch(err) {
console.error(err.stack);
invokeDoneCallback();
}
});
runner.on('test', function (test) {
counters.start++;
saveCounters();
try{
var testName = test.fullTitle();
var suitePath = getSuitePath(test);
//log('RUN: ' + testName);
if (!slProcess) {
if (!warnedOnce){
console.warn('[SeaLights for Mocha] Mocha reporter was not properly intiailized.')
warnedOnce = true;
}
return;
}
var testId = slProcess.createTestId(executionId, testName);
slProcess.setCurrentTestIdentifier(testId);
slProcess.pushEvent({ type: 'testStart', testName: testName, executionId: executionId, testPath: suitePath, meta:{counters:clone(counters)} });
slProcess.suspend && slProcess.suspend();
} catch(e) {
writeToLog('error #68: '+e);
}
});
runner.on('fail', function (test, err) {
counters.fail++;
saveCounters();
if (err)
writeToLog('fail error: '+err + '\n' + err.stack);
try{
//log('FAIL: ' + test.fullTitle());
if (!slProcess) return;
var testName = test.fullTitle();
var suitePath = getSuitePath(test);
slProcess.pushEvent({ type: 'testEnd', testName: testName, executionId: executionId, testPath: suitePath, result: "failed", duration: test.duration, meta:{counters:clone(counters)} });
slProcess.resume && slProcess.resume();
} catch(e) {
writeToLog('error #84: '+e);
}
});
runner.on('pass', function (test, err) {
counters.pass++;
saveCounters();
if (err)
writeToLog('pass error: ' + err + '\n' + err.stack);
try {
//log('PASS: ' + test.fullTitle());
if (!slProcess) return;
var testName = test.fullTitle();
var suitePath = getSuitePath(test);
slProcess.pushEvent({ type: 'testEnd', testName: testName, executionId: executionId, testPath: suitePath, result: "passed", duration: test.duration, meta:{counters:clone(counters)} });
slProcess.resume && slProcess.resume();
} catch(e) {
writeToLog('error #99: '+e);
}
});
runner.on('test end', function (test) {
counters.end++;
saveCounters();
try{
if (!slProcess) return;
slProcess.setCurrentTestIdentifier(null);
slProcess.resume && slProcess.resume();
} catch(e) {
writeToLog('error #110: '+e);
}
});
runner.on('pending', function(test) {
counters.skipped++;
saveCounters();
if (!slProcess) return;
var testName = test.fullTitle();
var suitePath = getSuitePath(test);
slProcess.pushEvent({ type: 'testStart', testName: testName, executionId: executionId, testPath: suitePath, meta:{counters:clone(counters)} });
slProcess.pushEvent({ type: 'testEnd', testName: testName, executionId: executionId, testPath: suitePath, result: "skipped", meta:{counters:clone(counters)} });
slProcess.resume && slProcess.resume();
});
function getSuitePath(t){
//t = t.parent;
var parts = [];
while(t){
if (t.parent)
parts.unshift(t.title);
t = t.parent;
}
return parts;
}
function saveCounters(){
//var str = '[ ' + new Date().toString()+' ] ' + JSON.stringify(counters) + '\n';
//fs.appendFileSync('sl.mocha.log', str );
}
function writeToLog(str){
slProcess && slProcess.writeToLog && slProcess.writeToLog(str);
}
function clone(o){
return JSON.parse(JSON.stringify(o));
}
this.getExecutionId = function getExecutionId() {
return executionId;
}
this.getVersion = function getVersion() {
return require('../package.json').version;
}
}
inherits(SeaLightsReporter, Base);