Skip to content

Commit fc6ccf8

Browse files
authored
fix(no-wait-for-side-effects): false positive inside .then() (testing-library#645)
* fix: no-wait-for-side-effects false positive inside .then() Added tests and a mention of edge case to rule documentation Closes testing-library#500 * fix: review feedback Remove awaits as the promise is waited by .then() * fix: review feedback Reuse existing helper function to make solution simpler * fix: review feedback Remove await as the promise is waited by .then() * fix: review feedback Remove await as the promise is waited by .then()
1 parent 2cf3883 commit fc6ccf8

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

docs/rules/no-wait-for-side-effects.md

+9
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,15 @@ Examples of **correct** code for this rule:
7373
expect(b).toEqual('b');
7474
});
7575

76+
// or
77+
userEvent.click(button);
78+
waitFor(function() {
79+
expect(b).toEqual('b');
80+
}).then(() => {
81+
// Outside of waitFor, e.g. inside a .then() side effects are allowed
82+
fireEvent.click(button);
83+
});
84+
7685
// or
7786
render(<App />)
7887
await waitFor(() => {

lib/rules/no-wait-for-side-effects.ts

+21
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
isAssignmentExpression,
99
isCallExpression,
1010
isSequenceExpression,
11+
hasThenProperty,
1112
} from '../node-utils';
1213

1314
export const RULE_NAME = 'no-wait-for-side-effects';
@@ -56,6 +57,22 @@ export default createTestingLibraryRule<Options, MessageIds>({
5657
);
5758
}
5859

60+
function isCallerThen(
61+
node:
62+
| TSESTree.AssignmentExpression
63+
| TSESTree.BlockStatement
64+
| TSESTree.CallExpression
65+
| TSESTree.SequenceExpression
66+
): boolean {
67+
if (!node.parent) {
68+
return false;
69+
}
70+
71+
const callExpressionNode = node.parent.parent as TSESTree.CallExpression;
72+
73+
return hasThenProperty(callExpressionNode.callee);
74+
}
75+
5976
function isRenderInVariableDeclaration(node: TSESTree.Node) {
6077
return (
6178
isVariableDeclaration(node) &&
@@ -137,6 +154,10 @@ export default createTestingLibraryRule<Options, MessageIds>({
137154
return;
138155
}
139156

157+
if (isCallerThen(node)) {
158+
return;
159+
}
160+
140161
getSideEffectNodes(node.body).forEach((sideEffectNode) =>
141162
context.report({
142163
node: sideEffectNode,

tests/lib/rules/no-wait-for-side-effects.test.ts

+48
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ ruleTester.run(RULE_NAME, rule, {
9999
await waitFor(function() {
100100
expect(b).toEqual('b')
101101
})
102+
`,
103+
},
104+
{
105+
// Issue #500, https://github.com/testing-library/eslint-plugin-testing-library/issues/500
106+
code: `
107+
import { waitFor } from '${testingFramework}';
108+
userEvent.click(button)
109+
waitFor(function() {
110+
expect(b).toEqual('b')
111+
}).then(() => {
112+
// Side effects are allowed inside .then()
113+
userEvent.click(button);
114+
})
102115
`,
103116
},
104117
]),
@@ -722,6 +735,41 @@ ruleTester.run(RULE_NAME, rule, {
722735
`,
723736
errors: [{ line: 4, column: 11, messageId: 'noSideEffectsWaitFor' }],
724737
} as const,
738+
{
739+
// Issue #500, https://github.com/testing-library/eslint-plugin-testing-library/issues/500
740+
code: `
741+
import { waitFor } from '${testingFramework}';
742+
waitFor(function() {
743+
userEvent.click(button)
744+
expect(b).toEqual('b')
745+
}).then(() => {
746+
userEvent.click(button) // Side effects are allowed inside .then()
747+
expect(b).toEqual('b')
748+
})
749+
`,
750+
errors: [{ line: 4, column: 11, messageId: 'noSideEffectsWaitFor' }],
751+
} as const,
752+
{
753+
// Issue #500, https://github.com/testing-library/eslint-plugin-testing-library/issues/500
754+
code: `
755+
import { waitFor } from '${testingFramework}';
756+
waitFor(function() {
757+
userEvent.click(button)
758+
expect(b).toEqual('b')
759+
}).then(() => {
760+
userEvent.click(button) // Side effects are allowed inside .then()
761+
expect(b).toEqual('b')
762+
await waitFor(() => {
763+
fireEvent.keyDown(input, {key: 'ArrowDown'}) // But not if there is a another waitFor with side effects inside the .then()
764+
expect(b).toEqual('b')
765+
})
766+
})
767+
`,
768+
errors: [
769+
{ line: 4, column: 11, messageId: 'noSideEffectsWaitFor' },
770+
{ line: 10, column: 13, messageId: 'noSideEffectsWaitFor' },
771+
],
772+
} as const,
725773
]),
726774

727775
{

0 commit comments

Comments
 (0)