|
1 | | -import { |
2 | | - DefinitionType, |
3 | | - type ScopeVariable, |
4 | | -} from '@typescript-eslint/scope-manager'; |
5 | 1 | import { TSESTree, ASTUtils } from '@typescript-eslint/utils';
|
6 | 2 |
|
7 | 3 | import { createTestingLibraryRule } from '../create-testing-library-rule';
|
8 | 4 | import {
|
9 | 5 | getDeepestIdentifierNode,
|
10 | | - getPropertyIdentifierNode, |
11 | | - isCallExpression, |
| 6 | + isLiteral, |
12 | 7 | isMemberExpression,
|
13 | 8 | } from '../node-utils';
|
14 | 9 | import {
|
| 10 | + ALL_QUERIES_COMBINATIONS, |
15 | 11 | ALL_RETURNING_NODES,
|
16 | 12 | EVENT_HANDLER_METHODS,
|
17 | | - getScope, |
18 | 13 | resolveToTestingLibraryFn,
|
19 | 14 | } from '../utils';
|
20 | 15 |
|
@@ -60,8 +55,6 @@ export default createTestingLibraryRule<Options, MessageIds>({
|
60 | 55 | ],
|
61 | 56 |
|
62 | 57 | create(context, [{ allowContainerFirstChild = false }], helpers) {
|
63 | | - const userEventInstanceNames = new Set<string>(); |
64 | | - |
65 | 58 | function showErrorForNodeAccess(node: TSESTree.MemberExpression) {
|
66 | 59 | // This rule is so aggressive that can cause tons of false positives outside test files when Aggressive Reporting
|
67 | 60 | // is enabled. Because of that, this rule will skip this mechanism and report only if some Testing Library package
|
@@ -99,94 +92,44 @@ export default createTestingLibraryRule<Options, MessageIds>({
|
99 | 92 | }
|
100 | 93 | }
|
101 | 94 |
|
102 | | - function detectTestingLibraryFn( |
103 | | - node: TSESTree.CallExpression, |
104 | | - variable: ScopeVariable | null |
| 95 | + function getProperty( |
| 96 | + node: TSESTree.PrivateIdentifier | TSESTree.Expression |
105 | 97 | ) {
|
106 | | - if (variable && variable.defs.length > 0) { |
107 | | - const def = variable.defs[0]; |
108 | | - if ( |
109 | | - def.type === DefinitionType.Variable && |
110 | | - isCallExpression(def.node.init) |
111 | | - ) { |
112 | | - return resolveToTestingLibraryFn(def.node.init, context); |
113 | | - } |
| 98 | + if (isLiteral(node)) { |
| 99 | + return node; |
114 | 100 | }
|
115 | 101 |
|
116 | | - return resolveToTestingLibraryFn(node,context); |
| 102 | + return getDeepestIdentifierNode(node); |
117 | 103 | }
|
118 | 104 |
|
119 | 105 | return {
|
120 | 106 | CallExpression(node: TSESTree.CallExpression) {
|
121 | | - const property = getDeepestIdentifierNode(node); |
122 | | - const identifier = getPropertyIdentifierNode(node); |
123 | | - |
124 | | - const isEventHandlerMethod = EVENT_HANDLER_METHODS.some( |
125 | | - (method) => method === property?.name |
126 | | - ); |
127 | | - const hasUserEventInstanceName = userEventInstanceNames.has( |
128 | | - identifier?.name ?? '' |
129 | | - ); |
130 | | - |
131 | | - const variable = identifier |
132 | | - ? ASTUtils.findVariable(getScope(context, node), identifier) |
133 | | - : null; |
134 | | - const testingLibraryFn = detectTestingLibraryFn(node, variable); |
| 107 | + if (!isMemberExpression(node.callee)) return; |
135 | 108 |
|
| 109 | + const { callee } = node; |
136 | 110 | if (
|
137 | | - !testingLibraryFn&& |
138 | | - isEventHandlerMethod&& |
139 | | - !hasUserEventInstanceName |
| 111 | + !EVENT_HANDLER_METHODS.some( |
| 112 | + (method)=>method===ASTUtils.getPropertyName(callee) |
| 113 | + ) |
140 | 114 | ) {
|
141 | | - context.report({ |
142 | | - node, |
143 | | - loc: property?.loc.start, |
144 | | - messageId: 'noNodeAccess', |
145 | | - }); |
146 | | - } |
147 | | - }, |
148 | | - VariableDeclarator(node: TSESTree.VariableDeclarator) { |
149 | | - const { init, id } = node; |
150 | | - |
151 | | - if (!isCallExpression(init)) { |
152 | 115 | return;
|
153 | 116 | }
|
| 117 | + const identifier = getDeepestIdentifierNode(callee.object); |
154 | 118 |
|
155 | 119 | if (
|
156 | | - !isMemberExpression(init.callee) || |
157 | | - !ASTUtils.isIdentifier(init.callee.object) |
| 120 | + !identifier || |
| 121 | + !ALL_QUERIES_COMBINATIONS.includes(identifier.name) |
158 | 122 | ) {
|
159 | 123 | return;
|
160 | 124 | }
|
161 | 125 |
|
162 | | - const testingLibraryFn = resolveToTestingLibraryFn(init, context); |
163 | | - if ( |
164 | | - init.callee.object.name === testingLibraryFn?.local && |
165 | | - ASTUtils.isIdentifier(init.callee.property) && |
166 | | - init.callee.property.name === 'setup' && |
167 | | - ASTUtils.isIdentifier(id) |
168 | | - ) { |
169 | | - userEventInstanceNames.add(id.name); |
170 | | - } |
171 | | - }, |
172 | | - AssignmentExpression(node: TSESTree.AssignmentExpression) { |
173 | | - if ( |
174 | | - ASTUtils.isIdentifier(node.left) && |
175 | | - isCallExpression(node.right) && |
176 | | - isMemberExpression(node.right.callee) && |
177 | | - ASTUtils.isIdentifier(node.right.callee.object) |
178 | | - ) { |
179 | | - const testingLibraryFn = resolveToTestingLibraryFn( |
180 | | - node.right, |
181 | | - context |
182 | | - ); |
183 | | - if ( |
184 | | - node.right.callee.object.name === testingLibraryFn?.local && |
185 | | - ASTUtils.isIdentifier(node.right.callee.property) && |
186 | | - node.right.callee.property.name === 'setup' |
187 | | - ) { |
188 | | - userEventInstanceNames.add(node.left.name); |
189 | | - } |
| 126 | + if (resolveToTestingLibraryFn(node, context)) { |
| 127 | + const property = getProperty(callee.property); |
| 128 | + context.report({ |
| 129 | + node, |
| 130 | + loc: property?.loc.start, |
| 131 | + messageId: 'noNodeAccess', |
| 132 | + }); |
190 | 133 | }
|
191 | 134 | },
|
192 | 135 | 'ExpressionStatement MemberExpression': showErrorForNodeAccess,
|
|
0 commit comments