Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,26 +52,25 @@ Would _you_ be interested in discussing this with us further? Please join in!
Listen to the events and receive the emitted data:

```js
// Attach one of the exiting adapters.
// Use automatic discovery of the framework adapter.
const runner = JsReporters.autoRegister();

// Listen to the same events for any testing framework.
runner.on('testEnd', function (test) {
console.log('Test %s has errors:', test.fullname.join(' '), test.errors);
// Listen to standard events, from any testing framework.
runner.on('testEnd', (test) => {
console.log('Test %s has errors:', test.fullName.join(' '), test.errors);
});

runner.on('runEnd', function (globalSuite) {
const testCounts = globalSuite.testCounts;

console.log('Testsuite status: %s', globalSuite.status);
runner.on('runEnd', (run) => {
const counts = run.counts;

console.log('Testsuite status: %s', run.status);
console.log('Total %d tests: %d passed, %d failed, %d skipped',
testCounts.total,
testCounts.passed,
testCounts.failed,
testCounts.skipped);

console.log('Total duration: %d', globalSuite.runtime);
counts.total,
counts.passed,
counts.failed,
counts.skipped
);
console.log('Total duration: %d', run.runtime);
});

// Or use one of the built-in reporters.
Expand Down
8 changes: 2 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ const JasmineAdapter = require('./lib/adapters/JasmineAdapter.js');
const MochaAdapter = require('./lib/adapters/MochaAdapter.js');
const TapReporter = require('./lib/reporters/TapReporter.js');
const ConsoleReporter = require('./lib/reporters/ConsoleReporter.js');
const SummaryReporter = require('./lib/reporters/SummaryReporter.js');
const {
collectSuiteStartData,
collectSuiteEndData,
createSuiteStart,
createTestStart
} = require('./lib/helpers.js');
const { autoRegister } = require('./lib/auto.js');
Expand All @@ -18,10 +16,8 @@ module.exports = {
MochaAdapter,
TapReporter,
ConsoleReporter,
SummaryReporter,
EventEmitter,
collectSuiteStartData,
collectSuiteEndData,
createSuiteStart,
createTestStart,
autoRegister
};
115 changes: 60 additions & 55 deletions lib/adapters/JasmineAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ module.exports = class JasmineAdapter extends EventEmitter {
// NodeJS or browser
this.env = jasmine.env || jasmine.getEnv();

this.suiteStarts = {};
this.suiteChildren = {};
this.suiteEnds = {};
this.suiteEnds = [];
this.testStarts = {};
this.testEnds = {};

Expand Down Expand Up @@ -56,93 +55,90 @@ module.exports = class JasmineAdapter extends EventEmitter {

return {
name: testStart.name,
suiteName: testStart.suiteName,
parentName: testStart.parentName,
fullName: testStart.fullName.slice(),
status: (result.status === 'pending') ? 'skipped' : result.status,
// TODO: Jasmine 3.4+ has result.duration, use it.
// Note that result.duration uses 0 instead of null for a 'skipped' test.
runtime: (result.status === 'pending') ? null : (new Date() - this.startTime),
errors,
assertions
};
}

/**
* Convert a Jasmine SuiteResult for CRI 'runStart' or 'suiteStart' event data.
* Traverse the Jasmine structured returned by `this.env.topSuite()`
* in order to extract the child-parent relations and full names.
*
* Jasmine provides details about childSuites and tests only in the structure
* returned by "this.env.topSuite()".
*/
createSuiteStart (result, parentNames) {
processSuite (result, parentNames, parentIds) {
const isGlobalSuite = (result.description === 'Jasmine__TopLevel__Suite');

const name = isGlobalSuite ? null : result.description;
const fullName = parentNames.slice();
const tests = [];
const childSuites = [];

if (!isGlobalSuite) {
fullName.push(result.description);
fullName.push(name);
}

parentIds.push(result.id);
this.suiteChildren[result.id] = [];

result.children.forEach((child) => {
this.testStarts[child.id] = {
name: child.description,
parentName: name,
fullName: [...fullName, child.description]
};

if (child.id.indexOf('suite') === 0) {
childSuites.push(this.createSuiteStart(child, fullName));
this.processSuite(child, fullName.slice(), parentIds.slice());
} else {
const testStart = {
name: child.description,
suiteName: name,
fullName: [...fullName, child.description]
};
tests.push(testStart);
this.testStarts[child.id] = testStart;
// Update flat list of test children
parentIds.forEach((id) => {
this.suiteChildren[id].push(child.id);
});
}
});

const helperData = helpers.collectSuiteStartData(tests, childSuites);
const suiteStart = {
name,
fullName,
tests,
childSuites,
testCounts: helperData.testCounts
};
this.suiteStarts[result.id] = suiteStart;
this.suiteChildren[result.id] = result.children.map(child => child.id);
return suiteStart;
}

createSuiteEnd (suiteStart, result) {
const tests = [];
const childSuites = [];
this.suiteChildren[result.id].forEach((childId) => {
if (childId.indexOf('suite') === 0) {
childSuites.push(this.suiteEnds[childId]);
} else {
tests.push(this.testEnds[childId]);
}
});
createSuiteEnd (testStart, result) {
const tests = this.suiteChildren[result.id].map((testId) => this.testEnds[testId]);

const helperData = helpers.collectSuiteEndData(tests, childSuites);
const helperData = helpers.aggregateTests(tests);
return {
name: suiteStart.name,
fullName: suiteStart.fullName,
tests,
childSuites,
name: testStart.name,
parentName: testStart.parentName,
fullName: testStart.fullName,
// Jasmine has result.status, but does not propagate 'todo' or 'skipped'
status: helperData.status,
testCounts: helperData.testCounts,
// Jasmine 3.4+ has result.duration, but uses 0 instead of null
// when 'skipped' is skipped.
runtime: helperData.status === 'skipped' ? null : (result.duration || helperData.runtime)
runtime: result.duration || helperData.runtime,
errors: [],
assertions: []
};
}

onJasmineStarted () {
this.globalSuite = this.createSuiteStart(this.env.topSuite(), []);
this.emit('runStart', this.globalSuite);
this.processSuite(this.env.topSuite(), [], []);

let total = 0;
this.env.topSuite().children.forEach(function countChild (child) {
total++;
if (child.id.indexOf('suite') === 0) {
child.children.forEach(countChild);
}
});

this.emit('runStart', {
name: null,
counts: {
total: total
}
});
}

onSuiteStarted (result) {
this.emit('suiteStart', this.suiteStarts[result.id]);
this.emit('testStart', this.testStarts[result.id]);
}

onSpecStarted (result) {
Expand All @@ -156,11 +152,20 @@ module.exports = class JasmineAdapter extends EventEmitter {
}

onSuiteDone (result) {
this.suiteEnds[result.id] = this.createSuiteEnd(this.suiteStarts[result.id], result);
this.emit('suiteEnd', this.suiteEnds[result.id]);
const suiteEnd = this.createSuiteEnd(this.testStarts[result.id], result);
this.suiteEnds.push(suiteEnd);
this.emit('testEnd', suiteEnd);
}

onJasmineDone (doneInfo) {
this.emit('runEnd', this.createSuiteEnd(this.globalSuite, this.env.topSuite()));
const topSuite = this.env.topSuite();
const tests = this.suiteChildren[topSuite.id].map((testId) => this.testEnds[testId]);
const helperData = helpers.aggregateTests([...tests, ...this.suiteEnds]);
this.emit('runEnd', {
name: null,
status: helperData.status,
counts: helperData.counts,
runtime: helperData.runtime
});
}
};
Loading