1+ import { ASTUtils , TSESTree } from '@typescript-eslint/experimental-utils' ;
12import {
2- ESLintUtils ,
3- TSESTree ,
4- ASTUtils ,
5- } from '@typescript-eslint/experimental-utils' ;
6- import { getDocsUrl , ALL_QUERIES_COMBINATIONS } from '../utils' ;
7- import {
3+ isCallExpression ,
84 isMemberExpression ,
5+ isObjectExpression ,
96 isObjectPattern ,
10- isCallExpression ,
117 isProperty ,
12- isObjectExpression ,
138} from '../node-utils' ;
9+ import { createTestingLibraryRule } from '../create-testing-library-rule' ;
1410
1511export const RULE_NAME = 'prefer-screen-queries' ;
1612export type MessageIds = 'preferScreenQueries' ;
@@ -20,7 +16,6 @@ const ALLOWED_RENDER_PROPERTIES_FOR_DESTRUCTURING = [
2016 'container' ,
2117 'baseElement' ,
2218] ;
23- const ALL_QUERIES_COMBINATIONS_REGEXP = ALL_QUERIES_COMBINATIONS . join ( '|' ) ;
2419
2520function usesContainerOrBaseElement ( node : TSESTree . CallExpression ) {
2621 const secondArgument = node . arguments [ 1 ] ;
@@ -35,7 +30,7 @@ function usesContainerOrBaseElement(node: TSESTree.CallExpression) {
3530 ) ;
3631}
3732
38- export default ESLintUtils . RuleCreator ( getDocsUrl ) < Options , MessageIds > ( {
33+ export default createTestingLibraryRule < Options , MessageIds > ( {
3934 name : RULE_NAME ,
4035 meta : {
4136 type : 'suggestion' ,
@@ -53,7 +48,7 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
5348 } ,
5449 defaultOptions : [ ] ,
5550
56- create ( context ) {
51+ create ( context , _ , helpers ) {
5752 function reportInvalidUsage ( node : TSESTree . Identifier ) {
5853 context . report ( {
5954 node,
@@ -64,8 +59,26 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
6459 } ) ;
6560 }
6661
67- const queriesRegex = new RegExp ( ALL_QUERIES_COMBINATIONS_REGEXP ) ;
68- const queriesDestructuredInWithinDeclaration : string [ ] = [ ] ;
62+ function saveSafeDestructuredQueries ( node : TSESTree . VariableDeclarator ) {
63+ if ( isObjectPattern ( node . id ) ) {
64+ const identifiers = node . id . properties
65+ . filter (
66+ ( property ) =>
67+ isProperty ( property ) &&
68+ ASTUtils . isIdentifier ( property . key ) &&
69+ helpers . isQuery ( property . key )
70+ )
71+ . map (
72+ ( property : TSESTree . Property ) =>
73+ ( property . key as TSESTree . Identifier ) . name
74+ ) ;
75+ safeDestructuredQueries . push ( ...identifiers ) ;
76+ }
77+ }
78+
79+ // keep here those queries which are safe and shouldn't be reported
80+ // (from within, from render + container/base element, not related to TL, etc)
81+ const safeDestructuredQueries : string [ ] = [ ] ;
6982 // use an array as within might be used more than once in a test
7083 const withinDeclaredVariables : string [ ] = [ ] ;
7184
@@ -77,63 +90,61 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
7790 ) {
7891 return ;
7992 }
93+
94+ const isComingFromValidRender = helpers . isRenderUtil ( node . init . callee ) ;
95+
96+ if ( ! isComingFromValidRender ) {
97+ // save the destructured query methods as safe since they are coming
98+ // from render not related to TL
99+ saveSafeDestructuredQueries ( node ) ;
100+ }
101+
80102 const isWithinFunction = node . init . callee . name === 'within' ;
81- // TODO add the custom render option #198
82103 const usesRenderOptions =
83- node . init . callee . name === 'render' &&
84- usesContainerOrBaseElement ( node . init ) ;
104+ isComingFromValidRender && usesContainerOrBaseElement ( node . init ) ;
85105
86106 if ( ! isWithinFunction && ! usesRenderOptions ) {
87107 return ;
88108 }
89109
90110 if ( isObjectPattern ( node . id ) ) {
91- // save the destructured query methods
92- const identifiers = node . id . properties
93- . filter (
94- ( property ) =>
95- isProperty ( property ) &&
96- ASTUtils . isIdentifier ( property . key ) &&
97- queriesRegex . test ( property . key . name )
98- )
99- . map (
100- ( property : TSESTree . Property ) =>
101- ( property . key as TSESTree . Identifier ) . name
102- ) ;
103-
104- queriesDestructuredInWithinDeclaration . push ( ...identifiers ) ;
111+ // save the destructured query methods as safe since they are coming
112+ // from within or render + base/container options
113+ saveSafeDestructuredQueries ( node ) ;
105114 return ;
106115 }
107116
108117 if ( ASTUtils . isIdentifier ( node . id ) ) {
109118 withinDeclaredVariables . push ( node . id . name ) ;
110119 }
111120 } ,
112- [ `CallExpression > Identifier[name=/^${ ALL_QUERIES_COMBINATIONS_REGEXP } $/]` ] (
113- node : TSESTree . Identifier
114- ) {
121+ 'CallExpression > Identifier' ( node : TSESTree . Identifier ) {
122+ if ( ! helpers . isQuery ( node ) ) {
123+ return ;
124+ }
125+
115126 if (
116- ! queriesDestructuredInWithinDeclaration . some (
117- ( queryName ) => queryName === node . name
118- )
127+ ! safeDestructuredQueries . some ( ( queryName ) => queryName === node . name )
119128 ) {
120129 reportInvalidUsage ( node ) ;
121130 }
122131 } ,
123- [ `MemberExpression > Identifier[name=/^${ ALL_QUERIES_COMBINATIONS_REGEXP } $/]` ] (
124- node : TSESTree . Identifier
125- ) {
132+ 'MemberExpression > Identifier' ( node : TSESTree . Identifier ) {
126133 function isIdentifierAllowed ( name : string ) {
127134 return [ 'screen' , ...withinDeclaredVariables ] . includes ( name ) ;
128135 }
129136
137+ if ( ! helpers . isQuery ( node ) ) {
138+ return ;
139+ }
140+
130141 if (
131142 ASTUtils . isIdentifier ( node ) &&
132143 isMemberExpression ( node . parent ) &&
133144 isCallExpression ( node . parent . object ) &&
134145 ASTUtils . isIdentifier ( node . parent . object . callee ) &&
135146 node . parent . object . callee . name !== 'within' &&
136- node . parent . object . callee . name === 'render' &&
147+ helpers . isRenderUtil ( node . parent . object . callee ) &&
137148 ! usesContainerOrBaseElement ( node . parent . object )
138149 ) {
139150 reportInvalidUsage ( node ) ;
0 commit comments