Skip to content

Commit 97d89d2

Browse files
committed
refactor: generalized util method
1 parent bb64181 commit 97d89d2

File tree

2 files changed

+90
-51
lines changed

2 files changed

+90
-51
lines changed

lib/node-utils.ts

+82
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
TSESTree,
66
} from '@typescript-eslint/experimental-utils';
77
import { RuleContext } from '@typescript-eslint/experimental-utils/dist/ts-eslint';
8+
import { DetectionHelpers } from './detect-testing-library-utils';
89

910
export function isCallExpression(
1011
node: TSESTree.Node | null | undefined
@@ -292,3 +293,84 @@ export function getAssertNodeInfo(
292293

293294
return { matcher, isNegated };
294295
}
296+
297+
/**
298+
* Returns a boolean indicating if the member expression passed as argument comes from a import clause in the provided node
299+
*/
300+
function isMemberFromCallExpressionComingFromImport(
301+
object: TSESTree.Identifier,
302+
importNode: TSESTree.ImportDeclaration
303+
) {
304+
return (
305+
isImportDeclaration(importNode) &&
306+
isImportNamespaceSpecifier(importNode.specifiers[0]) &&
307+
object.name === importNode.specifiers[0].local.name
308+
);
309+
}
310+
311+
/**
312+
* Returns a boolean indicating if the member expression passed as argument comes from a require clause in the provided node
313+
*/
314+
function isMemberFromCallExpressionComingFromRequire(
315+
object: TSESTree.Identifier,
316+
requireNode: TSESTree.CallExpression
317+
) {
318+
return (
319+
isCallExpression(requireNode) &&
320+
isVariableDeclarator(requireNode.parent) &&
321+
isIdentifier(requireNode.parent.id) &&
322+
object.name === requireNode.parent.id.name
323+
);
324+
}
325+
326+
/** Returns a boolean if the MemberExpression matches the one imported from RTL in a custom/standard import/require clause */
327+
export function isMemberFromMethodCallFromTestingLibrary(
328+
node: TSESTree.MemberExpression,
329+
helpers: DetectionHelpers
330+
): boolean {
331+
const importOrRequire =
332+
helpers.getCustomModuleImportNode() ??
333+
helpers.getTestingLibraryImportNode();
334+
if (!isIdentifier(node.object)) {
335+
return false;
336+
}
337+
if (isImportDeclaration(importOrRequire)) {
338+
return isMemberFromCallExpressionComingFromImport(
339+
node.object,
340+
importOrRequire
341+
);
342+
}
343+
return isMemberFromCallExpressionComingFromRequire(
344+
node.object,
345+
importOrRequire
346+
);
347+
}
348+
349+
export function isIdentifierInCallExpressionFromTestingLibrary(
350+
node: TSESTree.Identifier,
351+
helpers: DetectionHelpers
352+
): boolean {
353+
const importOrRequire =
354+
helpers.getCustomModuleImportNode() ??
355+
helpers.getTestingLibraryImportNode();
356+
if (!importOrRequire) {
357+
return false;
358+
}
359+
if (isImportDeclaration(importOrRequire)) {
360+
return importOrRequire.specifiers.some(
361+
(s) => isImportSpecifier(s) && s.local.name === node.name
362+
);
363+
} else {
364+
return (
365+
isVariableDeclarator(importOrRequire.parent) &&
366+
isObjectPattern(importOrRequire.parent.id) &&
367+
importOrRequire.parent.id.properties.some(
368+
(p) =>
369+
isProperty(p) &&
370+
isIdentifier(p.key) &&
371+
isIdentifier(p.value) &&
372+
p.value.name === node.name
373+
)
374+
);
375+
}
376+
}

lib/rules/prefer-wait-for.ts

+8-51
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import {
66
isIdentifier,
77
findClosestCallExpressionNode,
88
isCallExpression,
9-
isImportDeclaration,
109
isImportNamespaceSpecifier,
11-
isVariableDeclarator,
1210
isObjectPattern,
1311
isProperty,
12+
isMemberFromMethodCallFromTestingLibrary,
13+
isIdentifierInCallExpressionFromTestingLibrary,
1414
} from '../node-utils';
1515

1616
export const RULE_NAME = 'prefer-wait-for';
@@ -158,62 +158,19 @@ export default createTestingLibraryRule<Options, MessageIds>({
158158
// the method does not match a deprecated method
159159
return;
160160
}
161-
const testingLibraryNode =
162-
helpers.getCustomModuleImportNode() ??
163-
helpers.getTestingLibraryImportNode();
164-
// this verifies the owner of the MemberExpression is the same as the node if it was imported with "import * as TL from 'foo'"
165-
const callerIsTestingLibraryFromImport =
166-
isIdentifier(node.object) &&
167-
isImportDeclaration(testingLibraryNode) &&
168-
isImportNamespaceSpecifier(testingLibraryNode.specifiers[0]) &&
169-
node.object.name === testingLibraryNode.specifiers[0].local.name;
170-
// this verifies the owner of the MemberExpression is the same as the node if it was imported with "const tl = require('foo')"
171-
const callerIsTestingLibraryFromRequire =
172-
isIdentifier(node.object) &&
173-
isCallExpression(testingLibraryNode) &&
174-
isVariableDeclarator(testingLibraryNode.parent) &&
175-
isIdentifier(testingLibraryNode.parent.id) &&
176-
node.object.name === testingLibraryNode.parent.id.name;
177-
if (
178-
!callerIsTestingLibraryFromImport &&
179-
!callerIsTestingLibraryFromRequire
180-
) {
161+
if (!isMemberFromMethodCallFromTestingLibrary(node, helpers)) {
181162
// the method does not match from the imported elements from TL (even from custom)
182163
return;
183164
}
184165
addWaitFor = true;
185166
reportWait(node.property as TSESTree.Identifier); // compiler is not picking up correctly, it should have inferred it is an identifier
186167
},
187168
'CallExpression > Identifier'(node: TSESTree.Identifier) {
188-
const testingLibraryNode =
189-
helpers.getCustomModuleImportNode() ??
190-
helpers.getTestingLibraryImportNode();
191-
// this verifies the owner of the MemberExpression is the same as the node if it was imported with "import { deprecated as aliased } from 'foo'"
192-
const callerIsTestingLibraryFromImport =
193-
isImportDeclaration(testingLibraryNode) &&
194-
testingLibraryNode.specifiers.some(
195-
(s) =>
196-
isImportSpecifier(s) &&
197-
DEPRECATED_METHODS.includes(s.imported.name) &&
198-
s.local.name === node.name
199-
);
200-
// this verifies the owner of the MemberExpression is the same as the node if it was imported with "const { deprecatedMethod } = require('foo')"
201-
const callerIsTestingLibraryFromRequire =
202-
isCallExpression(testingLibraryNode) &&
203-
isVariableDeclarator(testingLibraryNode.parent) &&
204-
isObjectPattern(testingLibraryNode.parent.id) &&
205-
testingLibraryNode.parent.id.properties.some(
206-
(p) =>
207-
isProperty(p) &&
208-
isIdentifier(p.key) &&
209-
isIdentifier(p.value) &&
210-
p.value.name === node.name &&
211-
DEPRECATED_METHODS.includes(p.key.name)
212-
);
213-
if (
214-
!callerIsTestingLibraryFromRequire &&
215-
!callerIsTestingLibraryFromImport
216-
) {
169+
if (!DEPRECATED_METHODS.includes(node.name)) {
170+
return;
171+
}
172+
173+
if (!isIdentifierInCallExpressionFromTestingLibrary(node, helpers)) {
217174
return;
218175
}
219176
addWaitFor = true;

0 commit comments

Comments
 (0)