Skip to content

Commit

Permalink
[BREAKING CHANGE] Restore most consumer back-compat with v1
Browse files Browse the repository at this point in the history
In light of the shift in direction per #133,
I'm reverting (most of) cce0e4d so as
to allow the next release to more similar to the previous, and to make
upgrading easy, allowing most reporters to keep working with very minimal
changes (if any).

Instead, I'll focus on migrating consumers of js-reporters to use
TAP tools directly where available, and to otherwise reduce use of
js-reporters to purely the adapting and piping to TapReporter.

* Revert `RunStart.testCounts` > `RunStart.counts` (idem RunEnd).
* Revert `TestStart.suitName` > `TestStart.parentName` (idem TestEnd).
* Revert Test allowing Test as child, restore Suite.

This un-fixes #126,
which will be declined. Frameworks adapted to TAP by js-reporters will
not supported nested tests.

Frameworks directly providing TAP 13 can one of several strategies
to express relationships in a backwards-compatible manner, e.g. like
we do in js-reporters by flattening with '>' symbol, or through
indentation or through other manners proposed in
TestAnything/testanything.github.io#36.
Refer to #133 for
questions about how to support TAP.
  • Loading branch information
Krinkle committed Feb 21, 2021
1 parent 4d81c00 commit 53432e5
Show file tree
Hide file tree
Showing 12 changed files with 287 additions and 193 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ runner.on('testEnd', (test) => {
});

runner.on('runEnd', (run) => {
const counts = run.counts;
const counts = run.testCounts;

console.log('Testsuite status: %s', run.status);
console.log('Total %d tests: %d passed, %d failed, %d skipped',
Expand Down
33 changes: 17 additions & 16 deletions lib/adapters/JasmineAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = class JasmineAdapter extends EventEmitter {

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

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

return {
name: testStart.name,
parentName: testStart.parentName,
suiteName: testStart.suiteName,
fullName: testStart.fullName.slice(),
status: (result.status === 'pending') ? 'skipped' : result.status,
// TODO: Jasmine 3.4+ has result.duration, use it.
Expand Down Expand Up @@ -85,15 +86,18 @@ module.exports = class JasmineAdapter extends EventEmitter {
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) {
this.suiteStarts[child.id] = {
name: child.description,
fullName: [...fullName, child.description]
};
this.processSuite(child, fullName.slice(), parentIds.slice());
} else {
this.testStarts[child.id] = {
name: child.description,
suiteName: name,
fullName: [...fullName, child.description]
};
// Update flat list of test children
parentIds.forEach((id) => {
this.suiteChildren[id].push(child.id);
Expand All @@ -108,13 +112,10 @@ module.exports = class JasmineAdapter extends EventEmitter {
const helperData = helpers.aggregateTests(tests);
return {
name: testStart.name,
parentName: testStart.parentName,
fullName: testStart.fullName,
// Jasmine has result.status, but does not propagate 'todo' or 'skipped'
status: helperData.status,
runtime: result.duration || helperData.runtime,
errors: [],
assertions: []
runtime: result.duration || helperData.runtime
};
}

Expand All @@ -131,14 +132,14 @@ module.exports = class JasmineAdapter extends EventEmitter {

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

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

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

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

onJasmineDone (doneInfo) {
Expand All @@ -164,7 +165,7 @@ module.exports = class JasmineAdapter extends EventEmitter {
this.emit('runEnd', {
name: null,
status: helperData.status,
counts: helperData.counts,
testCounts: helperData.testCounts,
runtime: helperData.runtime
});
}
Expand Down
30 changes: 13 additions & 17 deletions lib/adapters/MochaAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ module.exports = class MochaAdapter extends EventEmitter {
convertToSuiteStart (mochaSuite) {
return {
name: mochaSuite.title,
parentName: (mochaSuite.parent && !mochaSuite.parent.root) ? mochaSuite.parent.title : null,
fullName: this.titlePath(mochaSuite)
};
}
Expand All @@ -47,25 +46,22 @@ module.exports = class MochaAdapter extends EventEmitter {

return {
name: mochaSuite.title,
parentName: (mochaSuite.parent && !mochaSuite.parent.root) ? mochaSuite.parent.title : null,
fullName: this.titlePath(mochaSuite),
status: helperData.status,
runtime: helperData.runtime,
errors: [],
assertions: []
runtime: helperData.runtime
};
}

convertTest (mochaTest) {
let parentName;
let suiteName;
let fullName;
if (!mochaTest.parent.root) {
parentName = mochaTest.parent.title;
suiteName = mochaTest.parent.title;
fullName = this.titlePath(mochaTest.parent);
// Add also the test name.
fullName.push(mochaTest.title);
} else {
parentName = null;
suiteName = null;
fullName = [mochaTest.title];
}

Expand All @@ -85,7 +81,7 @@ module.exports = class MochaAdapter extends EventEmitter {

return {
name: mochaTest.title,
parentName,
suiteName,
fullName,
status,
runtime,
Expand All @@ -96,7 +92,7 @@ module.exports = class MochaAdapter extends EventEmitter {
// It is a "test start".
return {
name: mochaTest.title,
parentName,
suiteName,
fullName
};
}
Expand Down Expand Up @@ -130,15 +126,15 @@ module.exports = class MochaAdapter extends EventEmitter {
});
this.emit('runStart', {
name: null,
counts: {
testCounts: {
total: total
}
});
}

onSuite (mochaSuite) {
if (!mochaSuite.root) {
this.emit('testStart', this.convertToSuiteStart(mochaSuite));
this.emit('suiteStart', this.convertToSuiteStart(mochaSuite));
}
}

Expand Down Expand Up @@ -175,19 +171,19 @@ module.exports = class MochaAdapter extends EventEmitter {

onSuiteEnd (mochaSuite) {
if (!mochaSuite.root) {
const testEnd = this.convertToSuiteEnd(mochaSuite);
this.emit('testEnd', testEnd);
const suiteEnd = this.convertToSuiteEnd(mochaSuite);
this.emit('suiteEnd', suiteEnd);
this.finalCounts.total++;
this.finalCounts[testEnd.status]++;
this.finalRuntime += testEnd.runtime || 0;
this.finalCounts[suiteEnd.status]++;
this.finalRuntime += suiteEnd.runtime || 0;
}
}

onEnd (details) {
this.emit('runEnd', {
name: null,
status: this.finalCounts.failed > 0 ? 'failed' : 'passed',
counts: this.finalCounts,
testCounts: this.finalCounts,
runtime: this.finalRuntime
});
}
Expand Down
43 changes: 21 additions & 22 deletions lib/adapters/QUnitAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ module.exports = class QUnitAdapter extends EventEmitter {
QUnit.done(this.onDone.bind(this));
}

prepTestEnd (parentName, parentNames, details) {
prepTestEnd (suiteName, parentNames, details) {
const testEnd = this.testEnds[details.testId] = {
name: details.name,
parentName: parentName,
suiteName: suiteName,
fullName: [...parentNames, details.name],
// Placeholders, populated by onTestDone() and onLog()
status: null,
Expand All @@ -45,22 +45,18 @@ module.exports = class QUnitAdapter extends EventEmitter {
processModule (qunitModule) {
const fullName = qunitModule.name.split(this.delim);
const name = fullName.slice(-1)[0];
const parentName = fullName.length >= 2 ? fullName.slice(-2, -1)[0] : null;

const childTests = qunitModule.tests.map((details) => {
return this.prepTestEnd(name, fullName, details);
});

return {
testEnd: {
suiteEnd: {
name,
parentName,
fullName,
// Placeholders, populated by emitTests()
status: null,
runtime: null,
errors: [],
assertions: []
runtime: null
},
childTests,
childModules: []
Expand All @@ -83,7 +79,7 @@ module.exports = class QUnitAdapter extends EventEmitter {
modules = this.QUnit.config.modules;
}

// Prepare all testEnd leafs
// Prepare all suiteEnd leafs
modules = modules.map(this.processModule.bind(this));

// For CRI, each module will be represented as a wrapper test
Expand All @@ -94,10 +90,10 @@ module.exports = class QUnitAdapter extends EventEmitter {
// module and add the current module to it as a child, among the test leafs.
const globalModules = [];
modules.forEach((mod) => {
if (mod.testEnd.parentName !== null) {
const parentFullName = mod.testEnd.fullName.slice(0, -1);
if (mod.suiteEnd.fullName.length > 1) {
const parentFullName = mod.suiteEnd.fullName.slice(0, -1);
modules.forEach((otherMod) => {
if (otherMod.testEnd.fullName.join(this.delim) === parentFullName.join(this.delim)) {
if (otherMod.suiteEnd.fullName.join(this.delim) === parentFullName.join(this.delim)) {
otherMod.childModules.push(mod);
}
});
Expand All @@ -115,7 +111,10 @@ module.exports = class QUnitAdapter extends EventEmitter {
});

const emitModule = (mod) => {
this.emit('testStart', helpers.createTestStart(mod.testEnd));
this.emit('suiteStart', {
name: mod.suiteEnd.name,
fullName: mod.suiteEnd.fullName.slice()
});

mod.childTests.forEach((testEnd) => {
this.emit('testStart', helpers.createTestStart(testEnd));
Expand All @@ -125,18 +124,18 @@ module.exports = class QUnitAdapter extends EventEmitter {

// This is non-recursive and can be because we emit modules in the original
// depth-first execution order. We fill in the status/runtime placeholders
// for the testEnd object of a nested module, and then later a parent module
// follows and sees that child testEnd object by reference and can propagate
// for the suiteEnd object of a nested module, and then later a parent module
// follows and sees that child suiteEnd object by reference and can propagate
// and aggregate the information further.
const helperData = helpers.aggregateTests([
...mod.childTests,
...mod.childModules.map(child => child.testEnd)
...mod.childModules.map(child => child.suiteEnd)
]);
mod.testEnd.status = helperData.status;
mod.testEnd.runtime = helperData.runtime;
mod.suiteEnd.status = helperData.status;
mod.suiteEnd.runtime = helperData.runtime;

this.moduleEnds.push(mod.testEnd);
this.emit('testEnd', mod.testEnd);
this.moduleEnds.push(mod.suiteEnd);
this.emit('suiteEnd', mod.suiteEnd);
};
this.globalModules.forEach(emitModule);
}
Expand All @@ -146,7 +145,7 @@ module.exports = class QUnitAdapter extends EventEmitter {

this.emit('runStart', {
name: null,
counts: {
testCounts: {
total: this.totalBegin
}
});
Expand Down Expand Up @@ -199,7 +198,7 @@ module.exports = class QUnitAdapter extends EventEmitter {
this.emit('runEnd', {
name: null,
status: helperData.status,
counts: helperData.counts,
testCounts: helperData.testCounts,
runtime: details.runtime || null
});
}
Expand Down
8 changes: 4 additions & 4 deletions lib/helpers.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
function aggregateTests (all) {
const counts = {
const testCounts = {
passed: all.filter((test) => test.status === 'passed').length,
failed: all.filter((test) => test.status === 'failed').length,
skipped: all.filter((test) => test.status === 'skipped').length,
todo: all.filter((test) => test.status === 'todo').length,
total: all.length
};
const status = counts.failed ? 'failed' : 'passed';
const status = testCounts.failed ? 'failed' : 'passed';

let runtime = 0;
all.forEach((test) => {
Expand All @@ -15,15 +15,15 @@ function aggregateTests (all) {

return {
status,
counts,
testCounts,
runtime
};
}

function createTestStart (testEnd) {
return {
name: testEnd.name,
parentName: testEnd.parentName,
suiteName: testEnd.suiteName,
fullName: testEnd.fullName.slice()
};
}
Expand Down
Loading

0 comments on commit 53432e5

Please sign in to comment.