88 getImportModuleName ,
99 getPropertyIdentifierNode ,
1010 getReferenceNode ,
11+ hasImportMatch ,
1112 ImportModuleNode ,
1213 isImportDeclaration ,
1314 isImportNamespaceSpecifier ,
@@ -127,22 +128,41 @@ export function detectTestingLibraryUtils<
127128 /**
128129 * Small method to extract common checks to determine whether a node is
129130 * related to Testing Library or not.
131+ *
132+ * To determine whether a node is a valid Testing Library util, there are
133+ * two conditions to match:
134+ * - it's named in a particular way (decided by given callback)
135+ * - it's imported from valid Testing Library module (depends on aggressive
136+ * reporting)
130137 */
131138 function isTestingLibraryUtil (
132139 node : TSESTree . Identifier ,
133- isUtilCallback : ( identifierNode : TSESTree . Identifier ) => boolean
140+ isUtilCallback : (
141+ identifierNodeName : string ,
142+ originalNodeName ?: string
143+ ) => boolean
134144 ) : boolean {
135- if ( ! isUtilCallback ( node ) ) {
145+ const referenceNode = getReferenceNode ( node ) ;
146+ const referenceNodeIdentifier = getPropertyIdentifierNode ( referenceNode ) ;
147+ const importedUtilSpecifier = getImportedUtilSpecifier (
148+ referenceNodeIdentifier
149+ ) ;
150+
151+ const originalNodeName =
152+ isImportSpecifier ( importedUtilSpecifier ) &&
153+ importedUtilSpecifier . local . name !== importedUtilSpecifier . imported . name
154+ ? importedUtilSpecifier . imported . name
155+ : undefined ;
156+
157+ if ( ! isUtilCallback ( node . name , originalNodeName ) ) {
136158 return false ;
137159 }
138160
139- const referenceNode = getReferenceNode ( node ) ;
140- const referenceNodeIdentifier = getPropertyIdentifierNode ( referenceNode ) ;
161+ if ( isAggressiveModuleReportingEnabled ( ) ) {
162+ return true ;
163+ }
141164
142- return (
143- isAggressiveModuleReportingEnabled ( ) ||
144- isNodeComingFromTestingLibrary ( referenceNodeIdentifier )
145- ) ;
165+ return isNodeComingFromTestingLibrary ( referenceNodeIdentifier ) ;
146166 }
147167
148168 /**
@@ -272,8 +292,8 @@ export function detectTestingLibraryUtils<
272292 * coming from Testing Library will be considered as valid.
273293 */
274294 const isAsyncUtil : IsAsyncUtilFn = ( node ) => {
275- return isTestingLibraryUtil ( node , ( identifierNode ) =>
276- ASYNC_UTILS . includes ( identifierNode . name )
295+ return isTestingLibraryUtil ( node , ( identifierNodeName ) =>
296+ ASYNC_UTILS . includes ( identifierNodeName )
277297 ) ;
278298 } ;
279299
@@ -347,13 +367,27 @@ export function detectTestingLibraryUtils<
347367 * only those nodes coming from Testing Library will be considered as valid.
348368 */
349369 const isRenderUtil : IsRenderUtilFn = ( node ) => {
350- return isTestingLibraryUtil ( node , ( identifierNode ) => {
351- if ( isAggressiveRenderReportingEnabled ( ) ) {
352- return identifierNode . name . toLowerCase ( ) . includes ( RENDER_NAME ) ;
370+ return isTestingLibraryUtil (
371+ node ,
372+ ( identifierNodeName , originalNodeName ) => {
373+ if ( isAggressiveRenderReportingEnabled ( ) ) {
374+ return identifierNodeName . toLowerCase ( ) . includes ( RENDER_NAME ) ;
375+ }
376+
377+ return [ RENDER_NAME , ...customRenders ] . some ( ( validRenderName ) => {
378+ let isMatch = false ;
379+
380+ if ( validRenderName === identifierNodeName ) {
381+ isMatch = true ;
382+ }
383+
384+ if ( ! ! originalNodeName && validRenderName === originalNodeName ) {
385+ isMatch = true ;
386+ }
387+ return isMatch ;
388+ } ) ;
353389 }
354-
355- return [ RENDER_NAME , ...customRenders ] . includes ( identifierNode . name ) ;
356- } ) ;
390+ ) ;
357391 } ;
358392
359393 /**
@@ -402,25 +436,34 @@ export function detectTestingLibraryUtils<
402436 specifierName
403437 ) => {
404438 const node = getCustomModuleImportNode ( ) ?? getTestingLibraryImportNode ( ) ;
439+
405440 if ( ! node ) {
406441 return null ;
407442 }
443+
408444 if ( isImportDeclaration ( node ) ) {
409- const namedExport = node . specifiers . find (
410- ( n ) => isImportSpecifier ( n ) && n . imported . name === specifierName
411- ) ;
445+ const namedExport = node . specifiers . find ( ( n ) => {
446+ return (
447+ isImportSpecifier ( n ) &&
448+ [ n . imported . name , n . local . name ] . includes ( specifierName )
449+ ) ;
450+ } ) ;
451+
412452 // it is "import { foo [as alias] } from 'baz'""
413453 if ( namedExport ) {
414454 return namedExport ;
415455 }
456+
416457 // it could be "import * as rtl from 'baz'"
417458 return node . specifiers . find ( ( n ) => isImportNamespaceSpecifier ( n ) ) ;
418459 } else {
419460 const requireNode = node . parent as TSESTree . VariableDeclarator ;
461+
420462 if ( ASTUtils . isIdentifier ( requireNode . id ) ) {
421463 // this is const rtl = require('foo')
422464 return requireNode . id ;
423465 }
466+
424467 // this should be const { something } = require('foo')
425468 const destructuring = requireNode . id as TSESTree . ObjectPattern ;
426469 const property = destructuring . properties . find (
@@ -429,27 +472,48 @@ export function detectTestingLibraryUtils<
429472 ASTUtils . isIdentifier ( n . key ) &&
430473 n . key . name === specifierName
431474 ) ;
475+ if ( ! property ) {
476+ return undefined ;
477+ }
432478 return ( property as TSESTree . Property ) . key as TSESTree . Identifier ;
433479 }
434480 } ;
435481
482+ const getImportedUtilSpecifier = (
483+ node : TSESTree . MemberExpression | TSESTree . Identifier
484+ ) : TSESTree . ImportClause | TSESTree . Identifier | undefined => {
485+ const identifierName : string | undefined = getPropertyIdentifierNode ( node )
486+ . name ;
487+
488+ return findImportedUtilSpecifier ( identifierName ) ;
489+ } ;
490+
436491 /**
437492 * Determines if file inspected meets all conditions to be reported by rules or not.
438493 */
439494 const canReportErrors : CanReportErrorsFn = ( ) => {
440495 return isTestingLibraryImported ( ) && isValidFilename ( ) ;
441496 } ;
497+
442498 /**
443- * Takes a MemberExpression or an Identifier and verifies if its name comes from the import in TL
444- * @param node a MemberExpression (in "foo.property" it would be property) or an Identifier
499+ * Determines whether a node is imported from a valid Testing Library module
500+ *
501+ * This method will try to find any import matching the given node name,
502+ * and also make sure the name is a valid match in case it's been renamed.
445503 */
446504 const isNodeComingFromTestingLibrary : IsNodeComingFromTestingLibraryFn = (
447505 node
448506 ) => {
507+ const importNode = getImportedUtilSpecifier ( node ) ;
508+
509+ if ( ! importNode ) {
510+ return false ;
511+ }
512+
449513 const identifierName : string | undefined = getPropertyIdentifierNode ( node )
450514 . name ;
451515
452- return ! ! findImportedUtilSpecifier ( identifierName ) ;
516+ return hasImportMatch ( importNode , identifierName ) ;
453517 } ;
454518
455519 const helpers : DetectionHelpers = {
0 commit comments