From 1566f01845c04ec69941715264fd3aebeb7e696a Mon Sep 17 00:00:00 2001 From: nathanmmiller <37555055+nathanmmiller@users.noreply.github.com> Date: Sat, 18 Mar 2023 17:22:39 -0400 Subject: [PATCH 1/2] fix: ignore getBy inside of within for prefer-presence-queries on absence queries --- lib/rules/prefer-presence-queries.ts | 14 +++++- .../lib/rules/prefer-presence-queries.test.ts | 48 +++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/lib/rules/prefer-presence-queries.ts b/lib/rules/prefer-presence-queries.ts index 9ec96c38..dd816408 100644 --- a/lib/rules/prefer-presence-queries.ts +++ b/lib/rules/prefer-presence-queries.ts @@ -59,6 +59,7 @@ export default createTestingLibraryRule({ return { 'CallExpression Identifier'(node: TSESTree.Identifier) { const expectCallNode = findClosestCallNode(node, 'expect'); + const withinCallNode = findClosestCallNode(node, 'within'); if (!expectCallNode || !isMemberExpression(expectCallNode.parent)) { return; @@ -79,9 +80,18 @@ export default createTestingLibraryRule({ return; } - if (presence && isPresenceAssert && !isPresenceQuery) { + if ( + presence && + (withinCallNode || isPresenceAssert) && + !isPresenceQuery + ) { context.report({ node, messageId: 'wrongPresenceQuery' }); - } else if (absence && isAbsenceAssert && isPresenceQuery) { + } else if ( + !withinCallNode && + absence && + isAbsenceAssert && + isPresenceQuery + ) { context.report({ node, messageId: 'wrongAbsenceQuery' }); } }, diff --git a/tests/lib/rules/prefer-presence-queries.test.ts b/tests/lib/rules/prefer-presence-queries.test.ts index 2b5187f2..a5e8b3c9 100644 --- a/tests/lib/rules/prefer-presence-queries.test.ts +++ b/tests/lib/rules/prefer-presence-queries.test.ts @@ -837,6 +837,12 @@ ruleTester.run(RULE_NAME, rule, { // right after clicking submit button it disappears expect(submitButton).not.toBeInTheDocument() `, + `// checking absence on getBy* inside a within with queryBy* outside the within + expect(within(screen.getByRole("button")).queryByText("Hello")).not.toBeInTheDocument() + `, + `// checking presence on getBy* inside a within with getBy* outside the within + expect(within(screen.getByRole("button")).getByText("Hello")).toBeInTheDocument() + `, ], invalid: [ // cases: asserting absence incorrectly with `getBy*` queries @@ -1199,5 +1205,47 @@ ruleTester.run(RULE_NAME, rule, { `, errors: [{ line: 4, column: 14, messageId: 'wrongAbsenceQuery' }], }, + { + code: ` + // case: asserting within check does still work with improper outer clause + expect(within(screen.getByRole("button")).getByText("Hello")).not.toBeInTheDocument()`, + errors: [{ line: 3, column: 46, messageId: 'wrongAbsenceQuery' }], + }, + { + code: ` + // case: asserting within check does still work with improper outer clause + expect(within(screen.getByRole("button")).queryByText("Hello")).toBeInTheDocument()`, + errors: [{ line: 3, column: 46, messageId: 'wrongPresenceQuery' }], + }, + { + code: ` + // case: asserting within check does still work with improper outer clause and improper inner clause + expect(within(screen.queryByRole("button")).getByText("Hello")).not.toBeInTheDocument()`, + errors: [ + { line: 3, column: 25, messageId: 'wrongPresenceQuery' }, + { line: 3, column: 48, messageId: 'wrongAbsenceQuery' }, + ], + }, + { + code: ` + // case: asserting within check does still work with proper outer clause and improper inner clause + expect(within(screen.queryByRole("button")).queryByText("Hello")).not.toBeInTheDocument()`, + errors: [{ line: 3, column: 25, messageId: 'wrongPresenceQuery' }], + }, + { + code: ` + // case: asserting within check does still work with proper outer clause and improper inner clause + expect(within(screen.queryByRole("button")).getByText("Hello")).toBeInTheDocument()`, + errors: [{ line: 3, column: 25, messageId: 'wrongPresenceQuery' }], + }, + { + code: ` + // case: asserting within check does still work with improper outer clause and improper inner clause + expect(within(screen.queryByRole("button")).queryByText("Hello")).toBeInTheDocument()`, + errors: [ + { line: 3, column: 25, messageId: 'wrongPresenceQuery' }, + { line: 3, column: 48, messageId: 'wrongPresenceQuery' }, + ], + }, ], }); From 6989ceba9a8ba527fe6a33ec6ef64fc07a026655 Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 4 Aug 2023 15:25:21 -0400 Subject: [PATCH 2/2] docs: within treatment in prefer-presence-queries --- docs/rules/prefer-presence-queries.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/rules/prefer-presence-queries.md b/docs/rules/prefer-presence-queries.md index af1df93c..2ab99d60 100644 --- a/docs/rules/prefer-presence-queries.md +++ b/docs/rules/prefer-presence-queries.md @@ -13,7 +13,7 @@ The (DOM) Testing Library allows to query DOM elements using different types of This rule fires whenever: -- `queryBy*` or `queryAllBy*` are used to assert element **is** present with `.toBeInTheDocument()`, `toBeTruthy()` or `.toBeDefined()` matchers or negated matchers from case below. +- `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. - `getBy*` or `getAllBy*` are used to assert element **is not** present with `.toBeNull()` or `.toBeFalsy()` matchers or negated matchers from case above. Examples of **incorrect** code for this rule: @@ -28,6 +28,7 @@ test('some test', () => { expect(screen.queryByText('button')).not.toBeNull(); expect(screen.queryAllByText('button')[2]).not.toBeNull(); expect(screen.queryByText('button')).not.toBeFalsy(); + ...(within(screen.queryByText('button')))... // check element is NOT present with `getBy*` expect(screen.getByText('loading')).not.toBeInTheDocument(); @@ -49,6 +50,7 @@ test('some test', async () => { expect(screen.getByText('button')).not.toBeNull(); expect(screen.getAllByText('button')[7]).not.toBeNull(); expect(screen.getByText('button')).not.toBeFalsy(); + ...(within(screen.getByText('button')))... // check element is NOT present with `queryBy*` expect(screen.queryByText('loading')).not.toBeInTheDocument();