testing-library / testing-library/eslint-plugin-testing-library

`no-wait-for-side-effects`: side effects not detected via `userEvent.setup()` instances and when wrapped in `void`

Open
#1,370 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug triage
Dominant language
TypeScript
Stars
1.1k
Forks
168
Avg merge
15h 44m
Merged PRs (30d)
14

Description

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
  1. Enable testing-library/no-wait-for-side-effects (config below).
  2. 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
  });
});
  1. 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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at no-wait-for-side-effects and compare its side-effect resolution with isUserEventMethod, userEventSetupVars, and getPropertyIdentifierNode. Add regression coverage for setup instances and void-wrapped userEvent, fireEvent, and render calls, using the supplied reproductions. Done means the three previously silent statements are reported while the existing direct userEvent and fireEvent cases remain reported.

Written by the indexing model from the issue text.

Assessment

Tech stack
eslint, javascript, typescript
Domain
testing-qa, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.