Skip to content

Commit b8549df

Browse files
Guillaume Martignysindresorhus
authored andcommitted
Calling a .cb test with the first argument being a reference disables the rule (#234)
1 parent 0bdb6b4 commit b8549df

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

rules/test-ended.js

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,40 @@ const util = require('../util');
55

66
const create = context => {
77
const ava = createAvaRule();
8+
const hasCbModifier = () => ava.hasTestModifier('cb');
89
let endCalled = false;
910

1011
return ava.merge({
1112
MemberExpression: visitIf([
1213
ava.isInTestFile,
13-
ava.isInTestNode
14+
ava.isInTestNode,
15+
hasCbModifier
1416
])(node => {
15-
if (ava.hasTestModifier('cb') &&
16-
node.object.name === 't' &&
17+
if (node.object.name === 't' &&
1718
node.property.name === 'end'
1819
) {
1920
endCalled = true;
2021
}
2122
}),
22-
'CallExpression:exit': visitIf([
23+
CallExpression: visitIf([
2324
ava.isInTestFile,
24-
ava.isTestNode
25+
ava.isTestNode,
26+
hasCbModifier
2527
])(node => {
26-
if (!ava.hasTestModifier('cb')) {
27-
return;
28+
const firstArg = node.arguments[0];
29+
if (node.callee.property.name === 'cb' && firstArg.type === 'Identifier') {
30+
const scope = context.getScope();
31+
const exists = scope.references.some(ref => ref.identifier.name === firstArg.name);
32+
if (exists) {
33+
endCalled = true;
34+
}
2835
}
29-
36+
}),
37+
'CallExpression:exit': visitIf([
38+
ava.isInTestFile,
39+
ava.isTestNode,
40+
hasCbModifier
41+
])(node => {
3042
// Leaving test function
3143
if (endCalled) {
3244
endCalled = false;

test/test-ended.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ ruleTester.run('test-ended', rule, {
2222
header + 'test.cb.only(t => { t.end(); });',
2323
header + 'test.cb.skip.only(t => { t.end(); });',
2424
header + 'test.only.cb.skip(t => { t.end(); });',
25+
// Detecting that the called function has `end()` is not required #119
26+
header + 'const macro = t => {};\ntest.cb(macro);',
2527
// Shouldn't be triggered since it's not a callback test
2628
header + 'test(t => { t.pass(); });',
2729
// Shouldn't be triggered since it's not a test file
@@ -32,6 +34,11 @@ ruleTester.run('test-ended', rule, {
3234
code: header + 'test.cb(function (t) { t.pass(); });',
3335
errors
3436
},
37+
{
38+
// Detecting that the called function has `end()` can turn into a recursive resolution nightmare
39+
code: header + 'const macro = t => t.end();\ntest.cb((t) => macro(t));',
40+
errors
41+
},
3542
{
3643
code: header + 'test.cb(t => { t.pass(); });',
3744
errors

0 commit comments

Comments
 (0)