diff --git a/docs/rules/no-wait-for-side-effects.md b/docs/rules/no-wait-for-side-effects.md
index b545fae5..741a91a3 100644
--- a/docs/rules/no-wait-for-side-effects.md
+++ b/docs/rules/no-wait-for-side-effects.md
@@ -73,6 +73,15 @@ Examples of **correct** code for this rule:
expect(b).toEqual('b');
});
+ // or
+ userEvent.click(button);
+ waitFor(function() {
+ expect(b).toEqual('b');
+ }).then(() => {
+ // Outside of waitFor, e.g. inside a .then() side effects are allowed
+ fireEvent.click(button);
+ });
+
// or
render()
await waitFor(() => {
diff --git a/lib/rules/no-wait-for-side-effects.ts b/lib/rules/no-wait-for-side-effects.ts
index a0fd85fe..24ace87f 100644
--- a/lib/rules/no-wait-for-side-effects.ts
+++ b/lib/rules/no-wait-for-side-effects.ts
@@ -8,6 +8,7 @@ import {
isAssignmentExpression,
isCallExpression,
isSequenceExpression,
+ hasThenProperty,
} from '../node-utils';
export const RULE_NAME = 'no-wait-for-side-effects';
@@ -56,6 +57,22 @@ export default createTestingLibraryRule({
);
}
+ function isCallerThen(
+ node:
+ | TSESTree.AssignmentExpression
+ | TSESTree.BlockStatement
+ | TSESTree.CallExpression
+ | TSESTree.SequenceExpression
+ ): boolean {
+ if (!node.parent) {
+ return false;
+ }
+
+ const callExpressionNode = node.parent.parent as TSESTree.CallExpression;
+
+ return hasThenProperty(callExpressionNode.callee);
+ }
+
function isRenderInVariableDeclaration(node: TSESTree.Node) {
return (
isVariableDeclaration(node) &&
@@ -137,6 +154,10 @@ export default createTestingLibraryRule({
return;
}
+ if (isCallerThen(node)) {
+ return;
+ }
+
getSideEffectNodes(node.body).forEach((sideEffectNode) =>
context.report({
node: sideEffectNode,
diff --git a/tests/lib/rules/no-wait-for-side-effects.test.ts b/tests/lib/rules/no-wait-for-side-effects.test.ts
index 2d536d51..38d05047 100644
--- a/tests/lib/rules/no-wait-for-side-effects.test.ts
+++ b/tests/lib/rules/no-wait-for-side-effects.test.ts
@@ -99,6 +99,19 @@ ruleTester.run(RULE_NAME, rule, {
await waitFor(function() {
expect(b).toEqual('b')
})
+ `,
+ },
+ {
+ // Issue #500, https://github.com/testing-library/eslint-plugin-testing-library/issues/500
+ code: `
+ import { waitFor } from '${testingFramework}';
+ userEvent.click(button)
+ waitFor(function() {
+ expect(b).toEqual('b')
+ }).then(() => {
+ // Side effects are allowed inside .then()
+ userEvent.click(button);
+ })
`,
},
]),
@@ -722,6 +735,41 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [{ line: 4, column: 11, messageId: 'noSideEffectsWaitFor' }],
} as const,
+ {
+ // Issue #500, https://github.com/testing-library/eslint-plugin-testing-library/issues/500
+ code: `
+ import { waitFor } from '${testingFramework}';
+ waitFor(function() {
+ userEvent.click(button)
+ expect(b).toEqual('b')
+ }).then(() => {
+ userEvent.click(button) // Side effects are allowed inside .then()
+ expect(b).toEqual('b')
+ })
+ `,
+ errors: [{ line: 4, column: 11, messageId: 'noSideEffectsWaitFor' }],
+ } as const,
+ {
+ // Issue #500, https://github.com/testing-library/eslint-plugin-testing-library/issues/500
+ code: `
+ import { waitFor } from '${testingFramework}';
+ waitFor(function() {
+ userEvent.click(button)
+ expect(b).toEqual('b')
+ }).then(() => {
+ userEvent.click(button) // Side effects are allowed inside .then()
+ expect(b).toEqual('b')
+ await waitFor(() => {
+ fireEvent.keyDown(input, {key: 'ArrowDown'}) // But not if there is a another waitFor with side effects inside the .then()
+ expect(b).toEqual('b')
+ })
+ })
+ `,
+ errors: [
+ { line: 4, column: 11, messageId: 'noSideEffectsWaitFor' },
+ { line: 10, column: 13, messageId: 'noSideEffectsWaitFor' },
+ ],
+ } as const,
]),
{