source: frontend/node_modules/eslint-plugin-testing-library/create-testing-library-rule/detect-testing-library-utils.js

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

Fix frontend appearance

  • Property mode set to 100644
File size: 25.6 KB
Line 
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.detectTestingLibraryUtils = void 0;
4const utils_1 = require("@typescript-eslint/utils");
5const node_utils_1 = require("../node-utils");
6const utils_2 = require("../utils");
7const SETTING_OPTION_OFF = 'off';
8const USER_EVENT_PACKAGE = '@testing-library/user-event';
9const REACT_DOM_TEST_UTILS_PACKAGE = 'react-dom/test-utils';
10const FIRE_EVENT_NAME = 'fireEvent';
11const CREATE_EVENT_NAME = 'createEvent';
12const USER_EVENT_NAME = 'userEvent';
13const RENDER_NAME = 'render';
14function detectTestingLibraryUtils(ruleCreate, { skipRuleReportingCheck = false } = {}) {
15 return (context, optionsWithDefault) => {
16 const importedTestingLibraryNodes = [];
17 let importedCustomModuleNode = null;
18 let importedUserEventLibraryNode = null;
19 let importedReactDomTestUtilsNode = null;
20 const customModuleSetting = context.settings['testing-library/utils-module'];
21 const customRendersSetting = context.settings['testing-library/custom-renders'];
22 const customQueriesSetting = context.settings['testing-library/custom-queries'];
23 function isPotentialTestingLibraryFunction(node, isPotentialFunctionCallback) {
24 if (!node) {
25 return false;
26 }
27 const referenceNode = (0, node_utils_1.getReferenceNode)(node);
28 const referenceNodeIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(referenceNode);
29 if (!referenceNodeIdentifier) {
30 return false;
31 }
32 const importedUtilSpecifier = getTestingLibraryImportedUtilSpecifier(referenceNodeIdentifier);
33 const originalNodeName = (0, node_utils_1.isImportSpecifier)(importedUtilSpecifier) &&
34 importedUtilSpecifier.local.name !== importedUtilSpecifier.imported.name
35 ? importedUtilSpecifier.imported.name
36 : undefined;
37 if (!isPotentialFunctionCallback(node.name, originalNodeName)) {
38 return false;
39 }
40 if (isAggressiveModuleReportingEnabled()) {
41 return true;
42 }
43 return isNodeComingFromTestingLibrary(referenceNodeIdentifier);
44 }
45 const isAggressiveModuleReportingEnabled = () => !customModuleSetting;
46 const isAggressiveRenderReportingEnabled = () => {
47 const isSwitchedOff = customRendersSetting === SETTING_OPTION_OFF;
48 const hasCustomOptions = Array.isArray(customRendersSetting) && customRendersSetting.length > 0;
49 return !isSwitchedOff && !hasCustomOptions;
50 };
51 const isAggressiveQueryReportingEnabled = () => {
52 const isSwitchedOff = customQueriesSetting === SETTING_OPTION_OFF;
53 const hasCustomOptions = Array.isArray(customQueriesSetting) && customQueriesSetting.length > 0;
54 return !isSwitchedOff && !hasCustomOptions;
55 };
56 const getCustomModule = () => {
57 if (!isAggressiveModuleReportingEnabled() &&
58 customModuleSetting !== SETTING_OPTION_OFF) {
59 return customModuleSetting;
60 }
61 return undefined;
62 };
63 const getCustomRenders = () => {
64 if (!isAggressiveRenderReportingEnabled() &&
65 customRendersSetting !== SETTING_OPTION_OFF) {
66 return customRendersSetting;
67 }
68 return [];
69 };
70 const getCustomQueries = () => {
71 if (!isAggressiveQueryReportingEnabled() &&
72 customQueriesSetting !== SETTING_OPTION_OFF) {
73 return customQueriesSetting;
74 }
75 return [];
76 };
77 const getTestingLibraryImportNode = () => {
78 return importedTestingLibraryNodes[0];
79 };
80 const getAllTestingLibraryImportNodes = () => {
81 return importedTestingLibraryNodes;
82 };
83 const getCustomModuleImportNode = () => {
84 return importedCustomModuleNode;
85 };
86 const getTestingLibraryImportName = () => {
87 return (0, node_utils_1.getImportModuleName)(importedTestingLibraryNodes[0]);
88 };
89 const getCustomModuleImportName = () => {
90 return (0, node_utils_1.getImportModuleName)(importedCustomModuleNode);
91 };
92 const isTestingLibraryImported = (isStrict = false) => {
93 const isSomeModuleImported = importedTestingLibraryNodes.length !== 0 || !!importedCustomModuleNode;
94 return ((!isStrict && isAggressiveModuleReportingEnabled()) ||
95 isSomeModuleImported);
96 };
97 const isQuery = (node) => {
98 const hasQueryPattern = /^(get|query|find)(All)?By.+$/.test(node.name);
99 if (!hasQueryPattern) {
100 return false;
101 }
102 if (isAggressiveQueryReportingEnabled()) {
103 return true;
104 }
105 const customQueries = getCustomQueries();
106 const isBuiltInQuery = utils_2.ALL_QUERIES_COMBINATIONS.includes(node.name);
107 const isReportableCustomQuery = customQueries.some((pattern) => new RegExp(pattern).test(node.name));
108 return isBuiltInQuery || isReportableCustomQuery;
109 };
110 const isGetQueryVariant = (node) => {
111 return isQuery(node) && node.name.startsWith('get');
112 };
113 const isQueryQueryVariant = (node) => {
114 return isQuery(node) && node.name.startsWith('query');
115 };
116 const isFindQueryVariant = (node) => {
117 return isQuery(node) && node.name.startsWith('find');
118 };
119 const isSyncQuery = (node) => {
120 return isGetQueryVariant(node) || isQueryQueryVariant(node);
121 };
122 const isAsyncQuery = (node) => {
123 return isFindQueryVariant(node);
124 };
125 const isCustomQuery = (node) => {
126 return isQuery(node) && !utils_2.ALL_QUERIES_COMBINATIONS.includes(node.name);
127 };
128 const isBuiltInQuery = (node) => {
129 return isQuery(node) && utils_2.ALL_QUERIES_COMBINATIONS.includes(node.name);
130 };
131 const isAsyncUtil = (node, validNames = utils_2.ASYNC_UTILS) => {
132 return isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
133 return (validNames.includes(identifierNodeName) ||
134 (!!originalNodeName &&
135 validNames.includes(originalNodeName)));
136 });
137 };
138 const isFireEventUtil = (node) => {
139 return isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
140 return [identifierNodeName, originalNodeName].includes('fireEvent');
141 });
142 };
143 const isUserEventUtil = (node) => {
144 const userEvent = findImportedUserEventSpecifier();
145 let userEventName;
146 if (userEvent) {
147 userEventName = userEvent.name;
148 }
149 else if (isAggressiveModuleReportingEnabled()) {
150 userEventName = USER_EVENT_NAME;
151 }
152 if (!userEventName) {
153 return false;
154 }
155 return node.name === userEventName;
156 };
157 const isFireEventMethod = (node) => {
158 const fireEventUtil = findImportedTestingLibraryUtilSpecifier(FIRE_EVENT_NAME);
159 let fireEventUtilName;
160 if (fireEventUtil) {
161 fireEventUtilName = utils_1.ASTUtils.isIdentifier(fireEventUtil)
162 ? fireEventUtil.name
163 : fireEventUtil.local.name;
164 }
165 else if (isAggressiveModuleReportingEnabled()) {
166 fireEventUtilName = FIRE_EVENT_NAME;
167 }
168 if (!fireEventUtilName) {
169 return false;
170 }
171 const parentMemberExpression = node.parent && (0, node_utils_1.isMemberExpression)(node.parent)
172 ? node.parent
173 : undefined;
174 const parentCallExpression = node.parent && (0, node_utils_1.isCallExpression)(node.parent) ? node.parent : undefined;
175 if (!parentMemberExpression && !parentCallExpression) {
176 return false;
177 }
178 if (parentCallExpression) {
179 return [fireEventUtilName, FIRE_EVENT_NAME].includes(node.name);
180 }
181 const definedParentMemberExpression = parentMemberExpression;
182 const regularCall = utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object) &&
183 (0, node_utils_1.isCallExpression)(definedParentMemberExpression.parent) &&
184 definedParentMemberExpression.object.name === fireEventUtilName &&
185 node.name !== FIRE_EVENT_NAME &&
186 node.name !== fireEventUtilName;
187 const wildcardCall = (0, node_utils_1.isMemberExpression)(definedParentMemberExpression.object) &&
188 utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object.object) &&
189 definedParentMemberExpression.object.object.name ===
190 fireEventUtilName &&
191 utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object.property) &&
192 definedParentMemberExpression.object.property.name ===
193 FIRE_EVENT_NAME &&
194 node.name !== FIRE_EVENT_NAME &&
195 node.name !== fireEventUtilName;
196 const wildcardCallWithCallExpression = utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object) &&
197 definedParentMemberExpression.object.name === fireEventUtilName &&
198 utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.property) &&
199 definedParentMemberExpression.property.name === FIRE_EVENT_NAME &&
200 !(0, node_utils_1.isMemberExpression)(definedParentMemberExpression.parent) &&
201 node.name === FIRE_EVENT_NAME &&
202 node.name !== fireEventUtilName;
203 return regularCall || wildcardCall || wildcardCallWithCallExpression;
204 };
205 const isUserEventMethod = (node) => {
206 const userEvent = findImportedUserEventSpecifier();
207 let userEventName;
208 if (userEvent) {
209 userEventName = userEvent.name;
210 }
211 else if (isAggressiveModuleReportingEnabled()) {
212 userEventName = USER_EVENT_NAME;
213 }
214 if (!userEventName) {
215 return false;
216 }
217 const parentMemberExpression = node.parent && (0, node_utils_1.isMemberExpression)(node.parent)
218 ? node.parent
219 : undefined;
220 if (!parentMemberExpression) {
221 return false;
222 }
223 if ([userEventName, USER_EVENT_NAME].includes(node.name) ||
224 (utils_1.ASTUtils.isIdentifier(parentMemberExpression.object) &&
225 parentMemberExpression.object.name === node.name)) {
226 return false;
227 }
228 return (utils_1.ASTUtils.isIdentifier(parentMemberExpression.object) &&
229 parentMemberExpression.object.name === userEventName);
230 };
231 const isRenderUtil = (node) => isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
232 if (isAggressiveRenderReportingEnabled()) {
233 return identifierNodeName.toLowerCase().includes(RENDER_NAME);
234 }
235 return [RENDER_NAME, ...getCustomRenders()].some((validRenderName) => validRenderName === identifierNodeName ||
236 (Boolean(originalNodeName) &&
237 validRenderName === originalNodeName));
238 });
239 const isCreateEventUtil = (node) => {
240 const isCreateEventCallback = (identifierNodeName, originalNodeName) => [identifierNodeName, originalNodeName].includes(CREATE_EVENT_NAME);
241 if ((0, node_utils_1.isCallExpression)(node) &&
242 (0, node_utils_1.isMemberExpression)(node.callee) &&
243 utils_1.ASTUtils.isIdentifier(node.callee.object)) {
244 return isPotentialTestingLibraryFunction(node.callee.object, isCreateEventCallback);
245 }
246 if ((0, node_utils_1.isCallExpression)(node) &&
247 (0, node_utils_1.isMemberExpression)(node.callee) &&
248 (0, node_utils_1.isMemberExpression)(node.callee.object) &&
249 utils_1.ASTUtils.isIdentifier(node.callee.object.property)) {
250 return isPotentialTestingLibraryFunction(node.callee.object.property, isCreateEventCallback);
251 }
252 const identifier = (0, node_utils_1.getDeepestIdentifierNode)(node);
253 return isPotentialTestingLibraryFunction(identifier, isCreateEventCallback);
254 };
255 const isRenderVariableDeclarator = (node) => {
256 if (!node.init) {
257 return false;
258 }
259 const initIdentifierNode = (0, node_utils_1.getDeepestIdentifierNode)(node.init);
260 if (!initIdentifierNode) {
261 return false;
262 }
263 return isRenderUtil(initIdentifierNode);
264 };
265 const isDebugUtil = (identifierNode, validNames = utils_2.DEBUG_UTILS) => {
266 const isBuiltInConsole = (0, node_utils_1.isMemberExpression)(identifierNode.parent) &&
267 utils_1.ASTUtils.isIdentifier(identifierNode.parent.object) &&
268 identifierNode.parent.object.name === 'console';
269 return (!isBuiltInConsole &&
270 isPotentialTestingLibraryFunction(identifierNode, (identifierNodeName, originalNodeName) => {
271 return (validNames.includes(identifierNodeName) ||
272 (!!originalNodeName &&
273 validNames.includes(originalNodeName)));
274 }));
275 };
276 const isActUtil = (node) => {
277 const isTestingLibraryAct = isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
278 return [identifierNodeName, originalNodeName]
279 .filter(Boolean)
280 .includes('act');
281 });
282 const isReactDomTestUtilsAct = (() => {
283 if (!importedReactDomTestUtilsNode) {
284 return false;
285 }
286 const referenceNode = (0, node_utils_1.getReferenceNode)(node);
287 const referenceNodeIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(referenceNode);
288 if (!referenceNodeIdentifier) {
289 return false;
290 }
291 const importedUtilSpecifier = (0, node_utils_1.findImportSpecifier)(node.name, importedReactDomTestUtilsNode);
292 if (!importedUtilSpecifier) {
293 return false;
294 }
295 const importDeclaration = (() => {
296 if ((0, node_utils_1.isImportDeclaration)(importedUtilSpecifier.parent)) {
297 return importedUtilSpecifier.parent;
298 }
299 const variableDeclarator = (0, node_utils_1.findClosestVariableDeclaratorNode)(importedUtilSpecifier);
300 if ((0, node_utils_1.isCallExpression)(variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init)) {
301 return variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init;
302 }
303 return undefined;
304 })();
305 if (!importDeclaration) {
306 return false;
307 }
308 const importDeclarationName = (0, node_utils_1.getImportModuleName)(importDeclaration);
309 if (!importDeclarationName) {
310 return false;
311 }
312 if (importDeclarationName !== REACT_DOM_TEST_UTILS_PACKAGE) {
313 return false;
314 }
315 return (0, node_utils_1.hasImportMatch)(importedUtilSpecifier, referenceNodeIdentifier.name);
316 })();
317 return isTestingLibraryAct || isReactDomTestUtilsAct;
318 };
319 const isTestingLibraryUtil = (node) => {
320 return (isAsyncUtil(node) ||
321 isQuery(node) ||
322 isRenderUtil(node) ||
323 isFireEventMethod(node) ||
324 isUserEventMethod(node) ||
325 isActUtil(node) ||
326 isCreateEventUtil(node));
327 };
328 const isPresenceAssert = (node) => {
329 const { matcher, isNegated } = (0, node_utils_1.getAssertNodeInfo)(node);
330 if (!matcher) {
331 return false;
332 }
333 return isNegated
334 ? utils_2.ABSENCE_MATCHERS.includes(matcher)
335 : utils_2.PRESENCE_MATCHERS.includes(matcher);
336 };
337 const isAbsenceAssert = (node) => {
338 const { matcher, isNegated } = (0, node_utils_1.getAssertNodeInfo)(node);
339 if (!matcher) {
340 return false;
341 }
342 return isNegated
343 ? utils_2.PRESENCE_MATCHERS.includes(matcher)
344 : utils_2.ABSENCE_MATCHERS.includes(matcher);
345 };
346 const isMatchingAssert = (node, matcherName) => {
347 const { matcher } = (0, node_utils_1.getAssertNodeInfo)(node);
348 if (!matcher) {
349 return false;
350 }
351 return matcher === matcherName;
352 };
353 const findImportedTestingLibraryUtilSpecifier = (specifierName) => {
354 var _a;
355 const node = (_a = getCustomModuleImportNode()) !== null && _a !== void 0 ? _a : getTestingLibraryImportNode();
356 if (!node) {
357 return undefined;
358 }
359 return (0, node_utils_1.findImportSpecifier)(specifierName, node);
360 };
361 const findImportedUserEventSpecifier = () => {
362 if (!importedUserEventLibraryNode) {
363 return null;
364 }
365 if ((0, node_utils_1.isImportDeclaration)(importedUserEventLibraryNode)) {
366 const userEventIdentifier = importedUserEventLibraryNode.specifiers.find((specifier) => (0, node_utils_1.isImportDefaultSpecifier)(specifier));
367 if (userEventIdentifier) {
368 return userEventIdentifier.local;
369 }
370 }
371 else {
372 if (!utils_1.ASTUtils.isVariableDeclarator(importedUserEventLibraryNode.parent)) {
373 return null;
374 }
375 const requireNode = importedUserEventLibraryNode.parent;
376 if (!utils_1.ASTUtils.isIdentifier(requireNode.id)) {
377 return null;
378 }
379 return requireNode.id;
380 }
381 return null;
382 };
383 const getTestingLibraryImportedUtilSpecifier = (node) => {
384 var _a;
385 const identifierName = (_a = (0, node_utils_1.getPropertyIdentifierNode)(node)) === null || _a === void 0 ? void 0 : _a.name;
386 if (!identifierName) {
387 return undefined;
388 }
389 return findImportedTestingLibraryUtilSpecifier(identifierName);
390 };
391 const canReportErrors = () => {
392 return skipRuleReportingCheck || isTestingLibraryImported();
393 };
394 const isNodeComingFromTestingLibrary = (node) => {
395 var _a;
396 const importNode = getTestingLibraryImportedUtilSpecifier(node);
397 if (!importNode) {
398 return false;
399 }
400 const referenceNode = (0, node_utils_1.getReferenceNode)(node);
401 const referenceNodeIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(referenceNode);
402 if (!referenceNodeIdentifier) {
403 return false;
404 }
405 const importDeclaration = (() => {
406 if ((0, node_utils_1.isImportDeclaration)(importNode.parent)) {
407 return importNode.parent;
408 }
409 const variableDeclarator = (0, node_utils_1.findClosestVariableDeclaratorNode)(importNode);
410 if ((0, node_utils_1.isCallExpression)(variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init)) {
411 return variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init;
412 }
413 return undefined;
414 })();
415 if (!importDeclaration) {
416 return false;
417 }
418 const importDeclarationName = (0, node_utils_1.getImportModuleName)(importDeclaration);
419 if (!importDeclarationName) {
420 return false;
421 }
422 const identifierName = (_a = (0, node_utils_1.getPropertyIdentifierNode)(node)) === null || _a === void 0 ? void 0 : _a.name;
423 if (!identifierName) {
424 return false;
425 }
426 const hasImportElementMatch = (0, node_utils_1.hasImportMatch)(importNode, identifierName);
427 const hasImportModuleMatch = /testing-library/g.test(importDeclarationName) ||
428 (typeof customModuleSetting === 'string' &&
429 importDeclarationName.endsWith(customModuleSetting));
430 return hasImportElementMatch && hasImportModuleMatch;
431 };
432 const helpers = {
433 getTestingLibraryImportNode,
434 getAllTestingLibraryImportNodes,
435 getCustomModuleImportNode,
436 getTestingLibraryImportName,
437 getCustomModuleImportName,
438 isTestingLibraryImported,
439 isTestingLibraryUtil,
440 isGetQueryVariant,
441 isQueryQueryVariant,
442 isFindQueryVariant,
443 isSyncQuery,
444 isAsyncQuery,
445 isQuery,
446 isCustomQuery,
447 isBuiltInQuery,
448 isAsyncUtil,
449 isFireEventUtil,
450 isUserEventUtil,
451 isFireEventMethod,
452 isUserEventMethod,
453 isRenderUtil,
454 isCreateEventUtil,
455 isRenderVariableDeclarator,
456 isDebugUtil,
457 isActUtil,
458 isPresenceAssert,
459 isMatchingAssert,
460 isAbsenceAssert,
461 canReportErrors,
462 findImportedTestingLibraryUtilSpecifier,
463 isNodeComingFromTestingLibrary,
464 };
465 const detectionInstructions = {
466 ImportDeclaration(node) {
467 if (typeof node.source.value !== 'string') {
468 return;
469 }
470 if (/testing-library/g.test(node.source.value)) {
471 importedTestingLibraryNodes.push(node);
472 }
473 const customModule = getCustomModule();
474 if (customModule &&
475 !importedCustomModuleNode &&
476 node.source.value.endsWith(customModule)) {
477 importedCustomModuleNode = node;
478 }
479 if (!importedUserEventLibraryNode &&
480 node.source.value === USER_EVENT_PACKAGE) {
481 importedUserEventLibraryNode = node;
482 }
483 if (!importedUserEventLibraryNode &&
484 node.source.value === REACT_DOM_TEST_UTILS_PACKAGE) {
485 importedReactDomTestUtilsNode = node;
486 }
487 },
488 [`CallExpression > Identifier[name="require"]`](node) {
489 const callExpression = node.parent;
490 const { arguments: args } = callExpression;
491 if (args.some((arg) => (0, node_utils_1.isLiteral)(arg) &&
492 typeof arg.value === 'string' &&
493 /testing-library/g.test(arg.value))) {
494 importedTestingLibraryNodes.push(callExpression);
495 }
496 const customModule = getCustomModule();
497 if (!importedCustomModuleNode &&
498 args.some((arg) => customModule &&
499 (0, node_utils_1.isLiteral)(arg) &&
500 typeof arg.value === 'string' &&
501 arg.value.endsWith(customModule))) {
502 importedCustomModuleNode = callExpression;
503 }
504 if (!importedCustomModuleNode &&
505 args.some((arg) => (0, node_utils_1.isLiteral)(arg) &&
506 typeof arg.value === 'string' &&
507 arg.value === USER_EVENT_PACKAGE)) {
508 importedUserEventLibraryNode = callExpression;
509 }
510 if (!importedReactDomTestUtilsNode &&
511 args.some((arg) => (0, node_utils_1.isLiteral)(arg) &&
512 typeof arg.value === 'string' &&
513 arg.value === REACT_DOM_TEST_UTILS_PACKAGE)) {
514 importedReactDomTestUtilsNode = callExpression;
515 }
516 },
517 };
518 const ruleInstructions = ruleCreate(context, optionsWithDefault, helpers);
519 const enhancedRuleInstructions = {};
520 const allKeys = new Set(Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)));
521 allKeys.forEach((instruction) => {
522 enhancedRuleInstructions[instruction] = (node) => {
523 var _a, _b;
524 if (instruction in detectionInstructions) {
525 (_a = detectionInstructions[instruction]) === null || _a === void 0 ? void 0 : _a.call(detectionInstructions, node);
526 }
527 if (canReportErrors() && ruleInstructions[instruction]) {
528 return (_b = ruleInstructions[instruction]) === null || _b === void 0 ? void 0 : _b.call(ruleInstructions, node);
529 }
530 return undefined;
531 };
532 });
533 return enhancedRuleInstructions;
534 };
535}
536exports.detectTestingLibraryUtils = detectTestingLibraryUtils;
Note: See TracBrowser for help on using the repository browser.