Skip to content

Commit b75dc73

Browse files
fix(prefer-presence-queries): ignore getBy* inside within for on absence queries (#740)
* fix: ignore getBy inside of within for prefer-presence-queries on absence queries * docs: within treatment in prefer-presence-queries --------- Co-authored-by: Mario Beltrán <[email protected]>
1 parent 8a6db01 commit b75dc73

File tree

3 files changed

+63
-3
lines changed

3 files changed

+63
-3
lines changed

docs/rules/prefer-presence-queries.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The (DOM) Testing Library allows to query DOM elements using different types of
1313

1414
This rule fires whenever:
1515

16-
- `queryBy*` or `queryAllBy*` are used to assert element **is** present with `.toBeInTheDocument()`, `toBeTruthy()` or `.toBeDefined()` matchers or negated matchers from case below.
16+
- `queryBy*` or `queryAllBy*` are used to assert element **is** present with `.toBeInTheDocument()`, `toBeTruthy()` or `.toBeDefined()` matchers or negated matchers from case below, or when used inside a `within()` clause.
1717
- `getBy*` or `getAllBy*` are used to assert element **is not** present with `.toBeNull()` or `.toBeFalsy()` matchers or negated matchers from case above.
1818

1919
Examples of **incorrect** code for this rule:
@@ -28,6 +28,7 @@ test('some test', () => {
2828
expect(screen.queryByText('button')).not.toBeNull();
2929
expect(screen.queryAllByText('button')[2]).not.toBeNull();
3030
expect(screen.queryByText('button')).not.toBeFalsy();
31+
...(within(screen.queryByText('button')))...
3132

3233
// check element is NOT present with `getBy*`
3334
expect(screen.getByText('loading')).not.toBeInTheDocument();
@@ -50,6 +51,7 @@ test('some test', async () => {
5051
expect(screen.getByText('button')).not.toBeNull();
5152
expect(screen.getAllByText('button')[7]).not.toBeNull();
5253
expect(screen.getByText('button')).not.toBeFalsy();
54+
...(within(screen.getByText('button')))...
5355

5456
// check element is NOT present with `queryBy*`
5557
expect(screen.queryByText('loading')).not.toBeInTheDocument();

lib/rules/prefer-presence-queries.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
5959
return {
6060
'CallExpression Identifier'(node: TSESTree.Identifier) {
6161
const expectCallNode = findClosestCallNode(node, 'expect');
62+
const withinCallNode = findClosestCallNode(node, 'within');
6263

6364
if (!expectCallNode || !isMemberExpression(expectCallNode.parent)) {
6465
return;
@@ -79,9 +80,18 @@ export default createTestingLibraryRule<Options, MessageIds>({
7980
return;
8081
}
8182

82-
if (presence && isPresenceAssert && !isPresenceQuery) {
83+
if (
84+
presence &&
85+
(withinCallNode || isPresenceAssert) &&
86+
!isPresenceQuery
87+
) {
8388
context.report({ node, messageId: 'wrongPresenceQuery' });
84-
} else if (absence && isAbsenceAssert && isPresenceQuery) {
89+
} else if (
90+
!withinCallNode &&
91+
absence &&
92+
isAbsenceAssert &&
93+
isPresenceQuery
94+
) {
8595
context.report({ node, messageId: 'wrongAbsenceQuery' });
8696
}
8797
},

tests/lib/rules/prefer-presence-queries.test.ts

+48
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,12 @@ ruleTester.run(RULE_NAME, rule, {
837837
// right after clicking submit button it disappears
838838
expect(submitButton).not.toBeInTheDocument()
839839
`,
840+
`// checking absence on getBy* inside a within with queryBy* outside the within
841+
expect(within(screen.getByRole("button")).queryByText("Hello")).not.toBeInTheDocument()
842+
`,
843+
`// checking presence on getBy* inside a within with getBy* outside the within
844+
expect(within(screen.getByRole("button")).getByText("Hello")).toBeInTheDocument()
845+
`,
840846
],
841847
invalid: [
842848
// cases: asserting absence incorrectly with `getBy*` queries
@@ -1199,5 +1205,47 @@ ruleTester.run(RULE_NAME, rule, {
11991205
`,
12001206
errors: [{ line: 4, column: 14, messageId: 'wrongAbsenceQuery' }],
12011207
},
1208+
{
1209+
code: `
1210+
// case: asserting within check does still work with improper outer clause
1211+
expect(within(screen.getByRole("button")).getByText("Hello")).not.toBeInTheDocument()`,
1212+
errors: [{ line: 3, column: 46, messageId: 'wrongAbsenceQuery' }],
1213+
},
1214+
{
1215+
code: `
1216+
// case: asserting within check does still work with improper outer clause
1217+
expect(within(screen.getByRole("button")).queryByText("Hello")).toBeInTheDocument()`,
1218+
errors: [{ line: 3, column: 46, messageId: 'wrongPresenceQuery' }],
1219+
},
1220+
{
1221+
code: `
1222+
// case: asserting within check does still work with improper outer clause and improper inner clause
1223+
expect(within(screen.queryByRole("button")).getByText("Hello")).not.toBeInTheDocument()`,
1224+
errors: [
1225+
{ line: 3, column: 25, messageId: 'wrongPresenceQuery' },
1226+
{ line: 3, column: 48, messageId: 'wrongAbsenceQuery' },
1227+
],
1228+
},
1229+
{
1230+
code: `
1231+
// case: asserting within check does still work with proper outer clause and improper inner clause
1232+
expect(within(screen.queryByRole("button")).queryByText("Hello")).not.toBeInTheDocument()`,
1233+
errors: [{ line: 3, column: 25, messageId: 'wrongPresenceQuery' }],
1234+
},
1235+
{
1236+
code: `
1237+
// case: asserting within check does still work with proper outer clause and improper inner clause
1238+
expect(within(screen.queryByRole("button")).getByText("Hello")).toBeInTheDocument()`,
1239+
errors: [{ line: 3, column: 25, messageId: 'wrongPresenceQuery' }],
1240+
},
1241+
{
1242+
code: `
1243+
// case: asserting within check does still work with improper outer clause and improper inner clause
1244+
expect(within(screen.queryByRole("button")).queryByText("Hello")).toBeInTheDocument()`,
1245+
errors: [
1246+
{ line: 3, column: 25, messageId: 'wrongPresenceQuery' },
1247+
{ line: 3, column: 48, messageId: 'wrongPresenceQuery' },
1248+
],
1249+
},
12021250
],
12031251
});

0 commit comments

Comments
 (0)