123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.detectTestingLibraryUtils = void 0;
- const utils_1 = require("@typescript-eslint/utils");
- const node_utils_1 = require("../node-utils");
- const utils_2 = require("../utils");
- const SETTING_OPTION_OFF = 'off';
- const USER_EVENT_PACKAGE = '@testing-library/user-event';
- const REACT_DOM_TEST_UTILS_PACKAGE = 'react-dom/test-utils';
- const FIRE_EVENT_NAME = 'fireEvent';
- const CREATE_EVENT_NAME = 'createEvent';
- const USER_EVENT_NAME = 'userEvent';
- const RENDER_NAME = 'render';
- function detectTestingLibraryUtils(ruleCreate, { skipRuleReportingCheck = false } = {}) {
- return (context, optionsWithDefault) => {
- const importedTestingLibraryNodes = [];
- let importedCustomModuleNode = null;
- let importedUserEventLibraryNode = null;
- let importedReactDomTestUtilsNode = null;
- const customModuleSetting = context.settings['testing-library/utils-module'];
- const customRendersSetting = context.settings['testing-library/custom-renders'];
- const customQueriesSetting = context.settings['testing-library/custom-queries'];
- function isPotentialTestingLibraryFunction(node, isPotentialFunctionCallback) {
- if (!node) {
- return false;
- }
- const referenceNode = (0, node_utils_1.getReferenceNode)(node);
- const referenceNodeIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(referenceNode);
- if (!referenceNodeIdentifier) {
- return false;
- }
- const importedUtilSpecifier = getTestingLibraryImportedUtilSpecifier(referenceNodeIdentifier);
- const originalNodeName = (0, node_utils_1.isImportSpecifier)(importedUtilSpecifier) &&
- importedUtilSpecifier.local.name !== importedUtilSpecifier.imported.name
- ? importedUtilSpecifier.imported.name
- : undefined;
- if (!isPotentialFunctionCallback(node.name, originalNodeName)) {
- return false;
- }
- if (isAggressiveModuleReportingEnabled()) {
- return true;
- }
- return isNodeComingFromTestingLibrary(referenceNodeIdentifier);
- }
- const isAggressiveModuleReportingEnabled = () => !customModuleSetting;
- const isAggressiveRenderReportingEnabled = () => {
- const isSwitchedOff = customRendersSetting === SETTING_OPTION_OFF;
- const hasCustomOptions = Array.isArray(customRendersSetting) && customRendersSetting.length > 0;
- return !isSwitchedOff && !hasCustomOptions;
- };
- const isAggressiveQueryReportingEnabled = () => {
- const isSwitchedOff = customQueriesSetting === SETTING_OPTION_OFF;
- const hasCustomOptions = Array.isArray(customQueriesSetting) && customQueriesSetting.length > 0;
- return !isSwitchedOff && !hasCustomOptions;
- };
- const getCustomModule = () => {
- if (!isAggressiveModuleReportingEnabled() &&
- customModuleSetting !== SETTING_OPTION_OFF) {
- return customModuleSetting;
- }
- return undefined;
- };
- const getCustomRenders = () => {
- if (!isAggressiveRenderReportingEnabled() &&
- customRendersSetting !== SETTING_OPTION_OFF) {
- return customRendersSetting;
- }
- return [];
- };
- const getCustomQueries = () => {
- if (!isAggressiveQueryReportingEnabled() &&
- customQueriesSetting !== SETTING_OPTION_OFF) {
- return customQueriesSetting;
- }
- return [];
- };
- const getTestingLibraryImportNode = () => {
- return importedTestingLibraryNodes[0];
- };
- const getAllTestingLibraryImportNodes = () => {
- return importedTestingLibraryNodes;
- };
- const getCustomModuleImportNode = () => {
- return importedCustomModuleNode;
- };
- const getTestingLibraryImportName = () => {
- return (0, node_utils_1.getImportModuleName)(importedTestingLibraryNodes[0]);
- };
- const getCustomModuleImportName = () => {
- return (0, node_utils_1.getImportModuleName)(importedCustomModuleNode);
- };
- const isTestingLibraryImported = (isStrict = false) => {
- const isSomeModuleImported = importedTestingLibraryNodes.length !== 0 || !!importedCustomModuleNode;
- return ((!isStrict && isAggressiveModuleReportingEnabled()) ||
- isSomeModuleImported);
- };
- const isQuery = (node) => {
- const hasQueryPattern = /^(get|query|find)(All)?By.+$/.test(node.name);
- if (!hasQueryPattern) {
- return false;
- }
- if (isAggressiveQueryReportingEnabled()) {
- return true;
- }
- const customQueries = getCustomQueries();
- const isBuiltInQuery = utils_2.ALL_QUERIES_COMBINATIONS.includes(node.name);
- const isReportableCustomQuery = customQueries.some((pattern) => new RegExp(pattern).test(node.name));
- return isBuiltInQuery || isReportableCustomQuery;
- };
- const isGetQueryVariant = (node) => {
- return isQuery(node) && node.name.startsWith('get');
- };
- const isQueryQueryVariant = (node) => {
- return isQuery(node) && node.name.startsWith('query');
- };
- const isFindQueryVariant = (node) => {
- return isQuery(node) && node.name.startsWith('find');
- };
- const isSyncQuery = (node) => {
- return isGetQueryVariant(node) || isQueryQueryVariant(node);
- };
- const isAsyncQuery = (node) => {
- return isFindQueryVariant(node);
- };
- const isCustomQuery = (node) => {
- return isQuery(node) && !utils_2.ALL_QUERIES_COMBINATIONS.includes(node.name);
- };
- const isBuiltInQuery = (node) => {
- return isQuery(node) && utils_2.ALL_QUERIES_COMBINATIONS.includes(node.name);
- };
- const isAsyncUtil = (node, validNames = utils_2.ASYNC_UTILS) => {
- return isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
- return (validNames.includes(identifierNodeName) ||
- (!!originalNodeName &&
- validNames.includes(originalNodeName)));
- });
- };
- const isFireEventUtil = (node) => {
- return isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
- return [identifierNodeName, originalNodeName].includes('fireEvent');
- });
- };
- const isUserEventUtil = (node) => {
- const userEvent = findImportedUserEventSpecifier();
- let userEventName;
- if (userEvent) {
- userEventName = userEvent.name;
- }
- else if (isAggressiveModuleReportingEnabled()) {
- userEventName = USER_EVENT_NAME;
- }
- if (!userEventName) {
- return false;
- }
- return node.name === userEventName;
- };
- const isFireEventMethod = (node) => {
- const fireEventUtil = findImportedTestingLibraryUtilSpecifier(FIRE_EVENT_NAME);
- let fireEventUtilName;
- if (fireEventUtil) {
- fireEventUtilName = utils_1.ASTUtils.isIdentifier(fireEventUtil)
- ? fireEventUtil.name
- : fireEventUtil.local.name;
- }
- else if (isAggressiveModuleReportingEnabled()) {
- fireEventUtilName = FIRE_EVENT_NAME;
- }
- if (!fireEventUtilName) {
- return false;
- }
- const parentMemberExpression = node.parent && (0, node_utils_1.isMemberExpression)(node.parent)
- ? node.parent
- : undefined;
- const parentCallExpression = node.parent && (0, node_utils_1.isCallExpression)(node.parent) ? node.parent : undefined;
- if (!parentMemberExpression && !parentCallExpression) {
- return false;
- }
- if (parentCallExpression) {
- return [fireEventUtilName, FIRE_EVENT_NAME].includes(node.name);
- }
- const definedParentMemberExpression = parentMemberExpression;
- const regularCall = utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object) &&
- (0, node_utils_1.isCallExpression)(definedParentMemberExpression.parent) &&
- definedParentMemberExpression.object.name === fireEventUtilName &&
- node.name !== FIRE_EVENT_NAME &&
- node.name !== fireEventUtilName;
- const wildcardCall = (0, node_utils_1.isMemberExpression)(definedParentMemberExpression.object) &&
- utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object.object) &&
- definedParentMemberExpression.object.object.name ===
- fireEventUtilName &&
- utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object.property) &&
- definedParentMemberExpression.object.property.name ===
- FIRE_EVENT_NAME &&
- node.name !== FIRE_EVENT_NAME &&
- node.name !== fireEventUtilName;
- const wildcardCallWithCallExpression = utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.object) &&
- definedParentMemberExpression.object.name === fireEventUtilName &&
- utils_1.ASTUtils.isIdentifier(definedParentMemberExpression.property) &&
- definedParentMemberExpression.property.name === FIRE_EVENT_NAME &&
- !(0, node_utils_1.isMemberExpression)(definedParentMemberExpression.parent) &&
- node.name === FIRE_EVENT_NAME &&
- node.name !== fireEventUtilName;
- return regularCall || wildcardCall || wildcardCallWithCallExpression;
- };
- const isUserEventMethod = (node) => {
- const userEvent = findImportedUserEventSpecifier();
- let userEventName;
- if (userEvent) {
- userEventName = userEvent.name;
- }
- else if (isAggressiveModuleReportingEnabled()) {
- userEventName = USER_EVENT_NAME;
- }
- if (!userEventName) {
- return false;
- }
- const parentMemberExpression = node.parent && (0, node_utils_1.isMemberExpression)(node.parent)
- ? node.parent
- : undefined;
- if (!parentMemberExpression) {
- return false;
- }
- if ([userEventName, USER_EVENT_NAME].includes(node.name) ||
- (utils_1.ASTUtils.isIdentifier(parentMemberExpression.object) &&
- parentMemberExpression.object.name === node.name)) {
- return false;
- }
- return (utils_1.ASTUtils.isIdentifier(parentMemberExpression.object) &&
- parentMemberExpression.object.name === userEventName);
- };
- const isRenderUtil = (node) => isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
- if (isAggressiveRenderReportingEnabled()) {
- return identifierNodeName.toLowerCase().includes(RENDER_NAME);
- }
- return [RENDER_NAME, ...getCustomRenders()].some((validRenderName) => validRenderName === identifierNodeName ||
- (Boolean(originalNodeName) &&
- validRenderName === originalNodeName));
- });
- const isCreateEventUtil = (node) => {
- const isCreateEventCallback = (identifierNodeName, originalNodeName) => [identifierNodeName, originalNodeName].includes(CREATE_EVENT_NAME);
- if ((0, node_utils_1.isCallExpression)(node) &&
- (0, node_utils_1.isMemberExpression)(node.callee) &&
- utils_1.ASTUtils.isIdentifier(node.callee.object)) {
- return isPotentialTestingLibraryFunction(node.callee.object, isCreateEventCallback);
- }
- if ((0, node_utils_1.isCallExpression)(node) &&
- (0, node_utils_1.isMemberExpression)(node.callee) &&
- (0, node_utils_1.isMemberExpression)(node.callee.object) &&
- utils_1.ASTUtils.isIdentifier(node.callee.object.property)) {
- return isPotentialTestingLibraryFunction(node.callee.object.property, isCreateEventCallback);
- }
- const identifier = (0, node_utils_1.getDeepestIdentifierNode)(node);
- return isPotentialTestingLibraryFunction(identifier, isCreateEventCallback);
- };
- const isRenderVariableDeclarator = (node) => {
- if (!node.init) {
- return false;
- }
- const initIdentifierNode = (0, node_utils_1.getDeepestIdentifierNode)(node.init);
- if (!initIdentifierNode) {
- return false;
- }
- return isRenderUtil(initIdentifierNode);
- };
- const isDebugUtil = (identifierNode, validNames = utils_2.DEBUG_UTILS) => {
- const isBuiltInConsole = (0, node_utils_1.isMemberExpression)(identifierNode.parent) &&
- utils_1.ASTUtils.isIdentifier(identifierNode.parent.object) &&
- identifierNode.parent.object.name === 'console';
- return (!isBuiltInConsole &&
- isPotentialTestingLibraryFunction(identifierNode, (identifierNodeName, originalNodeName) => {
- return (validNames.includes(identifierNodeName) ||
- (!!originalNodeName &&
- validNames.includes(originalNodeName)));
- }));
- };
- const isActUtil = (node) => {
- const isTestingLibraryAct = isPotentialTestingLibraryFunction(node, (identifierNodeName, originalNodeName) => {
- return [identifierNodeName, originalNodeName]
- .filter(Boolean)
- .includes('act');
- });
- const isReactDomTestUtilsAct = (() => {
- if (!importedReactDomTestUtilsNode) {
- return false;
- }
- const referenceNode = (0, node_utils_1.getReferenceNode)(node);
- const referenceNodeIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(referenceNode);
- if (!referenceNodeIdentifier) {
- return false;
- }
- const importedUtilSpecifier = (0, node_utils_1.findImportSpecifier)(node.name, importedReactDomTestUtilsNode);
- if (!importedUtilSpecifier) {
- return false;
- }
- const importDeclaration = (() => {
- if ((0, node_utils_1.isImportDeclaration)(importedUtilSpecifier.parent)) {
- return importedUtilSpecifier.parent;
- }
- const variableDeclarator = (0, node_utils_1.findClosestVariableDeclaratorNode)(importedUtilSpecifier);
- if ((0, node_utils_1.isCallExpression)(variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init)) {
- return variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init;
- }
- return undefined;
- })();
- if (!importDeclaration) {
- return false;
- }
- const importDeclarationName = (0, node_utils_1.getImportModuleName)(importDeclaration);
- if (!importDeclarationName) {
- return false;
- }
- if (importDeclarationName !== REACT_DOM_TEST_UTILS_PACKAGE) {
- return false;
- }
- return (0, node_utils_1.hasImportMatch)(importedUtilSpecifier, referenceNodeIdentifier.name);
- })();
- return isTestingLibraryAct || isReactDomTestUtilsAct;
- };
- const isTestingLibraryUtil = (node) => {
- return (isAsyncUtil(node) ||
- isQuery(node) ||
- isRenderUtil(node) ||
- isFireEventMethod(node) ||
- isUserEventMethod(node) ||
- isActUtil(node) ||
- isCreateEventUtil(node));
- };
- const isPresenceAssert = (node) => {
- const { matcher, isNegated } = (0, node_utils_1.getAssertNodeInfo)(node);
- if (!matcher) {
- return false;
- }
- return isNegated
- ? utils_2.ABSENCE_MATCHERS.includes(matcher)
- : utils_2.PRESENCE_MATCHERS.includes(matcher);
- };
- const isAbsenceAssert = (node) => {
- const { matcher, isNegated } = (0, node_utils_1.getAssertNodeInfo)(node);
- if (!matcher) {
- return false;
- }
- return isNegated
- ? utils_2.PRESENCE_MATCHERS.includes(matcher)
- : utils_2.ABSENCE_MATCHERS.includes(matcher);
- };
- const isMatchingAssert = (node, matcherName) => {
- const { matcher } = (0, node_utils_1.getAssertNodeInfo)(node);
- if (!matcher) {
- return false;
- }
- return matcher === matcherName;
- };
- const findImportedTestingLibraryUtilSpecifier = (specifierName) => {
- var _a;
- const node = (_a = getCustomModuleImportNode()) !== null && _a !== void 0 ? _a : getTestingLibraryImportNode();
- if (!node) {
- return undefined;
- }
- return (0, node_utils_1.findImportSpecifier)(specifierName, node);
- };
- const findImportedUserEventSpecifier = () => {
- if (!importedUserEventLibraryNode) {
- return null;
- }
- if ((0, node_utils_1.isImportDeclaration)(importedUserEventLibraryNode)) {
- const userEventIdentifier = importedUserEventLibraryNode.specifiers.find((specifier) => (0, node_utils_1.isImportDefaultSpecifier)(specifier));
- if (userEventIdentifier) {
- return userEventIdentifier.local;
- }
- }
- else {
- if (!utils_1.ASTUtils.isVariableDeclarator(importedUserEventLibraryNode.parent)) {
- return null;
- }
- const requireNode = importedUserEventLibraryNode.parent;
- if (!utils_1.ASTUtils.isIdentifier(requireNode.id)) {
- return null;
- }
- return requireNode.id;
- }
- return null;
- };
- const getTestingLibraryImportedUtilSpecifier = (node) => {
- var _a;
- const identifierName = (_a = (0, node_utils_1.getPropertyIdentifierNode)(node)) === null || _a === void 0 ? void 0 : _a.name;
- if (!identifierName) {
- return undefined;
- }
- return findImportedTestingLibraryUtilSpecifier(identifierName);
- };
- const canReportErrors = () => {
- return skipRuleReportingCheck || isTestingLibraryImported();
- };
- const isNodeComingFromTestingLibrary = (node) => {
- var _a;
- const importNode = getTestingLibraryImportedUtilSpecifier(node);
- if (!importNode) {
- return false;
- }
- const referenceNode = (0, node_utils_1.getReferenceNode)(node);
- const referenceNodeIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(referenceNode);
- if (!referenceNodeIdentifier) {
- return false;
- }
- const importDeclaration = (() => {
- if ((0, node_utils_1.isImportDeclaration)(importNode.parent)) {
- return importNode.parent;
- }
- const variableDeclarator = (0, node_utils_1.findClosestVariableDeclaratorNode)(importNode);
- if ((0, node_utils_1.isCallExpression)(variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init)) {
- return variableDeclarator === null || variableDeclarator === void 0 ? void 0 : variableDeclarator.init;
- }
- return undefined;
- })();
- if (!importDeclaration) {
- return false;
- }
- const importDeclarationName = (0, node_utils_1.getImportModuleName)(importDeclaration);
- if (!importDeclarationName) {
- return false;
- }
- const identifierName = (_a = (0, node_utils_1.getPropertyIdentifierNode)(node)) === null || _a === void 0 ? void 0 : _a.name;
- if (!identifierName) {
- return false;
- }
- const hasImportElementMatch = (0, node_utils_1.hasImportMatch)(importNode, identifierName);
- const hasImportModuleMatch = /testing-library/g.test(importDeclarationName) ||
- (typeof customModuleSetting === 'string' &&
- importDeclarationName.endsWith(customModuleSetting));
- return hasImportElementMatch && hasImportModuleMatch;
- };
- const helpers = {
- getTestingLibraryImportNode,
- getAllTestingLibraryImportNodes,
- getCustomModuleImportNode,
- getTestingLibraryImportName,
- getCustomModuleImportName,
- isTestingLibraryImported,
- isTestingLibraryUtil,
- isGetQueryVariant,
- isQueryQueryVariant,
- isFindQueryVariant,
- isSyncQuery,
- isAsyncQuery,
- isQuery,
- isCustomQuery,
- isBuiltInQuery,
- isAsyncUtil,
- isFireEventUtil,
- isUserEventUtil,
- isFireEventMethod,
- isUserEventMethod,
- isRenderUtil,
- isCreateEventUtil,
- isRenderVariableDeclarator,
- isDebugUtil,
- isActUtil,
- isPresenceAssert,
- isMatchingAssert,
- isAbsenceAssert,
- canReportErrors,
- findImportedTestingLibraryUtilSpecifier,
- isNodeComingFromTestingLibrary,
- };
- const detectionInstructions = {
- ImportDeclaration(node) {
- if (typeof node.source.value !== 'string') {
- return;
- }
- if (/testing-library/g.test(node.source.value)) {
- importedTestingLibraryNodes.push(node);
- }
- const customModule = getCustomModule();
- if (customModule &&
- !importedCustomModuleNode &&
- node.source.value.endsWith(customModule)) {
- importedCustomModuleNode = node;
- }
- if (!importedUserEventLibraryNode &&
- node.source.value === USER_EVENT_PACKAGE) {
- importedUserEventLibraryNode = node;
- }
- if (!importedUserEventLibraryNode &&
- node.source.value === REACT_DOM_TEST_UTILS_PACKAGE) {
- importedReactDomTestUtilsNode = node;
- }
- },
- [`CallExpression > Identifier[name="require"]`](node) {
- const callExpression = node.parent;
- const { arguments: args } = callExpression;
- if (args.some((arg) => (0, node_utils_1.isLiteral)(arg) &&
- typeof arg.value === 'string' &&
- /testing-library/g.test(arg.value))) {
- importedTestingLibraryNodes.push(callExpression);
- }
- const customModule = getCustomModule();
- if (!importedCustomModuleNode &&
- args.some((arg) => customModule &&
- (0, node_utils_1.isLiteral)(arg) &&
- typeof arg.value === 'string' &&
- arg.value.endsWith(customModule))) {
- importedCustomModuleNode = callExpression;
- }
- if (!importedCustomModuleNode &&
- args.some((arg) => (0, node_utils_1.isLiteral)(arg) &&
- typeof arg.value === 'string' &&
- arg.value === USER_EVENT_PACKAGE)) {
- importedUserEventLibraryNode = callExpression;
- }
- if (!importedReactDomTestUtilsNode &&
- args.some((arg) => (0, node_utils_1.isLiteral)(arg) &&
- typeof arg.value === 'string' &&
- arg.value === REACT_DOM_TEST_UTILS_PACKAGE)) {
- importedReactDomTestUtilsNode = callExpression;
- }
- },
- };
- const ruleInstructions = ruleCreate(context, optionsWithDefault, helpers);
- const enhancedRuleInstructions = {};
- const allKeys = new Set(Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)));
- allKeys.forEach((instruction) => {
- enhancedRuleInstructions[instruction] = (node) => {
- var _a, _b;
- if (instruction in detectionInstructions) {
- (_a = detectionInstructions[instruction]) === null || _a === void 0 ? void 0 : _a.call(detectionInstructions, node);
- }
- if (canReportErrors() && ruleInstructions[instruction]) {
- return (_b = ruleInstructions[instruction]) === null || _b === void 0 ? void 0 : _b.call(ruleInstructions, node);
- }
- return undefined;
- };
- });
- return enhancedRuleInstructions;
- };
- }
- exports.detectTestingLibraryUtils = detectTestingLibraryUtils;
|