Skip to content

Commit e697629

Browse files
BarryThePenguinsindresorhus
authored andcommitted
Close #565 PR: Add todo test modifier. Fixes #563
1 parent d967956 commit e697629

File tree

14 files changed

+234
-13
lines changed

14 files changed

+234
-13
lines changed

api.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Api.prototype._reset = function () {
5050
this.exceptionCount = 0;
5151
this.passCount = 0;
5252
this.skipCount = 0;
53+
this.todoCount = 0;
5354
this.failCount = 0;
5455
this.fileCount = 0;
5556
this.testCount = 0;
@@ -217,7 +218,7 @@ Api.prototype.run = function (files) {
217218
});
218219

219220
return {
220-
stats: {passCount: 0, skipCount: 0, failCount: 0},
221+
stats: {passCount: 0, skipCount: 0, todoCount: 0, failCount: 0},
221222
tests: []
222223
};
223224
});
@@ -244,6 +245,7 @@ Api.prototype.run = function (files) {
244245

245246
self.passCount = sum(self.stats, 'passCount');
246247
self.skipCount = sum(self.stats, 'skipCount');
248+
self.todoCount = sum(self.stats, 'todoCount');
247249
self.failCount = sum(self.stats, 'failCount');
248250
});
249251
};

lib/colors.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var chalk = require('chalk');
44
module.exports = {
55
error: chalk.red,
66
skip: chalk.yellow,
7+
todo: chalk.blue,
78
pass: chalk.green,
89
duration: chalk.gray.dim,
910
stack: chalk.red

lib/reporters/mini.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ MiniReporter.prototype.reset = function () {
2525
this.passCount = 0;
2626
this.failCount = 0;
2727
this.skipCount = 0;
28+
this.todoCount = 0;
2829
this.rejectionCount = 0;
2930
this.exceptionCount = 0;
3031
this.currentStatus = '';
@@ -36,7 +37,10 @@ MiniReporter.prototype.test = function (test) {
3637
var status = '';
3738
var title;
3839

39-
if (test.skip) {
40+
if (test.todo) {
41+
title = colors.todo('- ' + test.title);
42+
this.todoCount++;
43+
} else if (test.skip) {
4044
title = colors.skip('- ' + test.title);
4145
this.skipCount++;
4246
} else if (test.error) {
@@ -80,6 +84,10 @@ MiniReporter.prototype.finish = function () {
8084
status += ' ' + colors.skip(this.skipCount, 'skipped');
8185
}
8286

87+
if (this.todoCount > 0) {
88+
status += ' ' + colors.todo(this.todoCount, 'todo');
89+
}
90+
8391
if (this.failCount > 0) {
8492
status += ' ' + colors.error(this.failCount, 'failed');
8593
}

lib/reporters/tap.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ TapReporter.prototype.start = function () {
2727
TapReporter.prototype.test = function (test) {
2828
var output;
2929

30+
var directive = '';
31+
var passed = test.todo ? 'not ok' : 'ok';
32+
33+
if (test.todo) {
34+
directive = '# TODO';
35+
} else if (test.skip) {
36+
directive = '# SKIP';
37+
}
38+
3039
if (test.error) {
3140
output = [
3241
'# ' + test.title,
@@ -41,7 +50,7 @@ TapReporter.prototype.test = function (test) {
4150
} else {
4251
output = [
4352
'# ' + test.title,
44-
format('ok %d - %s', ++this.i, test.title)
53+
format('%s %d - %s %s', passed, ++this.i, test.title, directive).trim()
4554
];
4655
}
4756

lib/reporters/verbose.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ VerboseReporter.prototype.test = function (test) {
2121
return ' ' + colors.error(figures.cross) + ' ' + test.title + ' ' + colors.error(test.error.message);
2222
}
2323

24-
if (test.skip) {
24+
if (test.todo) {
25+
return ' ' + colors.todo('- ' + test.title);
26+
} else if (test.skip) {
2527
return ' ' + colors.skip('- ' + test.title);
2628
}
2729

@@ -72,6 +74,10 @@ VerboseReporter.prototype.finish = function () {
7274
output += ' ' + colors.skip(this.api.skipCount, plur('test', this.api.skipCount), 'skipped') + '\n';
7375
}
7476

77+
if (this.api.todoCount > 0) {
78+
output += ' ' + colors.todo(this.api.todoCount, plur('test', this.api.todoCount), 'todo') + '\n';
79+
}
80+
7581
if (this.api.rejectionCount > 0) {
7682
output += ' ' + colors.error(this.api.rejectionCount, 'unhandled', plur('rejection', this.api.rejectionCount)) + '\n';
7783
}

lib/runner.js

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ var Promise = require('bluebird');
55
var optionChain = require('option-chain');
66
var TestCollection = require('./test-collection');
77

8+
function noop() {}
9+
810
var chainableMethods = {
911
spread: true,
1012
defaults: {
1113
type: 'test',
1214
serial: false,
1315
exclusive: false,
1416
skipped: false,
17+
todo: false,
1518
callback: false
1619
},
1720
chainableMethods: {
@@ -20,6 +23,7 @@ var chainableMethods = {
2023
before: {type: 'before'},
2124
after: {type: 'after'},
2225
skip: {skipped: true},
26+
todo: {todo: true},
2327
only: {exclusive: true},
2428
beforeEach: {type: 'beforeEach'},
2529
afterEach: {type: 'afterEach'},
@@ -51,6 +55,16 @@ optionChain(chainableMethods, function (opts, title, fn) {
5155
title = null;
5256
}
5357

58+
if (opts.todo) {
59+
fn = noop;
60+
61+
if (typeof title !== 'string') {
62+
throw new TypeError('`todo` tests require a title');
63+
}
64+
} else if (opts.skipped && typeof fn !== 'function') {
65+
throw new TypeError('Expected a function. Use `test.todo()` for tests without a function.');
66+
}
67+
5468
if (this._serial) {
5569
opts.serial = true;
5670
}
@@ -63,10 +77,14 @@ optionChain(chainableMethods, function (opts, title, fn) {
6377
}, Runner.prototype);
6478

6579
Runner.prototype._addTestResult = function (result) {
66-
if (result.result.metadata.type === 'test') {
80+
var test = result.result;
81+
82+
if (test.metadata.type === 'test') {
6783
this.stats.testCount++;
6884

69-
if (result.result.metadata.skipped) {
85+
if (test.metadata.todo) {
86+
this.stats.todoCount++;
87+
} else if (test.metadata.skipped) {
7088
this.stats.skipCount++;
7189
}
7290
}
@@ -75,14 +93,13 @@ Runner.prototype._addTestResult = function (result) {
7593
this.stats.failCount++;
7694
}
7795

78-
var test = result.result;
79-
8096
var props = {
8197
duration: test.duration,
8298
title: test.title,
8399
error: result.reason,
84100
type: test.metadata.type,
85-
skip: test.metadata.skipped
101+
skip: test.metadata.skipped,
102+
todo: test.metadata.todo
86103
};
87104

88105
this.emit('test', props);
@@ -93,6 +110,7 @@ Runner.prototype.run = function (options) {
93110
failCount: 0,
94111
passCount: 0,
95112
skipCount: 0,
113+
todoCount: 0,
96114
testCount: 0
97115
};
98116

@@ -103,6 +121,6 @@ Runner.prototype.run = function (options) {
103121
this.tests.on('test', this._addTestResult);
104122

105123
return Promise.resolve(this.tests.build(this._bail).run()).then(function () {
106-
stats.passCount = stats.testCount - stats.failCount - stats.skipCount;
124+
stats.passCount = stats.testCount - stats.failCount - stats.skipCount - stats.todoCount;
107125
});
108126
};

lib/test-collection.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ TestCollection.prototype._buildHooks = function (hooks, testTitle, context) {
111111
return hooks.map(function (hook) {
112112
var test = this._buildHook(hook, testTitle, context);
113113

114-
if (hook.metadata.skipped) {
114+
if (hook.metadata.skipped || hook.metadata.todo) {
115115
return this._skippedTest(test);
116116
}
117117

readme.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,14 +248,22 @@ test.only('will be run', t => {
248248

249249
### Skip-tests
250250

251-
Skip-tests are shown in the output as skipped but never run.
251+
Skip-tests are shown in the output as skipped but never run. Skip-tests require a function.
252252

253253
```js
254254
test.skip('will not be run', t => {
255255
t.fail();
256256
});
257257
```
258258

259+
### Todo-tests
260+
261+
Todo-tests, like skip-tests, are shown in the output but are never run. They can be useful for planning future tests. Todo-tests require only a test title.
262+
263+
```js
264+
test.todo('will think about writing this later');
265+
```
266+
259267
### Before & after hooks
260268

261269
When setup and/or teardown is required, you can use `test.before()` and `test.after()`,
@@ -478,6 +486,7 @@ AVA automatically removes unrelated lines in stack traces, allowing you to find
478486
### test.cb([title], body)
479487
### test.only([title], body)
480488
### test.skip([title], body)
489+
### test.todo(title)
481490
### test.before([title], body)
482491
### test.after([title], body)
483492
### test.beforeEach([title], body)

test/api.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,3 +664,22 @@ test('emits dependencies for test files', function (t) {
664664
api.on('error', function () {});
665665
result.catch(function () {});
666666
});
667+
668+
test('verify test count', function (t) {
669+
t.plan(8);
670+
671+
var api = new Api();
672+
673+
t.is(api.passCount, 0);
674+
t.is(api.failCount, 0);
675+
t.is(api.skipCount, 0);
676+
t.is(api.todoCount, 0);
677+
678+
api.run([path.join(__dirname, 'fixture/test-count.js')])
679+
.then(function () {
680+
t.is(api.passCount, 1);
681+
t.is(api.failCount, 1);
682+
t.is(api.skipCount, 1);
683+
t.is(api.todoCount, 1);
684+
});
685+
});

test/fixture/test-count.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import test from '../../';
2+
3+
test('passCount', t => {
4+
t.pass();
5+
});
6+
7+
test('failCount', t => {
8+
t.fail();
9+
});
10+
11+
test.skip('skipCount', t => {
12+
t.pass();
13+
});
14+
15+
test.todo('todoCount');

test/reporters/mini.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ test('skipped test', function (t) {
6969
t.end();
7070
});
7171

72+
test('todo test', function (t) {
73+
var reporter = miniReporter();
74+
75+
var actualOutput = reporter.test({
76+
title: 'todo',
77+
skip: true,
78+
todo: true
79+
});
80+
81+
var expectedOutput = [
82+
' ' + chalk.blue('- todo'),
83+
'',
84+
''
85+
].join('\n');
86+
87+
t.is(actualOutput, expectedOutput);
88+
t.end();
89+
});
90+
7291
test('results with passing tests', function (t) {
7392
var reporter = miniReporter();
7493
reporter.passCount = 1;
@@ -100,6 +119,22 @@ test('results with skipped tests', function (t) {
100119
t.end();
101120
});
102121

122+
test('results with todo tests', function (t) {
123+
var reporter = miniReporter();
124+
reporter.passCount = 0;
125+
reporter.todoCount = 1;
126+
reporter.failCount = 0;
127+
128+
var actualOutput = reporter.finish();
129+
var expectedOutput = [
130+
'\n ' + chalk.blue('1 todo'),
131+
''
132+
].join('\n');
133+
134+
t.is(actualOutput, expectedOutput);
135+
t.end();
136+
});
137+
103138
test('results with passing skipped tests', function (t) {
104139
var reporter = miniReporter();
105140
reporter.passCount = 1;

test/reporters/tap.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,40 @@ test('results does not show skipped tests if there are none', function (t) {
146146
t.is(actualOutput, expectedOutput);
147147
t.end();
148148
});
149+
150+
test('todo test', function (t) {
151+
var reporter = tapReporter();
152+
153+
var actualOutput = reporter.test({
154+
title: 'should think about doing this',
155+
passed: false,
156+
skip: true,
157+
todo: true
158+
});
159+
160+
var expectedOutput = [
161+
'# should think about doing this',
162+
'not ok 1 - should think about doing this # TODO'
163+
].join('\n');
164+
165+
t.is(actualOutput, expectedOutput);
166+
t.end();
167+
});
168+
169+
test('skip test', function (t) {
170+
var reporter = tapReporter();
171+
172+
var actualOutput = reporter.test({
173+
title: 'skipped',
174+
passed: true,
175+
skip: true
176+
});
177+
178+
var expectedOutput = [
179+
'# skipped',
180+
'ok 1 - skipped # SKIP'
181+
].join('\n');
182+
183+
t.is(actualOutput, expectedOutput);
184+
t.end();
185+
});

0 commit comments

Comments
 (0)