Skip to content

Commit 1eb4114

Browse files
committed
fix(valid-expect-in-promise): bailout if done callback is present
1 parent 4bb3dca commit 1eb4114

File tree

2 files changed

+85
-24
lines changed

2 files changed

+85
-24
lines changed

src/rules/__tests__/valid-expect-in-promise.test.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@ const ruleTester = new TSESLint.RuleTester({
1212

1313
ruleTester.run('valid-expect-in-promise', rule, {
1414
valid: [
15-
// todo: done callback
16-
// dedent`
17-
// it('it1', () => new Promise((done) => {
18-
// test()
19-
// .then(() => {
20-
// expect(someThing).toEqual(true);
21-
// done();
22-
// });
23-
// }));
24-
// `,
15+
dedent`
16+
it('it1', () => new Promise((done) => {
17+
test()
18+
.then(() => {
19+
expect(someThing).toEqual(true);
20+
done();
21+
});
22+
}));
23+
`,
2524
dedent`
2625
it('passes', () => {
2726
Promise.resolve().then(() => {
@@ -280,20 +279,30 @@ ruleTester.run('valid-expect-in-promise', rule, {
280279
}))
281280
`,
282281
'it("it1", () => somePromise.then(() => expect(someThing).toEqual(true)))',
283-
// todo: done callback
284-
// dedent`
285-
// it('promise test with done', (done) => {
286-
// const promise = getPromise();
287-
// promise.then(() => expect(someThing).toEqual(true));
288-
// });
289-
// `,
290-
// todo: done callback
291-
// dedent`
292-
// it('name of done param does not matter', (nameDoesNotMatter) => {
293-
// const promise = getPromise();
294-
// promise.then(() => expect(someThing).toEqual(true));
295-
// });
296-
// `,
282+
dedent`
283+
it('promise test with done', (done) => {
284+
const promise = getPromise();
285+
promise.then(() => expect(someThing).toEqual(true));
286+
});
287+
`,
288+
dedent`
289+
it('name of done param does not matter', (nameDoesNotMatter) => {
290+
const promise = getPromise();
291+
promise.then(() => expect(someThing).toEqual(true));
292+
});
293+
`,
294+
dedent`
295+
it.each([])('name of done param does not matter', (nameDoesNotMatter) => {
296+
const promise = getPromise();
297+
promise.then(() => expect(someThing).toEqual(true));
298+
});
299+
`,
300+
dedent`
301+
it.each\`\`('name of done param does not matter', ({}, nameDoesNotMatter) => {
302+
const promise = getPromise();
303+
promise.then(() => expect(someThing).toEqual(true));
304+
});
305+
`,
297306
],
298307
invalid: [
299308
{

src/rules/valid-expect-in-promise.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import {
77
KnownCallExpression,
88
createRule,
99
getAccessorValue,
10+
getNodeName,
1011
isExpectCall,
12+
isFunction,
1113
isSupportedAccessor,
1214
isTestCaseCall,
1315
} from './utils';
@@ -55,6 +57,41 @@ const reportReturnRequired = (context: RuleContext, node: TSESTree.Node) => {
5557
});
5658
};
5759

60+
const isTestCaseCallWithCallbackArg = (
61+
node: TSESTree.CallExpression,
62+
): boolean => {
63+
if (!isTestCaseCall(node)) {
64+
return false;
65+
}
66+
67+
const isJestEach = getNodeName(node).endsWith('.each');
68+
69+
if (
70+
isJestEach &&
71+
node.callee.type !== AST_NODE_TYPES.TaggedTemplateExpression
72+
) {
73+
// isJestEach but not a TaggedTemplateExpression, so this must be
74+
// the `jest.each([])()` syntax which this rule doesn't support due
75+
// to its complexity (see jest-community/eslint-plugin-jest#710)
76+
// so we return true to trigger bailout
77+
return true;
78+
}
79+
80+
if (isJestEach || node.arguments.length >= 2) {
81+
const [, callback] = node.arguments;
82+
83+
const callbackArgIndex = Number(isJestEach);
84+
85+
return (
86+
callback &&
87+
isFunction(callback) &&
88+
callback.params.length === 1 + callbackArgIndex
89+
);
90+
}
91+
92+
return false;
93+
};
94+
5895
export default createRule<unknown[], MessageIds>({
5996
name: __filename,
6097
meta: {
@@ -72,11 +109,18 @@ export default createRule<unknown[], MessageIds>({
72109
},
73110
defaultOptions: [],
74111
create(context) {
112+
let inTestCaseWithDoneCallback = false;
75113
let inPromiseChain = false;
76114
let hasExpectCall = false;
77115

78116
return {
79117
CallExpression(node) {
118+
if (isTestCaseCallWithCallbackArg(node)) {
119+
inTestCaseWithDoneCallback = true;
120+
121+
return;
122+
}
123+
80124
if (isThenOrCatchCall(node)) {
81125
inPromiseChain = true;
82126

@@ -94,6 +138,14 @@ export default createRule<unknown[], MessageIds>({
94138
}
95139
},
96140
'CallExpression:exit'(node: TSESTree.CallExpression) {
141+
if (inTestCaseWithDoneCallback) {
142+
if (isTestCaseCall(node)) {
143+
inTestCaseWithDoneCallback = false;
144+
}
145+
146+
return;
147+
}
148+
97149
if (isThenOrCatchCall(node)) {
98150
inPromiseChain = false;
99151

0 commit comments

Comments
 (0)