1- import {
2- ESLintUtils ,
3- TSESTree ,
4- ASTUtils ,
5- } from '@typescript-eslint/experimental-utils' ;
1+ import { TSESTree , ASTUtils } from '@typescript-eslint/experimental-utils' ;
62import {
73 ReportFixFunction ,
84 RuleFix ,
@@ -15,7 +11,7 @@ import {
1511 isObjectPattern ,
1612 isProperty ,
1713} from '../node-utils' ;
18- import { getDocsUrl , SYNC_QUERIES_COMBINATIONS } from '../utils ' ;
14+ import { createTestingLibraryRule } from '../create-testing-library-rule ' ;
1915
2016export const RULE_NAME = 'prefer-find-by' ;
2117export type MessageIds = 'preferFindBy' ;
@@ -51,7 +47,7 @@ function findRenderDefinitionDeclaration(
5147 return findRenderDefinitionDeclaration ( scope . upper , query ) ;
5248}
5349
54- export default ESLintUtils . RuleCreator ( getDocsUrl ) < Options , MessageIds > ( {
50+ export default createTestingLibraryRule < Options , MessageIds > ( {
5551 name : RULE_NAME ,
5652 meta : {
5753 type : 'suggestion' ,
@@ -70,7 +66,7 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
7066 } ,
7167 defaultOptions : [ ] ,
7268
73- create ( context ) {
69+ create ( context , _ , helpers ) {
7470 const sourceCode = context . getSourceCode ( ) ;
7571
7672 /**
@@ -126,7 +122,7 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
126122 isMemberExpression ( argument . body . callee ) &&
127123 ASTUtils . isIdentifier ( argument . body . callee . property ) &&
128124 ASTUtils . isIdentifier ( argument . body . callee . object ) &&
129- SYNC_QUERIES_COMBINATIONS . includes ( argument . body . callee . property . name )
125+ helpers . isSyncQuery ( argument . body . callee . property )
130126 ) {
131127 // shape of () => screen.getByText
132128 const fullQueryMethod = argument . body . callee . property . name ;
@@ -139,6 +135,11 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
139135 queryMethod,
140136 queryVariant,
141137 fix ( fixer ) {
138+ const property = ( ( argument . body as TSESTree . CallExpression )
139+ . callee as TSESTree . MemberExpression ) . property ;
140+ if ( helpers . isCustomQuery ( property as TSESTree . Identifier ) ) {
141+ return ;
142+ }
142143 const newCode = `${ caller } .${ queryVariant } ${ queryMethod } (${ callArguments
143144 . map ( ( node ) => sourceCode . getText ( node ) )
144145 . join ( ', ' ) } )`;
@@ -148,65 +149,74 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
148149 return ;
149150 }
150151 if (
151- ASTUtils . isIdentifier ( argument . body . callee ) &&
152- SYNC_QUERIES_COMBINATIONS . includes ( argument . body . callee . name )
152+ ! ASTUtils . isIdentifier ( argument . body . callee ) ||
153+ ! helpers . isSyncQuery ( argument . body . callee )
153154 ) {
154- // shape of () => getByText
155- const fullQueryMethod = argument . body . callee . name ;
156- const queryMethod = fullQueryMethod . split ( 'By' ) [ 1 ] ;
157- const queryVariant = getFindByQueryVariant ( fullQueryMethod ) ;
158- const callArguments = argument . body . arguments ;
155+ return ;
156+ }
157+ // shape of () => getByText
158+ const fullQueryMethod = argument . body . callee . name ;
159+ const queryMethod = fullQueryMethod . split ( 'By' ) [ 1 ] ;
160+ const queryVariant = getFindByQueryVariant ( fullQueryMethod ) ;
161+ const callArguments = argument . body . arguments ;
159162
160- reportInvalidUsage ( node , {
161- queryMethod,
162- queryVariant,
163- fix ( fixer ) {
164- const findByMethod = `${ queryVariant } ${ queryMethod } ` ;
165- const allFixes : RuleFix [ ] = [ ] ;
166- // this updates waitFor with findBy*
167- const newCode = `${ findByMethod } (${ callArguments
168- . map ( ( node ) => sourceCode . getText ( node ) )
169- . join ( ', ' ) } )`;
170- allFixes . push ( fixer . replaceText ( node , newCode ) ) ;
163+ reportInvalidUsage ( node , {
164+ queryMethod,
165+ queryVariant,
166+ fix ( fixer ) {
167+ // we know from above callee is an Identifier
168+ if (
169+ helpers . isCustomQuery (
170+ ( argument . body as TSESTree . CallExpression )
171+ . callee as TSESTree . Identifier
172+ )
173+ ) {
174+ return ;
175+ }
176+ const findByMethod = `${ queryVariant } ${ queryMethod } ` ;
177+ const allFixes : RuleFix [ ] = [ ] ;
178+ // this updates waitFor with findBy*
179+ const newCode = `${ findByMethod } (${ callArguments
180+ . map ( ( node ) => sourceCode . getText ( node ) )
181+ . join ( ', ' ) } )`;
182+ allFixes . push ( fixer . replaceText ( node , newCode ) ) ;
171183
172- // this adds the findBy* declaration - adding it to the list of destructured variables { findBy* } = render()
173- const definition = findRenderDefinitionDeclaration (
174- context . getScope ( ) ,
175- fullQueryMethod
176- ) ;
177- // I think it should always find it, otherwise code should not be valid (it'd be using undeclared variables)
178- if ( ! definition ) {
184+ // this adds the findBy* declaration - adding it to the list of destructured variables { findBy* } = render()
185+ const definition = findRenderDefinitionDeclaration (
186+ context . getScope ( ) ,
187+ fullQueryMethod
188+ ) ;
189+ // I think it should always find it, otherwise code should not be valid (it'd be using undeclared variables)
190+ if ( ! definition ) {
191+ return allFixes ;
192+ }
193+ // check the declaration is part of a destructuring
194+ if ( isObjectPattern ( definition . parent . parent ) ) {
195+ const allVariableDeclarations = definition . parent . parent ;
196+ // verify if the findBy* method was already declared
197+ if (
198+ allVariableDeclarations . properties . some (
199+ ( p ) =>
200+ isProperty ( p ) &&
201+ ASTUtils . isIdentifier ( p . key ) &&
202+ p . key . name === findByMethod
203+ )
204+ ) {
179205 return allFixes ;
180206 }
181- // check the declaration is part of a destructuring
182- if ( isObjectPattern ( definition . parent . parent ) ) {
183- const allVariableDeclarations = definition . parent . parent ;
184- // verify if the findBy* method was already declared
185- if (
186- allVariableDeclarations . properties . some (
187- ( p ) =>
188- isProperty ( p ) &&
189- ASTUtils . isIdentifier ( p . key ) &&
190- p . key . name === findByMethod
191- )
192- ) {
193- return allFixes ;
194- }
195- // the last character of a destructuring is always a " }", so we should replace it with the findBy* declaration
196- const textDestructuring = sourceCode . getText (
197- allVariableDeclarations
198- ) ;
199- const text =
200- textDestructuring . substring ( 0 , textDestructuring . length - 2 ) +
201- `, ${ findByMethod } }` ;
202- allFixes . push ( fixer . replaceText ( allVariableDeclarations , text ) ) ;
203- }
207+ // the last character of a destructuring is always a " }", so we should replace it with the findBy* declaration
208+ const textDestructuring = sourceCode . getText (
209+ allVariableDeclarations
210+ ) ;
211+ const text =
212+ textDestructuring . substring ( 0 , textDestructuring . length - 2 ) +
213+ `, ${ findByMethod } }` ;
214+ allFixes . push ( fixer . replaceText ( allVariableDeclarations , text ) ) ;
215+ }
204216
205- return allFixes ;
206- } ,
207- } ) ;
208- return ;
209- }
217+ return allFixes ;
218+ } ,
219+ } ) ;
210220 } ,
211221 } ;
212222 } ,
0 commit comments