Skip to content

Commit e5f2e93

Browse files
committed
TapeAdapter: Add new adapter for tape
Ref #118.
1 parent 05fc407 commit e5f2e93

File tree

7 files changed

+429
-3
lines changed

7 files changed

+429
-3
lines changed

index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const EventEmitter = require('events');
22
const QUnitAdapter = require('./lib/adapters/QUnitAdapter.js');
33
const JasmineAdapter = require('./lib/adapters/JasmineAdapter.js');
44
const MochaAdapter = require('./lib/adapters/MochaAdapter.js');
5+
const TapeAdapter = require('./lib/adapters/TapeAdapter.js');
56
const TapReporter = require('./lib/reporters/TapReporter.js');
67
const ConsoleReporter = require('./lib/reporters/ConsoleReporter.js');
78
const SummaryReporter = require('./lib/reporters/SummaryReporter.js');
@@ -14,6 +15,7 @@ module.exports = {
1415
QUnitAdapter,
1516
JasmineAdapter,
1617
MochaAdapter,
18+
TapeAdapter,
1719
TapReporter,
1820
ConsoleReporter,
1921
SummaryReporter,

lib/adapters/TapeAdapter.js

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
const EventEmitter = require('events');
2+
3+
module.exports = class TapeAdapter extends EventEmitter {
4+
/**
5+
* Unlike other adapters, this adapter ends up disabling the default
6+
* reporter of its framework (in this case, Tape's TAP reporter to
7+
* console.log). This is the default Tape behaviour, and we choose not to
8+
* change that. If you wish to enable Tape's default reporter also, and
9+
* e.g. use CRI only for additional reports to network or artefact files,
10+
* then run `tape.createStream().pipe(process.stdout);` to have both.
11+
*
12+
* @param {Tape} tape
13+
*/
14+
constructor (tape) {
15+
super();
16+
17+
// TODO: Unable to observe 'prerun' event for some reason.
18+
let started = false;
19+
let runStartTime;
20+
let runStatus = 'passed';
21+
const runCounts = { passed: 0, failed: 0, skipped: 0, todo: 0, total: 0 };
22+
const startOnce = () => {
23+
if (!started) {
24+
started = true;
25+
this.emit('runStart', { name: null, counts: { total: null } });
26+
runStartTime = new Date().getTime();
27+
}
28+
};
29+
30+
let fakeTestId = -1;
31+
const activeTests = {};
32+
const handleRow = (row) => {
33+
let test;
34+
switch (row.type) {
35+
// {type: test, name: '…', id: 0, skip: false, todo: false}
36+
// {type: test, name: '…', id: 1, skip: false, todo: false, parent: 0}
37+
case 'test':
38+
test = activeTests[row.id] = {
39+
startTime: new Date().getTime(),
40+
name: row.name,
41+
parentName: row.parent ? activeTests[row.parent].name : null,
42+
fullName: row.parent ? [...activeTests[row.parent].fullName, row.name] : [row.name],
43+
status: row.skip ? 'skipped' : (row.todo ? 'todo' : 'passed'),
44+
assertions: [],
45+
errors: [],
46+
parent: row.parent ? activeTests[row.parent] : null
47+
};
48+
this.emit('testStart', {
49+
name: test.name,
50+
parentName: test.parentName,
51+
fullName: test.fullName
52+
});
53+
break;
54+
55+
// {type: 'end', test: 0}
56+
case 'end':
57+
test = activeTests[row.test];
58+
delete activeTests[row.test];
59+
this.emit('testEnd', {
60+
name: test.name,
61+
parentName: test.parentName,
62+
fullName: test.fullName,
63+
status: test.status,
64+
assertions: test.assertions,
65+
errors: test.errors,
66+
runtime: test.status === 'skipped' ? null : new Date().getTime() - test.startTime
67+
});
68+
runCounts.total++;
69+
runCounts[test.status]++;
70+
if (test.status === 'failed') {
71+
if (test.parent) {
72+
test.parent.status = test.status;
73+
}
74+
runStatus = 'failed';
75+
}
76+
break;
77+
78+
// {type: 'assert', test: 0, ok: true, skip: false, name: '…', actual: '…', expected: '…', error: Error}
79+
case 'assert':
80+
if (row.skip) {
81+
// Replay as skipped test, ref https://github.com/substack/tape/issues/545
82+
const testId = fakeTestId--;
83+
handleRow({
84+
type: 'test',
85+
name: row.name,
86+
id: testId,
87+
skip: row.skip,
88+
todo: row.todo,
89+
parent: row.test
90+
});
91+
handleRow({ type: 'end', test: testId });
92+
return;
93+
}
94+
95+
activeTests[row.test].assertions.push({
96+
passed: row.ok,
97+
message: row.name
98+
});
99+
if (!row.ok) {
100+
if (!row.todo) {
101+
activeTests[row.test].status = 'failed';
102+
}
103+
activeTests[row.test].errors.push({
104+
passed: row.ok,
105+
message: row.name,
106+
// actual and expected are optional, e.g. not set for t.fail()
107+
actual: row.actual,
108+
expected: row.expected,
109+
stack: (row.error && row.error.stack) || null
110+
});
111+
}
112+
break;
113+
}
114+
};
115+
116+
const stream = tape.createStream({ objectMode: true });
117+
stream.on('data', (row) => {
118+
startOnce();
119+
handleRow(row);
120+
});
121+
stream.on('end', (row) => {
122+
startOnce();
123+
if (row) {
124+
handleRow(row);
125+
}
126+
this.emit('runEnd', {
127+
name: null,
128+
status: runStatus,
129+
counts: runCounts,
130+
runtime: new Date().getTime() - runStartTime
131+
});
132+
});
133+
}
134+
};

0 commit comments

Comments
 (0)