Skip to content

Commit 76860dd

Browse files
jamestalmagesindresorhus
authored andcommitted
Close #599 PR: Add busy indicator to mini reporter. Fixes #598
1 parent cac933e commit 76860dd

File tree

5 files changed

+144
-45
lines changed

5 files changed

+144
-45
lines changed

lib/reporters/mini.js

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,21 @@ var cliCursor = require('cli-cursor');
33
var lastLineTracker = require('last-line-stream/tracker');
44
var StringDecoder = require('string_decoder').StringDecoder;
55
var plur = require('plur');
6+
var spinners = require('cli-spinners');
7+
var chalk = require('chalk');
68
var colors = require('../colors');
79

810
function MiniReporter() {
911
if (!(this instanceof MiniReporter)) {
1012
return new MiniReporter();
1113
}
1214

15+
var spinnerDef = spinners.dots;
16+
this.spinnerFrames = spinnerDef.frames.map(function (c) {
17+
return chalk.gray.dim(c);
18+
});
19+
this.spinnerInterval = spinnerDef.interval;
20+
1321
this.reset();
1422
this.stream = process.stderr;
1523
this.stringDecoder = new StringDecoder();
@@ -18,23 +26,50 @@ function MiniReporter() {
1826
module.exports = MiniReporter;
1927

2028
MiniReporter.prototype.start = function () {
21-
return '';
29+
var self = this;
30+
this.interval = setInterval(function () {
31+
self.spinnerIndex = (self.spinnerIndex + 1) % self.spinnerFrames.length;
32+
self.write(self.prefix());
33+
}, this.spinnerInterval);
34+
return this.prefix('');
2235
};
2336

2437
MiniReporter.prototype.reset = function () {
38+
this.clearInterval();
2539
this.passCount = 0;
2640
this.failCount = 0;
2741
this.skipCount = 0;
2842
this.todoCount = 0;
2943
this.rejectionCount = 0;
3044
this.exceptionCount = 0;
3145
this.currentStatus = '';
46+
this.currentTest = '';
3247
this.statusLineCount = 0;
48+
this.spinnerIndex = 0;
3349
this.lastLineTracker = lastLineTracker();
3450
};
3551

52+
MiniReporter.prototype.spinnerChar = function () {
53+
return this.spinnerFrames[this.spinnerIndex];
54+
};
55+
56+
MiniReporter.prototype.clearInterval = function () {
57+
clearInterval(this.interval);
58+
this.interval = null;
59+
};
60+
3661
MiniReporter.prototype.test = function (test) {
37-
var status = '';
62+
return this.prefix(this._test(test));
63+
};
64+
65+
MiniReporter.prototype.prefix = function (str) {
66+
str = str || this.currentTest;
67+
this.currentTest = str;
68+
// The space before the newline is required for proper formatting. (Not sure why).
69+
return ' \n ' + this.spinnerChar() + ' ' + str;
70+
};
71+
72+
MiniReporter.prototype._test = function (test) {
3873
var title;
3974

4075
if (test.todo) {
@@ -51,18 +86,7 @@ MiniReporter.prototype.test = function (test) {
5186
this.passCount++;
5287
}
5388

54-
status += ' ' + title;
55-
status += '\n\n';
56-
57-
if (this.passCount > 0) {
58-
status += ' ' + colors.pass(this.passCount, 'passed');
59-
}
60-
61-
if (this.failCount > 0) {
62-
status += ' ' + colors.error(this.failCount, 'failed');
63-
}
64-
65-
return status;
89+
return title + '\n' + this.reportCounts();
6690
};
6791

6892
MiniReporter.prototype.unhandledError = function (err) {
@@ -73,31 +97,38 @@ MiniReporter.prototype.unhandledError = function (err) {
7397
}
7498
};
7599

76-
MiniReporter.prototype.finish = function () {
77-
var status = '\n';
100+
MiniReporter.prototype.reportCounts = function () {
101+
var status = '';
78102

79103
if (this.passCount > 0) {
80-
status += ' ' + colors.pass(this.passCount, 'passed');
104+
status += '\n ' + colors.pass(this.passCount, 'passed');
81105
}
82106

83107
if (this.skipCount > 0) {
84-
status += ' ' + colors.skip(this.skipCount, 'skipped');
108+
status += '\n ' + colors.skip(this.skipCount, 'skipped');
85109
}
86110

87111
if (this.todoCount > 0) {
88-
status += ' ' + colors.todo(this.todoCount, 'todo');
112+
status += '\n ' + colors.todo(this.todoCount, 'todo');
89113
}
90114

91115
if (this.failCount > 0) {
92-
status += ' ' + colors.error(this.failCount, 'failed');
116+
status += '\n ' + colors.error(this.failCount, 'failed');
93117
}
94118

119+
return status.length ? status : '\n';
120+
};
121+
122+
MiniReporter.prototype.finish = function () {
123+
this.clearInterval();
124+
var status = this.reportCounts();
125+
95126
if (this.rejectionCount > 0) {
96-
status += '\n ' + colors.error(this.rejectionCount, plur('rejection', this.rejectionCount));
127+
status += '\n ' + colors.error(this.rejectionCount, plur('rejection', this.rejectionCount));
97128
}
98129

99130
if (this.exceptionCount > 0) {
100-
status += '\n ' + colors.error(this.exceptionCount, plur('exception', this.exceptionCount));
131+
status += '\n ' + colors.error(this.exceptionCount, plur('exception', this.exceptionCount));
101132
}
102133

103134
var i = 0;

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
"caching-transform": "^1.0.0",
8989
"chalk": "^1.0.0",
9090
"cli-cursor": "^1.0.2",
91+
"cli-spinners": "^0.1.2",
9192
"co-with-promise": "^4.6.0",
9293
"common-path-prefix": "^1.0.0",
9394
"convert-source-map": "^1.1.2",

test/reporters/mini.js

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,24 @@
22
var chalk = require('chalk');
33
var test = require('tap').test;
44
var AvaError = require('../../lib/ava-error');
5-
var miniReporter = require('../../lib/reporters/mini');
5+
var _miniReporter = require('../../lib/reporters/mini');
66
var beautifyStack = require('../../lib/beautify-stack');
77

8+
function miniReporter() {
9+
var reporter = _miniReporter();
10+
reporter.start = function () {
11+
return '';
12+
};
13+
return reporter;
14+
}
15+
816
process.stderr.setMaxListeners(50);
917

1018
test('start', function (t) {
11-
var reporter = miniReporter();
19+
var reporter = _miniReporter();
1220

13-
t.is(reporter.start(), '');
21+
t.is(reporter.start(), ' \n ⠋ ');
22+
reporter.clearInterval();
1423
t.end();
1524
});
1625

@@ -22,9 +31,10 @@ test('passing test', function (t) {
2231
});
2332

2433
var expectedOutput = [
25-
' ' + chalk.green('passed'),
34+
' ',
35+
' ⠋ ' + chalk.green('passed'),
2636
'',
27-
' ' + chalk.green('1 passed')
37+
' ' + chalk.green('1 passed')
2838
].join('\n');
2939

3040
t.is(actualOutput, expectedOutput);
@@ -42,9 +52,58 @@ test('failing test', function (t) {
4252
});
4353

4454
var expectedOutput = [
45-
' ' + chalk.red('failed'),
55+
' ',
56+
' ⠋ ' + chalk.red('failed'),
57+
'',
58+
' ' + chalk.red('1 failed')
59+
].join('\n');
60+
61+
t.is(actualOutput, expectedOutput);
62+
t.end();
63+
});
64+
65+
test('passing test after failing', function (t) {
66+
var reporter = miniReporter();
67+
68+
reporter.test({
69+
title: 'failed',
70+
error: {
71+
message: 'assertion failed'
72+
}
73+
});
74+
75+
var actualOutput = reporter.test({title: 'passed'});
76+
77+
var expectedOutput = [
78+
' ',
79+
' ⠋ ' + chalk.green('passed'),
80+
'',
81+
' ' + chalk.green('1 passed'),
82+
' ' + chalk.red('1 failed')
83+
].join('\n');
84+
85+
t.is(actualOutput, expectedOutput);
86+
t.end();
87+
});
88+
89+
test('failing test after passing', function (t) {
90+
var reporter = miniReporter();
91+
92+
reporter.test({title: 'passed'});
93+
94+
var actualOutput = reporter.test({
95+
title: 'failed',
96+
error: {
97+
message: 'assertion failed'
98+
}
99+
});
100+
101+
var expectedOutput = [
102+
' ',
103+
' ⠋ ' + chalk.red('failed'),
46104
'',
47-
' ' + chalk.red('1 failed')
105+
' ' + chalk.green('1 passed'),
106+
' ' + chalk.red('1 failed')
48107
].join('\n');
49108

50109
t.is(actualOutput, expectedOutput);
@@ -60,9 +119,10 @@ test('skipped test', function (t) {
60119
});
61120

62121
var expectedOutput = [
63-
' ' + chalk.yellow('- skipped'),
122+
' ',
123+
' ⠋ ' + chalk.yellow('- skipped'),
64124
'',
65-
''
125+
' ' + chalk.yellow('1 skipped')
66126
].join('\n');
67127

68128
t.is(actualOutput, expectedOutput);
@@ -79,9 +139,10 @@ test('todo test', function (t) {
79139
});
80140

81141
var expectedOutput = [
82-
' ' + chalk.blue('- todo'),
142+
' ',
143+
' ⠋ ' + chalk.blue('- todo'),
83144
'',
84-
''
145+
' ' + chalk.blue('1 todo')
85146
].join('\n');
86147

87148
t.is(actualOutput, expectedOutput);
@@ -95,7 +156,7 @@ test('results with passing tests', function (t) {
95156

96157
var actualOutput = reporter.finish();
97158
var expectedOutput = [
98-
'\n ' + chalk.green('1 passed'),
159+
'\n ' + chalk.green('1 passed'),
99160
''
100161
].join('\n');
101162

@@ -111,7 +172,7 @@ test('results with skipped tests', function (t) {
111172

112173
var actualOutput = reporter.finish();
113174
var expectedOutput = [
114-
'\n ' + chalk.yellow('1 skipped'),
175+
'\n ' + chalk.yellow('1 skipped'),
115176
''
116177
].join('\n');
117178

@@ -127,7 +188,7 @@ test('results with todo tests', function (t) {
127188

128189
var actualOutput = reporter.finish();
129190
var expectedOutput = [
130-
'\n ' + chalk.blue('1 todo'),
191+
'\n ' + chalk.blue('1 todo'),
131192
''
132193
].join('\n');
133194

@@ -143,8 +204,9 @@ test('results with passing skipped tests', function (t) {
143204
var output = reporter.finish().split('\n');
144205

145206
t.is(output[0], '');
146-
t.is(output[1], ' ' + chalk.green('1 passed') + ' ' + chalk.yellow('1 skipped'));
147-
t.is(output[2], '');
207+
t.is(output[1], ' ' + chalk.green('1 passed'));
208+
t.is(output[2], ' ' + chalk.yellow('1 skipped'));
209+
t.is(output[3], '');
148210
t.end();
149211
});
150212

@@ -164,8 +226,8 @@ test('results with passing tests and rejections', function (t) {
164226
var output = reporter.finish().split('\n');
165227

166228
t.is(output[0], '');
167-
t.is(output[1], ' ' + chalk.green('1 passed'));
168-
t.is(output[2], ' ' + chalk.red('1 rejection'));
229+
t.is(output[1], ' ' + chalk.green('1 passed'));
230+
t.is(output[2], ' ' + chalk.red('1 rejection'));
169231
t.is(output[3], '');
170232
t.is(output[4], ' ' + chalk.red('1. Unhandled Rejection'));
171233
t.match(output[5], /Error: failure/);
@@ -192,8 +254,8 @@ test('results with passing tests and exceptions', function (t) {
192254
var output = reporter.finish().split('\n');
193255

194256
t.is(output[0], '');
195-
t.is(output[1], ' ' + chalk.green('1 passed'));
196-
t.is(output[2], ' ' + chalk.red('2 exceptions'));
257+
t.is(output[1], ' ' + chalk.green('1 passed'));
258+
t.is(output[2], ' ' + chalk.red('2 exceptions'));
197259
t.is(output[3], '');
198260
t.is(output[4], ' ' + chalk.red('1. Uncaught Exception'));
199261
t.match(output[5], /Error: failure/);
@@ -220,7 +282,7 @@ test('results with errors', function (t) {
220282
var output = reporter.finish().split('\n');
221283

222284
t.is(output[0], '');
223-
t.is(output[1], ' ' + chalk.red('1 failed'));
285+
t.is(output[1], ' ' + chalk.red('1 failed'));
224286
t.is(output[2], '');
225287
t.is(output[3], ' ' + chalk.red('1. failed'));
226288
t.match(output[4], /failure/);

test/visual/lorem-ipsum.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ async function testFn(t) {
88
t.pass();
99
}
1010

11+
async function failFn(t) {
12+
await delay(40);
13+
t.fail();
14+
}
15+
1116
for (var i = 0; i < 400; i++) {
12-
test.serial('test number ' + i, testFn);
17+
test.serial('test number ' + i, i === 125 ? failFn : testFn);
1318
}

test/visual/run-visual-tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ run(
100100
'You should see the entire contents of the Gettysburg address.',
101101
'Three paragraphs with a blank line in between each.',
102102
'There should be no other blank lines within the speech text.',
103-
'The test counter should display "400 passed" at the bottom.'
103+
'The test counter should display "399 passed 1 failed" at the bottom.'
104104
]
105105
))
106106
;

0 commit comments

Comments
 (0)