Skip to content

Commit

Permalink
refactor: generalized util method
Browse files Browse the repository at this point in the history
  • Loading branch information
gndelia committed Nov 16, 2020
1 parent bb64181 commit 97d89d2
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 51 deletions.
82 changes: 82 additions & 0 deletions lib/node-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
TSESTree,
} from '@typescript-eslint/experimental-utils';
import { RuleContext } from '@typescript-eslint/experimental-utils/dist/ts-eslint';
import { DetectionHelpers } from './detect-testing-library-utils';

export function isCallExpression(
node: TSESTree.Node | null | undefined
Expand Down Expand Up @@ -292,3 +293,84 @@ export function getAssertNodeInfo(

return { matcher, isNegated };
}

/**
* Returns a boolean indicating if the member expression passed as argument comes from a import clause in the provided node
*/
function isMemberFromCallExpressionComingFromImport(
object: TSESTree.Identifier,
importNode: TSESTree.ImportDeclaration
) {
return (
isImportDeclaration(importNode) &&
isImportNamespaceSpecifier(importNode.specifiers[0]) &&
object.name === importNode.specifiers[0].local.name
);
}

/**
* Returns a boolean indicating if the member expression passed as argument comes from a require clause in the provided node
*/
function isMemberFromCallExpressionComingFromRequire(
object: TSESTree.Identifier,
requireNode: TSESTree.CallExpression
) {
return (
isCallExpression(requireNode) &&
isVariableDeclarator(requireNode.parent) &&
isIdentifier(requireNode.parent.id) &&
object.name === requireNode.parent.id.name
);
}

/** Returns a boolean if the MemberExpression matches the one imported from RTL in a custom/standard import/require clause */
export function isMemberFromMethodCallFromTestingLibrary(
node: TSESTree.MemberExpression,
helpers: DetectionHelpers
): boolean {
const importOrRequire =
helpers.getCustomModuleImportNode() ??
helpers.getTestingLibraryImportNode();
if (!isIdentifier(node.object)) {
return false;
}
if (isImportDeclaration(importOrRequire)) {
return isMemberFromCallExpressionComingFromImport(
node.object,
importOrRequire
);
}
return isMemberFromCallExpressionComingFromRequire(
node.object,
importOrRequire
);
}

export function isIdentifierInCallExpressionFromTestingLibrary(
node: TSESTree.Identifier,
helpers: DetectionHelpers
): boolean {
const importOrRequire =
helpers.getCustomModuleImportNode() ??
helpers.getTestingLibraryImportNode();
if (!importOrRequire) {
return false;
}
if (isImportDeclaration(importOrRequire)) {
return importOrRequire.specifiers.some(
(s) => isImportSpecifier(s) && s.local.name === node.name
);
} else {
return (
isVariableDeclarator(importOrRequire.parent) &&
isObjectPattern(importOrRequire.parent.id) &&
importOrRequire.parent.id.properties.some(
(p) =>
isProperty(p) &&
isIdentifier(p.key) &&
isIdentifier(p.value) &&
p.value.name === node.name
)
);
}
}
59 changes: 8 additions & 51 deletions lib/rules/prefer-wait-for.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import {
isIdentifier,
findClosestCallExpressionNode,
isCallExpression,
isImportDeclaration,
isImportNamespaceSpecifier,
isVariableDeclarator,
isObjectPattern,
isProperty,
isMemberFromMethodCallFromTestingLibrary,
isIdentifierInCallExpressionFromTestingLibrary,
} from '../node-utils';

export const RULE_NAME = 'prefer-wait-for';
Expand Down Expand Up @@ -158,62 +158,19 @@ export default createTestingLibraryRule<Options, MessageIds>({
// the method does not match a deprecated method
return;
}
const testingLibraryNode =
helpers.getCustomModuleImportNode() ??
helpers.getTestingLibraryImportNode();
// this verifies the owner of the MemberExpression is the same as the node if it was imported with "import * as TL from 'foo'"
const callerIsTestingLibraryFromImport =
isIdentifier(node.object) &&
isImportDeclaration(testingLibraryNode) &&
isImportNamespaceSpecifier(testingLibraryNode.specifiers[0]) &&
node.object.name === testingLibraryNode.specifiers[0].local.name;
// this verifies the owner of the MemberExpression is the same as the node if it was imported with "const tl = require('foo')"
const callerIsTestingLibraryFromRequire =
isIdentifier(node.object) &&
isCallExpression(testingLibraryNode) &&
isVariableDeclarator(testingLibraryNode.parent) &&
isIdentifier(testingLibraryNode.parent.id) &&
node.object.name === testingLibraryNode.parent.id.name;
if (
!callerIsTestingLibraryFromImport &&
!callerIsTestingLibraryFromRequire
) {
if (!isMemberFromMethodCallFromTestingLibrary(node, helpers)) {
// the method does not match from the imported elements from TL (even from custom)
return;
}
addWaitFor = true;
reportWait(node.property as TSESTree.Identifier); // compiler is not picking up correctly, it should have inferred it is an identifier
},
'CallExpression > Identifier'(node: TSESTree.Identifier) {
const testingLibraryNode =
helpers.getCustomModuleImportNode() ??
helpers.getTestingLibraryImportNode();
// this verifies the owner of the MemberExpression is the same as the node if it was imported with "import { deprecated as aliased } from 'foo'"
const callerIsTestingLibraryFromImport =
isImportDeclaration(testingLibraryNode) &&
testingLibraryNode.specifiers.some(
(s) =>
isImportSpecifier(s) &&
DEPRECATED_METHODS.includes(s.imported.name) &&
s.local.name === node.name
);
// this verifies the owner of the MemberExpression is the same as the node if it was imported with "const { deprecatedMethod } = require('foo')"
const callerIsTestingLibraryFromRequire =
isCallExpression(testingLibraryNode) &&
isVariableDeclarator(testingLibraryNode.parent) &&
isObjectPattern(testingLibraryNode.parent.id) &&
testingLibraryNode.parent.id.properties.some(
(p) =>
isProperty(p) &&
isIdentifier(p.key) &&
isIdentifier(p.value) &&
p.value.name === node.name &&
DEPRECATED_METHODS.includes(p.key.name)
);
if (
!callerIsTestingLibraryFromRequire &&
!callerIsTestingLibraryFromImport
) {
if (!DEPRECATED_METHODS.includes(node.name)) {
return;
}

if (!isIdentifierInCallExpressionFromTestingLibrary(node, helpers)) {
return;
}
addWaitFor = true;
Expand Down

0 comments on commit 97d89d2

Please sign in to comment.