-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve metadata checks #980
Changes from 5 commits
76b4066
b50c365
824d936
238bef2
093060b
3d04ff2
e935033
718cf6c
514440b
5863914
35aa667
274307a
aca3818
5f2a5ea
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
'use strict'; | ||
|
||
function validate(title, fn, metadata) { | ||
if (metadata.type !== 'test') { | ||
if (metadata.exclusive) { | ||
return '`only` is only for tests and cannot be used with hooks'; | ||
} | ||
|
||
if (metadata.failing) { | ||
return '`failing` is only for tests and cannot be used with hooks'; | ||
} | ||
|
||
if (metadata.todo) { | ||
return '`todo` is only for documentation of future tests and cannot be used with hooks'; | ||
} | ||
} | ||
|
||
if (metadata.todo) { | ||
if (typeof fn === 'function') { | ||
return '`todo` tests are not allowed to have an implementation. Use ' + | ||
'`test.skip()` for tests with an implementation.'; | ||
} | ||
|
||
if (typeof title !== 'string') { | ||
return '`todo` tests require a title'; | ||
} | ||
|
||
if (metadata.skipped || metadata.failing || metadata.exclusive) { | ||
return '`todo` tests are just for documentation and cannot be used with skip, only, or failing'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep the comma :-) I like Oxford Commas. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For consistency, should use backticks around There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add backticks around I've just clarified with @sindresorhus that's what he meant to say originally: #980 (comment) |
||
} | ||
} else if (typeof fn !== 'function') { | ||
return 'Expected an implementation. Use `test.todo()` for tests without an implementation.'; | ||
} | ||
|
||
if (metadata.always) { | ||
if (!(metadata.type === 'after' || metadata.type === 'afterEach')) { | ||
return '`always` can only be used with `after` and `afterEach`'; | ||
} | ||
} | ||
|
||
if (metadata.skipped && metadata.exclusive) { | ||
return '`only` tests cannot be skipped'; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
module.exports = validate; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -319,6 +319,36 @@ test('only test', function (t) { | |
}); | ||
}); | ||
|
||
test('throws if you try to set a hook as exclusive', function (t) { | ||
var runner = new Runner(); | ||
|
||
t.throws(function () { | ||
runner.beforeEach.only('', noop); | ||
}, {message: '`only` is only for tests and cannot be used with hooks'}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is better as: t.throws(() => {
runner.beforeEach.only('', noop);
}, TypeError, '`only` is only for tests and cannot be used with hooks'); Same goes for the other tests. See http://www.node-tap.org/asserts/#tthrowsfn-expectederror-message-extrafor specifics. |
||
|
||
t.end(); | ||
}); | ||
|
||
test('throws if you try to set a before hook as always', function (t) { | ||
var runner = new Runner(); | ||
|
||
t.throws(function () { | ||
runner.before.always('', noop); | ||
}, {message: '`always` can only be used with `after` and `afterEach`'}); | ||
|
||
t.end(); | ||
}); | ||
|
||
test('throws if you try to set a test as always', function (t) { | ||
var runner = new Runner(); | ||
|
||
t.throws(function () { | ||
runner.test.always('', noop); | ||
}, {message: '`always` can only be used with `after` and `afterEach`'}); | ||
|
||
t.end(); | ||
}); | ||
|
||
test('runOnlyExclusive option test', function (t) { | ||
t.plan(1); | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
'use strict'; | ||
|
||
var test = require('tap').test; | ||
var validate = require('../lib/validate-test'); | ||
|
||
var noop = function () {}; | ||
|
||
test('validate accepts basic test', function (t) { | ||
t.type(validate('basic test', noop, {type: 'test'}), 'null'); | ||
t.end(); | ||
}); | ||
|
||
test('validate rejects tests without implementations except `todo` tests', function (t) { | ||
var errorMessage = 'Expected an implementation. Use `test.todo()` for tests without an implementation.'; | ||
|
||
t.deepEquals(validate('test', null, {type: 'test'}), errorMessage); | ||
t.deepEquals(validate('before', null, {type: 'before'}), errorMessage); | ||
t.deepEquals(validate('beforeEach', null, {type: 'beforeEach'}), errorMessage); | ||
t.deepEquals(validate('after', null, {type: 'after'}), errorMessage); | ||
t.deepEquals(validate('afterEach', null, {type: 'afterEach'}), errorMessage); | ||
t.end(); | ||
}); | ||
|
||
test('validate accepts proper todo', function (t) { | ||
t.type(validate('proper todo', null, {todo: true, type: 'test'}), 'null'); | ||
t.end(); | ||
}); | ||
|
||
test('validate rejects todo with function', function (t) { | ||
var errorMessage = '`todo` tests are not allowed to have an implementation. Use ' + | ||
'`test.skip()` for tests with an implementation.'; | ||
|
||
t.deepEquals(validate('todo with function', noop, {todo: true, type: 'test'}), errorMessage); | ||
t.end(); | ||
}); | ||
|
||
test('validate rejects todo without title', function (t) { | ||
var errorMessage = '`todo` tests require a title'; | ||
|
||
t.deepEquals(validate(null, null, {todo: true, type: 'test'}), errorMessage); | ||
t.end(); | ||
}); | ||
|
||
test('validate rejects todo with failing, skipped, or exclusive', function (t) { | ||
var errorMessage = '`todo` tests are just for documentation and cannot be used with skip, only, or failing'; | ||
|
||
t.deepEquals(validate('failing', null, {todo: true, failing: true, type: 'test'}), errorMessage); | ||
t.deepEquals(validate('skipped', null, {todo: true, skipped: true, type: 'test'}), errorMessage); | ||
t.deepEquals(validate('exclusive', null, {todo: true, exclusive: true, type: 'test'}), errorMessage); | ||
t.end(); | ||
}); | ||
|
||
test('validate rejects todo when it\'s not a test', function (t) { | ||
var errorMessage = '`todo` is only for documentation of future tests and cannot be used with hooks'; | ||
|
||
t.deepEquals(validate('before', null, {todo: true, type: 'before'}), errorMessage); | ||
t.deepEquals(validate('beforeEach', null, {todo: true, type: 'beforeEach'}), errorMessage); | ||
t.deepEquals(validate('after', null, {todo: true, type: 'after'}), errorMessage); | ||
t.deepEquals(validate('afterEach', null, {todo: true, type: 'afterEach'}), errorMessage); | ||
t.end(); | ||
}); | ||
|
||
test('validate rejects skipped exclusive', function (t) { | ||
var errorMessage = '`only` tests cannot be skipped'; | ||
|
||
t.deepEquals(validate('skipped exclusive', noop, {exclusive: true, skipped: true, type: 'test'}), errorMessage); | ||
t.end(); | ||
}); | ||
|
||
test('validate rejects failing on non-tests', function (t) { | ||
var errorMessage = '`failing` is only for tests and cannot be used with hooks'; | ||
|
||
t.type(validate('before', noop, {failing: true, type: 'test'}), 'null'); | ||
t.deepEquals(validate('before', noop, {failing: true, type: 'before'}), errorMessage); | ||
t.deepEquals(validate('beforeEach', noop, {failing: true, type: 'beforeEach'}), errorMessage); | ||
t.deepEquals(validate('after', noop, {failing: true, type: 'after'}), errorMessage); | ||
t.deepEquals(validate('afterEach', noop, {failing: true, type: 'afterEach'}), errorMessage); | ||
t.end(); | ||
}); | ||
|
||
test('validate rejects skip on non-tests', function (t) { | ||
var errorMessage = '`only` is only for tests and cannot be used with hooks'; | ||
|
||
t.type(validate('before', noop, {exclusive: true, type: 'test'}), 'null'); | ||
t.deepEquals(validate('before', noop, {exclusive: true, type: 'before'}), errorMessage); | ||
t.deepEquals(validate('beforeEach', noop, {exclusive: true, type: 'beforeEach'}), errorMessage); | ||
t.deepEquals(validate('after', noop, {exclusive: true, type: 'after'}), errorMessage); | ||
t.deepEquals(validate('afterEach', noop, {exclusive: true, type: 'afterEach'}), errorMessage); | ||
t.end(); | ||
}); | ||
|
||
test('validate only allows always on `after` and `afterEach`', function (t) { | ||
var errorMessage = '`always` can only be used with `after` and `afterEach`'; | ||
|
||
t.deepEquals(validate('before', noop, {always: true, type: 'test'}), errorMessage); | ||
t.deepEquals(validate('before', noop, {always: true, type: 'before'}), errorMessage); | ||
t.deepEquals(validate('beforeEach', noop, {always: true, type: 'beforeEach'}), errorMessage); | ||
t.type(validate('after', noop, {always: true, type: 'after'}), 'null'); | ||
t.type(validate('afterEach', noop, {always: true, type: 'afterEach'}), 'null'); | ||
t.end(); | ||
}); | ||
|
||
test('validate accepts skipping failing tests', function (t) { | ||
t.deepEquals(validate('before', noop, {failing: true, skipped: true, type: 'test'}), null); | ||
t.end(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the fact that hooks are "skipped" handled here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the issue, it was discussed that skipping hooks should be allowed. Do you think we shouldn't skip them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jfmengels I don't know what you meant here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't remember why I wrote that either 😅