Skip to content

Commit 45c2737

Browse files
committed
fix: ignore waitForElementToBeRemoved callbacks
1 parent ee2c337 commit 45c2737

3 files changed

Lines changed: 26 additions & 4 deletions

File tree

docs/rules/no-unsettled-absence-query.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This rule fires when an absence assertion on a `queryBy*` / `queryAllBy*` query
1212

1313
**What counts as "settled":**
1414

15-
1. Any `await` expression on a preceding statement - covers `findBy*`, `waitFor`, `act`, or custom async helpers.
15+
1. Any `await` expression on a preceding statement - covers `findBy*`, `waitFor`, `waitForElementToBeRemoved`, `act`, or custom async helpers.
1616
2. A `getBy*` / `getAllBy*` call on a preceding statement - proves the synchronous render produced expected output.
1717

1818
**Additionally**, absence assertions inside a `waitFor` callback are always flagged, because `waitFor` retries until the assertion passes - an absence check passes on the first invocation before the component has settled.
@@ -77,6 +77,13 @@ test('shows no error', () => {
7777
screen.getByText('visible heading');
7878
expect(screen.queryByText('error')).not.toBeInTheDocument();
7979
});
80+
81+
// waitForElementToBeRemoved is a settling expression on its own
82+
test('shows no error', async () => {
83+
render(<Component />);
84+
await waitForElementToBeRemoved(() => screen.queryByText('loading'));
85+
expect(screen.queryByText('error')).not.toBeInTheDocument();
86+
});
8087
```
8188

8289
## Further Reading

src/rules/no-unsettled-absence-query.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
106106
);
107107
}
108108

109-
function isInsideAsyncUtilCallback(node: TSESTree.Node): boolean {
109+
function isInsideWaitForCallback(node: TSESTree.Node): boolean {
110110
let current: TSESTree.Node | undefined = node.parent;
111111

112112
while (current) {
@@ -118,7 +118,10 @@ export default createTestingLibraryRule<Options, MessageIds>({
118118
const calleeIdentifier = getDeepestIdentifierNode(
119119
current.parent.callee
120120
);
121-
if (calleeIdentifier && helpers.isAsyncUtil(calleeIdentifier)) {
121+
if (
122+
calleeIdentifier &&
123+
helpers.isAsyncUtil(calleeIdentifier, ['waitFor'])
124+
) {
122125
return true;
123126
}
124127
}
@@ -188,7 +191,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
188191
return;
189192
}
190193

191-
if (isInsideAsyncUtilCallback(node)) {
194+
if (isInsideWaitForCallback(node)) {
192195
context.report({
193196
node,
194197
messageId: 'noUnsettledAbsenceQuery',

tests/rules/no-unsettled-absence-query.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ ruleTester.run('no-unsettled-absence-query', rule, {
6262
`,
6363
},
6464

65+
{
66+
code: `
67+
import { render, screen, waitForElementToBeRemoved } from '@testing-library/react'
68+
69+
test('waitForElementToBeRemoved is itself a settling expression', async () => {
70+
render(<Component />)
71+
await waitForElementToBeRemoved(() => screen.queryByText('loading'))
72+
expect(screen.queryByText('error')).not.toBeInTheDocument()
73+
})
74+
`,
75+
},
76+
6577
{
6678
code: `
6779
import { render, screen } from '@testing-library/react'

0 commit comments

Comments
 (0)