Have you read the Troubleshooting section?
Yes
Plugin version
v7.16.2
ESLint version
v9.39.2
Node.js version
v22.20.0
Bug description
no-wait-for-side-effects misses side effects inside waitFor in two
independent cases:
1. Aliased userEvent (userEvent.setup() instances). The rule only
recognizes side effects spelled userEvent.* (or the import alias). With the
user-event v14 recommended pattern — const user = userEvent.setup() and
calling methods on the instance — nothing is reported, so the rule is silent
for the most common modern usage. Cause: side effects are resolved by
identifier name via isUserEventUtil (node.name === userEventName), so the
identifier user never matches. The plugin already has an alias-aware helper
for exactly this case — isUserEventMethod with userEventSetupVars tracking,
used by await-async-events and no-await-sync-events — but this rule doesn't
use it. Same class of gap previously fixed for other rules in #812 and #758.
2. void-wrapped side effects. A statement like
void userEvent.click(el) is not reported even with the plain userEvent
name — this also hides void fireEvent.*(...) and void render(...). Cause:
getPropertyIdentifierNode unwraps member/call/chain/await expressions but has
no UnaryExpression case, so void x returns null and the statement is
skipped. await unwrapping was added for this rule in #1008; void needs the
same treatment.
The two combine: void user.click(el) is missed for both reasons.
Steps to reproduce
- Enable
testing-library/no-wait-for-side-effects (config below).
- Lint this spec:
import { waitFor, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
const el = document.body;
test('direct userEvent — reported', async () => {
await waitFor(async () => {
await userEvent.click(el); // ✅ reported
});
});
test('fireEvent — reported', async () => {
await waitFor(() => {
fireEvent.click(el); // ✅ reported
});
});
test('bug 1: setup() instance — NOT reported', async () => {
const user = userEvent.setup();
await waitFor(async () => {
await user.click(el); // ❌ silent (alias not matched)
});
});
test('bug 2: void-wrapped, real userEvent name — NOT reported', async () => {
await waitFor(() => {
void userEvent.click(el); // ❌ silent (void not unwrapped)
});
});
test('bugs 1+2 combined — NOT reported', async () => {
const user = userEvent.setup();
await waitFor(() => {
void user.click(el); // ❌ silent
});
});
- Only the first two tests are flagged. The
user.click and
void userEvent.click statements pass silently, even though they are the
same side effects.
Error output/screenshots
Actual output (fresh project, only eslint + this plugin installed):
repro.spec.js
8:5 error Avoid using side effects within `waitFor` callback testing-library/no-wait-for-side-effects
14:5 error Avoid using side effects within `waitFor` callback testing-library/no-wait-for-side-effects
✖ 2 problems (2 errors, 0 warnings)
Expected: the same noSideEffectsWaitFor error on the three unreported
statements (await user.click(el), void userEvent.click(el),
void user.click(el)).
| callback body |
reported? |
await waitFor(async () => { await userEvent.click(el) }) |
✅ error |
await waitFor(() => { fireEvent.click(el) }) |
✅ error |
await waitFor(async () => { await user.click(el) }) |
❌ silent |
await waitFor(() => { void userEvent.click(el) }) |
❌ silent |
await waitFor(() => { void user.click(el) }) |
❌ silent |
### ESLint configuration
```js
// eslint.config.js
import testingLibrary from 'eslint-plugin-testing-library';
export default [
{
files: ['**/*.spec.js'],
plugins: { 'testing-library': testingLibrary },
rules: {
'testing-library/no-wait-for-side-effects': 'error',
},
},
];
Rule(s) affected
testing-library/no-wait-for-side-effects, there might be more
Anything else?
No response
Do you want to submit a pull request to fix this bug?
Yes
Have you read the Troubleshooting section?
Yes
Plugin version
v7.16.2
ESLint version
v9.39.2
Node.js version
v22.20.0
Bug description
no-wait-for-side-effectsmisses side effects insidewaitForin twoindependent cases:
1. Aliased userEvent (
userEvent.setup()instances). The rule onlyrecognizes side effects spelled
userEvent.*(or the import alias). With theuser-event v14 recommended pattern —
const user = userEvent.setup()andcalling methods on the instance — nothing is reported, so the rule is silent
for the most common modern usage. Cause: side effects are resolved by
identifier name via
isUserEventUtil(node.name === userEventName), so theidentifier
usernever matches. The plugin already has an alias-aware helperfor exactly this case —
isUserEventMethodwithuserEventSetupVarstracking,used by
await-async-eventsandno-await-sync-events— but this rule doesn'tuse it. Same class of gap previously fixed for other rules in #812 and #758.
2.
void-wrapped side effects. A statement likevoid userEvent.click(el)is not reported even with the plainuserEventname — this also hides
void fireEvent.*(...)andvoid render(...). Cause:getPropertyIdentifierNodeunwraps member/call/chain/await expressions but hasno
UnaryExpressioncase, sovoid xreturnsnulland the statement isskipped.
awaitunwrapping was added for this rule in #1008;voidneeds thesame treatment.
The two combine:
void user.click(el)is missed for both reasons.Steps to reproduce
testing-library/no-wait-for-side-effects(config below).user.clickandvoid userEvent.clickstatements pass silently, even though they are thesame side effects.
Error output/screenshots
Actual output (fresh project, only
eslint+ this plugin installed):Expected: the same
noSideEffectsWaitForerror on the three unreportedstatements (
await user.click(el),void userEvent.click(el),void user.click(el)).await waitFor(async () => { await userEvent.click(el) })await waitFor(() => { fireEvent.click(el) })await waitFor(async () => { await user.click(el) })await waitFor(() => { void userEvent.click(el) })await waitFor(() => { void user.click(el) })Rule(s) affected
testing-library/no-wait-for-side-effects, there might be moreAnything else?
No response
Do you want to submit a pull request to fix this bug?
Yes