source: frontend/node_modules/eslint-plugin-testing-library/rules/prefer-find-by.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 13 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 15.4 KB
Line 
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.getFindByQueryVariant = exports.WAIT_METHODS = exports.RULE_NAME = void 0;
4const utils_1 = require("@typescript-eslint/utils");
5const create_testing_library_rule_1 = require("../create-testing-library-rule");
6const node_utils_1 = require("../node-utils");
7exports.RULE_NAME = 'prefer-find-by';
8exports.WAIT_METHODS = ['waitFor', 'waitForElement', 'wait'];
9function getFindByQueryVariant(queryMethod) {
10 return queryMethod.includes('All') ? 'findAllBy' : 'findBy';
11}
12exports.getFindByQueryVariant = getFindByQueryVariant;
13function findRenderDefinitionDeclaration(scope, query) {
14 var _a;
15 if (!scope) {
16 return null;
17 }
18 const variable = scope.variables.find((v) => v.name === query);
19 if (variable) {
20 return ((_a = variable.defs
21 .map(({ name }) => name)
22 .filter(utils_1.ASTUtils.isIdentifier)
23 .find(({ name }) => name === query)) !== null && _a !== void 0 ? _a : null);
24 }
25 return findRenderDefinitionDeclaration(scope.upper, query);
26}
27exports.default = (0, create_testing_library_rule_1.createTestingLibraryRule)({
28 name: exports.RULE_NAME,
29 meta: {
30 type: 'suggestion',
31 docs: {
32 description: 'Suggest using `find(All)By*` query instead of `waitFor` + `get(All)By*` to wait for elements',
33 recommendedConfig: {
34 dom: 'error',
35 angular: 'error',
36 react: 'error',
37 vue: 'error',
38 marko: 'error',
39 },
40 },
41 messages: {
42 preferFindBy: 'Prefer `{{queryVariant}}{{queryMethod}}` query over using `{{waitForMethodName}}` + `{{prevQuery}}`',
43 },
44 fixable: 'code',
45 schema: [],
46 },
47 defaultOptions: [],
48 create(context, _, helpers) {
49 const sourceCode = context.getSourceCode();
50 function reportInvalidUsage(node, replacementParams) {
51 const { queryMethod, queryVariant, prevQuery, waitForMethodName, fix } = replacementParams;
52 context.report({
53 node,
54 messageId: 'preferFindBy',
55 data: {
56 queryVariant,
57 queryMethod,
58 prevQuery,
59 waitForMethodName,
60 },
61 fix,
62 });
63 }
64 function getWrongQueryNameInAssertion(node) {
65 if (!(0, node_utils_1.isCallExpression)(node.body) ||
66 !(0, node_utils_1.isMemberExpression)(node.body.callee)) {
67 return null;
68 }
69 if ((0, node_utils_1.isCallExpression)(node.body.callee.object) &&
70 (0, node_utils_1.isCallExpression)(node.body.callee.object.arguments[0]) &&
71 utils_1.ASTUtils.isIdentifier(node.body.callee.object.arguments[0].callee)) {
72 return node.body.callee.object.arguments[0].callee.name;
73 }
74 if (!utils_1.ASTUtils.isIdentifier(node.body.callee.property)) {
75 return null;
76 }
77 if ((0, node_utils_1.isCallExpression)(node.body.callee.object) &&
78 (0, node_utils_1.isCallExpression)(node.body.callee.object.arguments[0]) &&
79 (0, node_utils_1.isMemberExpression)(node.body.callee.object.arguments[0].callee) &&
80 utils_1.ASTUtils.isIdentifier(node.body.callee.object.arguments[0].callee.property)) {
81 return node.body.callee.object.arguments[0].callee.property.name;
82 }
83 if ((0, node_utils_1.isMemberExpression)(node.body.callee.object) &&
84 (0, node_utils_1.isCallExpression)(node.body.callee.object.object) &&
85 (0, node_utils_1.isCallExpression)(node.body.callee.object.object.arguments[0]) &&
86 (0, node_utils_1.isMemberExpression)(node.body.callee.object.object.arguments[0].callee) &&
87 utils_1.ASTUtils.isIdentifier(node.body.callee.object.object.arguments[0].callee.property)) {
88 return node.body.callee.object.object.arguments[0].callee.property.name;
89 }
90 if ((0, node_utils_1.isMemberExpression)(node.body.callee.object) &&
91 (0, node_utils_1.isCallExpression)(node.body.callee.object.object) &&
92 (0, node_utils_1.isCallExpression)(node.body.callee.object.object.arguments[0]) &&
93 utils_1.ASTUtils.isIdentifier(node.body.callee.object.object.arguments[0].callee)) {
94 return node.body.callee.object.object.arguments[0].callee.name;
95 }
96 return node.body.callee.property.name;
97 }
98 function getWrongQueryName(node) {
99 if (!(0, node_utils_1.isCallExpression)(node.body)) {
100 return null;
101 }
102 if (utils_1.ASTUtils.isIdentifier(node.body.callee) &&
103 helpers.isSyncQuery(node.body.callee)) {
104 return node.body.callee.name;
105 }
106 return getWrongQueryNameInAssertion(node);
107 }
108 function getCaller(node) {
109 if (!(0, node_utils_1.isCallExpression)(node.body) ||
110 !(0, node_utils_1.isMemberExpression)(node.body.callee)) {
111 return null;
112 }
113 if (utils_1.ASTUtils.isIdentifier(node.body.callee.object)) {
114 return node.body.callee.object.name;
115 }
116 if ((0, node_utils_1.isCallExpression)(node.body.callee.object) &&
117 utils_1.ASTUtils.isIdentifier(node.body.callee.object.callee) &&
118 (0, node_utils_1.isCallExpression)(node.body.callee.object.arguments[0]) &&
119 (0, node_utils_1.isMemberExpression)(node.body.callee.object.arguments[0].callee) &&
120 utils_1.ASTUtils.isIdentifier(node.body.callee.object.arguments[0].callee.object)) {
121 return node.body.callee.object.arguments[0].callee.object.name;
122 }
123 if ((0, node_utils_1.isMemberExpression)(node.body.callee.object) &&
124 (0, node_utils_1.isCallExpression)(node.body.callee.object.object) &&
125 (0, node_utils_1.isCallExpression)(node.body.callee.object.object.arguments[0]) &&
126 (0, node_utils_1.isMemberExpression)(node.body.callee.object.object.arguments[0].callee) &&
127 utils_1.ASTUtils.isIdentifier(node.body.callee.object.object.arguments[0].callee.object)) {
128 return node.body.callee.object.object.arguments[0].callee.object.name;
129 }
130 return null;
131 }
132 function isSyncQuery(node) {
133 if (!(0, node_utils_1.isCallExpression)(node.body)) {
134 return false;
135 }
136 const isQuery = utils_1.ASTUtils.isIdentifier(node.body.callee) &&
137 helpers.isSyncQuery(node.body.callee);
138 const isWrappedInPresenceAssert = (0, node_utils_1.isMemberExpression)(node.body.callee) &&
139 (0, node_utils_1.isCallExpression)(node.body.callee.object) &&
140 (0, node_utils_1.isCallExpression)(node.body.callee.object.arguments[0]) &&
141 utils_1.ASTUtils.isIdentifier(node.body.callee.object.arguments[0].callee) &&
142 helpers.isSyncQuery(node.body.callee.object.arguments[0].callee) &&
143 helpers.isPresenceAssert(node.body.callee);
144 const isWrappedInNegatedPresenceAssert = (0, node_utils_1.isMemberExpression)(node.body.callee) &&
145 (0, node_utils_1.isMemberExpression)(node.body.callee.object) &&
146 (0, node_utils_1.isCallExpression)(node.body.callee.object.object) &&
147 (0, node_utils_1.isCallExpression)(node.body.callee.object.object.arguments[0]) &&
148 utils_1.ASTUtils.isIdentifier(node.body.callee.object.object.arguments[0].callee) &&
149 helpers.isSyncQuery(node.body.callee.object.object.arguments[0].callee) &&
150 helpers.isPresenceAssert(node.body.callee.object);
151 return (isQuery || isWrappedInPresenceAssert || isWrappedInNegatedPresenceAssert);
152 }
153 function isScreenSyncQuery(node) {
154 if (!(0, node_utils_1.isArrowFunctionExpression)(node) || !(0, node_utils_1.isCallExpression)(node.body)) {
155 return false;
156 }
157 if (!(0, node_utils_1.isMemberExpression)(node.body.callee) ||
158 !utils_1.ASTUtils.isIdentifier(node.body.callee.property)) {
159 return false;
160 }
161 if (!utils_1.ASTUtils.isIdentifier(node.body.callee.object) &&
162 !(0, node_utils_1.isCallExpression)(node.body.callee.object) &&
163 !(0, node_utils_1.isMemberExpression)(node.body.callee.object)) {
164 return false;
165 }
166 const isWrappedInPresenceAssert = helpers.isPresenceAssert(node.body.callee) &&
167 (0, node_utils_1.isCallExpression)(node.body.callee.object) &&
168 (0, node_utils_1.isCallExpression)(node.body.callee.object.arguments[0]) &&
169 (0, node_utils_1.isMemberExpression)(node.body.callee.object.arguments[0].callee) &&
170 utils_1.ASTUtils.isIdentifier(node.body.callee.object.arguments[0].callee.object);
171 const isWrappedInNegatedPresenceAssert = (0, node_utils_1.isMemberExpression)(node.body.callee.object) &&
172 helpers.isPresenceAssert(node.body.callee.object) &&
173 (0, node_utils_1.isCallExpression)(node.body.callee.object.object) &&
174 (0, node_utils_1.isCallExpression)(node.body.callee.object.object.arguments[0]) &&
175 (0, node_utils_1.isMemberExpression)(node.body.callee.object.object.arguments[0].callee);
176 return (helpers.isSyncQuery(node.body.callee.property) ||
177 isWrappedInPresenceAssert ||
178 isWrappedInNegatedPresenceAssert);
179 }
180 function getQueryArguments(node) {
181 if ((0, node_utils_1.isMemberExpression)(node.callee) &&
182 (0, node_utils_1.isCallExpression)(node.callee.object) &&
183 (0, node_utils_1.isCallExpression)(node.callee.object.arguments[0])) {
184 return node.callee.object.arguments[0].arguments;
185 }
186 if ((0, node_utils_1.isMemberExpression)(node.callee) &&
187 (0, node_utils_1.isMemberExpression)(node.callee.object) &&
188 (0, node_utils_1.isCallExpression)(node.callee.object.object) &&
189 (0, node_utils_1.isCallExpression)(node.callee.object.object.arguments[0])) {
190 return node.callee.object.object.arguments[0].arguments;
191 }
192 return node.arguments;
193 }
194 return {
195 'AwaitExpression > CallExpression'(node) {
196 if (!utils_1.ASTUtils.isIdentifier(node.callee) ||
197 !helpers.isAsyncUtil(node.callee, exports.WAIT_METHODS)) {
198 return;
199 }
200 const argument = node.arguments[0];
201 if (!(0, node_utils_1.isArrowFunctionExpression)(argument) ||
202 !(0, node_utils_1.isCallExpression)(argument.body)) {
203 return;
204 }
205 const waitForMethodName = node.callee.name;
206 if (isScreenSyncQuery(argument)) {
207 const caller = getCaller(argument);
208 if (!caller) {
209 return;
210 }
211 const fullQueryMethod = getWrongQueryName(argument);
212 if (!fullQueryMethod) {
213 return;
214 }
215 const waitOptions = node.arguments[1];
216 let waitOptionsSourceCode = '';
217 if ((0, node_utils_1.isObjectExpression)(waitOptions)) {
218 waitOptionsSourceCode = `, ${sourceCode.getText(waitOptions)}`;
219 }
220 const queryVariant = getFindByQueryVariant(fullQueryMethod);
221 const callArguments = getQueryArguments(argument.body);
222 const queryMethod = fullQueryMethod.split('By')[1];
223 if (!queryMethod) {
224 return;
225 }
226 reportInvalidUsage(node, {
227 queryMethod,
228 queryVariant,
229 prevQuery: fullQueryMethod,
230 waitForMethodName,
231 fix(fixer) {
232 const property = argument.body
233 .callee.property;
234 if (helpers.isCustomQuery(property)) {
235 return null;
236 }
237 const newCode = `${caller}.${queryVariant}${queryMethod}(${callArguments
238 .map((callArgNode) => sourceCode.getText(callArgNode))
239 .join(', ')}${waitOptionsSourceCode})`;
240 return fixer.replaceText(node, newCode);
241 },
242 });
243 return;
244 }
245 if (!isSyncQuery(argument)) {
246 return;
247 }
248 const fullQueryMethod = getWrongQueryName(argument);
249 if (!fullQueryMethod) {
250 return;
251 }
252 const queryMethod = fullQueryMethod.split('By')[1];
253 const queryVariant = getFindByQueryVariant(fullQueryMethod);
254 const callArguments = getQueryArguments(argument.body);
255 reportInvalidUsage(node, {
256 queryMethod,
257 queryVariant,
258 prevQuery: fullQueryMethod,
259 waitForMethodName,
260 fix(fixer) {
261 if (helpers.isCustomQuery(argument.body
262 .callee)) {
263 return null;
264 }
265 const findByMethod = `${queryVariant}${queryMethod}`;
266 const allFixes = [];
267 const newCode = `${findByMethod}(${callArguments
268 .map((callArgNode) => sourceCode.getText(callArgNode))
269 .join(', ')})`;
270 allFixes.push(fixer.replaceText(node, newCode));
271 const definition = findRenderDefinitionDeclaration(context.getScope(), fullQueryMethod);
272 if (!definition) {
273 return allFixes;
274 }
275 if (definition.parent &&
276 (0, node_utils_1.isObjectPattern)(definition.parent.parent)) {
277 const allVariableDeclarations = definition.parent.parent;
278 if (allVariableDeclarations.properties.some((p) => (0, node_utils_1.isProperty)(p) &&
279 utils_1.ASTUtils.isIdentifier(p.key) &&
280 p.key.name === findByMethod)) {
281 return allFixes;
282 }
283 const textDestructuring = sourceCode.getText(allVariableDeclarations);
284 const text = textDestructuring.replace(/(\s*})$/, `, ${findByMethod}$1`);
285 allFixes.push(fixer.replaceText(allVariableDeclarations, text));
286 }
287 return allFixes;
288 },
289 });
290 },
291 };
292 },
293});
Note: See TracBrowser for help on using the repository browser.