1
+ import { ASTUtils , TSESTree } from '@typescript-eslint/experimental-utils' ;
1
2
import {
2
- ESLintUtils ,
3
- TSESTree ,
4
- ASTUtils ,
5
- } from '@typescript-eslint/experimental-utils' ;
6
- import { getDocsUrl , ALL_QUERIES_COMBINATIONS } from '../utils' ;
7
- import {
3
+ isCallExpression ,
8
4
isMemberExpression ,
5
+ isObjectExpression ,
9
6
isObjectPattern ,
10
- isCallExpression ,
11
7
isProperty ,
12
- isObjectExpression ,
13
8
} from '../node-utils' ;
9
+ import { createTestingLibraryRule } from '../create-testing-library-rule' ;
14
10
15
11
export const RULE_NAME = 'prefer-screen-queries' ;
16
12
export type MessageIds = 'preferScreenQueries' ;
@@ -20,7 +16,6 @@ const ALLOWED_RENDER_PROPERTIES_FOR_DESTRUCTURING = [
20
16
'container' ,
21
17
'baseElement' ,
22
18
] ;
23
- const ALL_QUERIES_COMBINATIONS_REGEXP = ALL_QUERIES_COMBINATIONS . join ( '|' ) ;
24
19
25
20
function usesContainerOrBaseElement ( node : TSESTree . CallExpression ) {
26
21
const secondArgument = node . arguments [ 1 ] ;
@@ -35,7 +30,7 @@ function usesContainerOrBaseElement(node: TSESTree.CallExpression) {
35
30
) ;
36
31
}
37
32
38
- export default ESLintUtils . RuleCreator ( getDocsUrl ) < Options , MessageIds > ( {
33
+ export default createTestingLibraryRule < Options , MessageIds > ( {
39
34
name : RULE_NAME ,
40
35
meta : {
41
36
type : 'suggestion' ,
@@ -53,7 +48,7 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
53
48
} ,
54
49
defaultOptions : [ ] ,
55
50
56
- create ( context ) {
51
+ create ( context , _ , helpers ) {
57
52
function reportInvalidUsage ( node : TSESTree . Identifier ) {
58
53
context . report ( {
59
54
node,
@@ -64,8 +59,26 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
64
59
} ) ;
65
60
}
66
61
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 [ ] = [ ] ;
69
82
// use an array as within might be used more than once in a test
70
83
const withinDeclaredVariables : string [ ] = [ ] ;
71
84
@@ -77,63 +90,61 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
77
90
) {
78
91
return ;
79
92
}
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
+
80
102
const isWithinFunction = node . init . callee . name === 'within' ;
81
- // TODO add the custom render option #198
82
103
const usesRenderOptions =
83
- node . init . callee . name === 'render' &&
84
- usesContainerOrBaseElement ( node . init ) ;
104
+ isComingFromValidRender && usesContainerOrBaseElement ( node . init ) ;
85
105
86
106
if ( ! isWithinFunction && ! usesRenderOptions ) {
87
107
return ;
88
108
}
89
109
90
110
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 ) ;
105
114
return ;
106
115
}
107
116
108
117
if ( ASTUtils . isIdentifier ( node . id ) ) {
109
118
withinDeclaredVariables . push ( node . id . name ) ;
110
119
}
111
120
} ,
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
+
115
126
if (
116
- ! queriesDestructuredInWithinDeclaration . some (
117
- ( queryName ) => queryName === node . name
118
- )
127
+ ! safeDestructuredQueries . some ( ( queryName ) => queryName === node . name )
119
128
) {
120
129
reportInvalidUsage ( node ) ;
121
130
}
122
131
} ,
123
- [ `MemberExpression > Identifier[name=/^${ ALL_QUERIES_COMBINATIONS_REGEXP } $/]` ] (
124
- node : TSESTree . Identifier
125
- ) {
132
+ 'MemberExpression > Identifier' ( node : TSESTree . Identifier ) {
126
133
function isIdentifierAllowed ( name : string ) {
127
134
return [ 'screen' , ...withinDeclaredVariables ] . includes ( name ) ;
128
135
}
129
136
137
+ if ( ! helpers . isQuery ( node ) ) {
138
+ return ;
139
+ }
140
+
130
141
if (
131
142
ASTUtils . isIdentifier ( node ) &&
132
143
isMemberExpression ( node . parent ) &&
133
144
isCallExpression ( node . parent . object ) &&
134
145
ASTUtils . isIdentifier ( node . parent . object . callee ) &&
135
146
node . parent . object . callee . name !== 'within' &&
136
- node . parent . object . callee . name === 'render' &&
147
+ helpers . isRenderUtil ( node . parent . object . callee ) &&
137
148
! usesContainerOrBaseElement ( node . parent . object )
138
149
) {
139
150
reportInvalidUsage ( node ) ;
0 commit comments