Skip to content

Commit b4f506d

Browse files
committed
feat: new detection helpers for findBy queries
1 parent 2cdafb7 commit b4f506d

File tree

3 files changed

+124
-1
lines changed

3 files changed

+124
-1
lines changed

lib/detect-testing-library-utils.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ export type DetectionHelpers = {
5050
isValidFilename: () => boolean;
5151
isGetByQuery: (node: TSESTree.Identifier) => boolean;
5252
isQueryByQuery: (node: TSESTree.Identifier) => boolean;
53+
isFindByQuery: (node: TSESTree.Identifier) => boolean;
5354
isSyncQuery: (node: TSESTree.Identifier) => boolean;
55+
isAsyncQuery: (node: TSESTree.Identifier) => boolean;
5456
isPresenceAssert: (node: TSESTree.MemberExpression) => boolean;
5557
isAbsenceAssert: (node: TSESTree.MemberExpression) => boolean;
5658
canReportErrors: () => boolean;
@@ -145,13 +147,27 @@ export function detectTestingLibraryUtils<
145147
return !!node.name.match(/^query(All)?By.+$/);
146148
};
147149

150+
/**
151+
* Determines whether a given node is `findBy*` or `findAllBy*` query variant or not.
152+
*/
153+
const isFindByQuery: DetectionHelpers['isFindByQuery'] = (node) => {
154+
return !!node.name.match(/^find(All)?By.+$/);
155+
};
156+
148157
/**
149158
* Determines whether a given node is sync query or not.
150159
*/
151160
const isSyncQuery: DetectionHelpers['isSyncQuery'] = (node) => {
152161
return isGetByQuery(node) || isQueryByQuery(node);
153162
};
154163

164+
/**
165+
* Determines whether a given node is async query or not.
166+
*/
167+
const isAsyncQuery: DetectionHelpers['isAsyncQuery'] = (node) => {
168+
return isFindByQuery(node);
169+
};
170+
155171
/**
156172
* Determines whether a given MemberExpression node is a presence assert
157173
*
@@ -293,7 +309,9 @@ export function detectTestingLibraryUtils<
293309
isValidFilename,
294310
isGetByQuery,
295311
isQueryByQuery,
312+
isFindByQuery,
296313
isSyncQuery,
314+
isAsyncQuery,
297315
isPresenceAssert,
298316
isAbsenceAssert,
299317
canReportErrors,

tests/create-testing-library-rule.test.ts

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ ruleTester.run(RULE_NAME, rule, {
147147
querySomeElement('button')
148148
`,
149149
},
150+
{
151+
code: `
152+
// case: custom method not matching "findBy*" variant pattern
153+
findSomeElement('button')
154+
`,
155+
},
150156
{
151157
settings: {
152158
'testing-library/module': 'test-utils',
@@ -167,6 +173,16 @@ ruleTester.run(RULE_NAME, rule, {
167173
queryByRole('button')
168174
`,
169175
},
176+
{
177+
settings: {
178+
'testing-library/module': 'test-utils',
179+
},
180+
code: `
181+
// case: built-in "findBy*" query not reported because custom module not imported
182+
import { render } from 'other-module'
183+
findByRole('button')
184+
`,
185+
},
170186
{
171187
settings: {
172188
'testing-library/filename-pattern': 'testing-library\\.js',
@@ -185,6 +201,15 @@ ruleTester.run(RULE_NAME, rule, {
185201
queryByRole('button')
186202
`,
187203
},
204+
{
205+
settings: {
206+
'testing-library/filename-pattern': 'testing-library\\.js',
207+
},
208+
code: `
209+
// case: built-in "findBy*" query not reported because custom filename doesn't match
210+
findByRole('button')
211+
`,
212+
},
188213
{
189214
settings: {
190215
'testing-library/module': 'test-utils',
@@ -430,6 +455,13 @@ ruleTester.run(RULE_NAME, rule, {
430455
`,
431456
errors: [{ line: 3, column: 7, messageId: 'queryByError' }],
432457
},
458+
{
459+
code: `
460+
// case: built-in "findBy*" query reported without import (aggressive reporting)
461+
findByRole('button')
462+
`,
463+
errors: [{ line: 3, column: 7, messageId: 'findByError' }],
464+
},
433465
{
434466
filename: 'MyComponent.spec.js',
435467
code: `
@@ -445,6 +477,13 @@ ruleTester.run(RULE_NAME, rule, {
445477
`,
446478
errors: [{ line: 3, column: 7, messageId: 'queryByError' }],
447479
},
480+
{
481+
code: `
482+
// case: custom "findBy*" query reported without import (aggressive reporting)
483+
findByIcon('search')
484+
`,
485+
errors: [{ line: 3, column: 7, messageId: 'findByError' }],
486+
},
448487
{
449488
settings: {
450489
'testing-library/module': 'test-utils',
@@ -458,13 +497,28 @@ ruleTester.run(RULE_NAME, rule, {
458497
},
459498
{
460499
filename: 'MyComponent.spec.js',
500+
settings: {
501+
'testing-library/module': 'test-utils',
502+
},
461503
code: `
462504
// case: built-in "queryBy*" query reported with custom module + Testing Library package import
463-
import { render } from '@testing-library/framework'
505+
import { render } from '@testing-library/react'
464506
queryByRole('button')
465507
`,
466508
errors: [{ line: 4, column: 7, messageId: 'queryByError' }],
467509
},
510+
{
511+
filename: 'MyComponent.spec.js',
512+
settings: {
513+
'testing-library/module': 'test-utils',
514+
},
515+
code: `
516+
// case: built-in "findBy*" query reported with custom module + Testing Library package import
517+
import { render } from '@testing-library/react'
518+
findByRole('button')
519+
`,
520+
errors: [{ line: 4, column: 7, messageId: 'findByError' }],
521+
},
468522
{
469523
settings: {
470524
'testing-library/module': 'test-utils',
@@ -478,13 +532,28 @@ ruleTester.run(RULE_NAME, rule, {
478532
},
479533
{
480534
filename: 'MyComponent.spec.js',
535+
settings: {
536+
'testing-library/module': 'test-utils',
537+
},
481538
code: `
482539
// case: built-in "queryBy*" query reported with custom module + custom module import
483540
import { render } from 'test-utils'
484541
queryByRole('button')
485542
`,
486543
errors: [{ line: 4, column: 7, messageId: 'queryByError' }],
487544
},
545+
{
546+
filename: 'MyComponent.spec.js',
547+
settings: {
548+
'testing-library/module': 'test-utils',
549+
},
550+
code: `
551+
// case: built-in "queryBy*" query reported with custom module + custom module import
552+
import { render } from 'test-utils'
553+
findByRole('button')
554+
`,
555+
errors: [{ line: 4, column: 7, messageId: 'findByError' }],
556+
},
488557

489558
{
490559
settings: {
@@ -499,13 +568,28 @@ ruleTester.run(RULE_NAME, rule, {
499568
},
500569
{
501570
filename: 'MyComponent.spec.js',
571+
settings: {
572+
'testing-library/module': 'test-utils',
573+
},
502574
code: `
503575
// case: custom "queryBy*" query reported with custom module + Testing Library package import
504576
import { render } from '@testing-library/framework'
505577
queryByIcon('search')
506578
`,
507579
errors: [{ line: 4, column: 7, messageId: 'queryByError' }],
508580
},
581+
{
582+
filename: 'MyComponent.spec.js',
583+
settings: {
584+
'testing-library/module': 'test-utils',
585+
},
586+
code: `
587+
// case: custom "findBy*" query reported with custom module + Testing Library package import
588+
import { render } from '@testing-library/framework'
589+
findByIcon('search')
590+
`,
591+
errors: [{ line: 4, column: 7, messageId: 'findByError' }],
592+
},
509593
{
510594
settings: {
511595
'testing-library/module': 'test-utils',
@@ -519,13 +603,28 @@ ruleTester.run(RULE_NAME, rule, {
519603
},
520604
{
521605
filename: 'MyComponent.spec.js',
606+
settings: {
607+
'testing-library/module': 'test-utils',
608+
},
522609
code: `
523610
// case: custom "queryBy*" query reported with custom module + custom module import
524611
import { render } from 'test-utils'
525612
queryByIcon('search')
526613
`,
527614
errors: [{ line: 4, column: 7, messageId: 'queryByError' }],
528615
},
616+
{
617+
filename: 'MyComponent.spec.js',
618+
settings: {
619+
'testing-library/module': 'test-utils',
620+
},
621+
code: `
622+
// case: custom "findBy*" query reported with custom module + custom module import
623+
import { render } from 'test-utils'
624+
findByIcon('search')
625+
`,
626+
errors: [{ line: 4, column: 7, messageId: 'findByError' }],
627+
},
529628
{
530629
settings: {
531630
'testing-library/module': 'test-utils',

tests/fake-rule.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ type MessageIds =
1111
| 'fakeError'
1212
| 'getByError'
1313
| 'queryByError'
14+
| 'findByError'
1415
| 'presenceAssertError'
1516
| 'absenceAssertError';
1617

@@ -27,6 +28,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
2728
fakeError: 'fake error reported',
2829
getByError: 'some error related to getBy reported',
2930
queryByError: 'some error related to queryBy reported',
31+
findByError: 'some error related to findBy reported',
3032
presenceAssertError: 'some error related to presence assert reported',
3133
absenceAssertError: 'some error related to absence assert reported',
3234
},
@@ -49,6 +51,10 @@ export default createTestingLibraryRule<Options, MessageIds>({
4951
if (helpers.isQueryByQuery(node)) {
5052
return context.report({ node, messageId: 'queryByError' });
5153
}
54+
55+
if (helpers.isFindByQuery(node)) {
56+
return context.report({ node, messageId: 'findByError' });
57+
}
5258
};
5359

5460
const reportMemberExpression = (node: TSESTree.MemberExpression) => {

0 commit comments

Comments
 (0)