@@ -2,12 +2,15 @@ import { TSESTree, ASTUtils, TSESLint } from '@typescript-eslint/utils';
2
2
3
3
import { createTestingLibraryRule } from '../create-testing-library-rule' ;
4
4
import {
5
+ getDeepestIdentifierNode ,
5
6
isArrowFunctionExpression ,
7
+ isBlockStatement ,
6
8
isCallExpression ,
7
9
isMemberExpression ,
8
10
isObjectExpression ,
9
11
isObjectPattern ,
10
12
isProperty ,
13
+ isVariableDeclaration ,
11
14
} from '../node-utils' ;
12
15
import { getScope , getSourceCode } from '../utils' ;
13
16
@@ -329,20 +332,82 @@ export default createTestingLibraryRule<Options, MessageIds>({
329
332
}
330
333
331
334
return {
332
- 'AwaitExpression > CallExpression' ( node : TSESTree . CallExpression ) {
335
+ 'AwaitExpression > CallExpression' (
336
+ node : TSESTree . CallExpression & { parent : TSESTree . AwaitExpression }
337
+ ) {
333
338
if (
334
339
! ASTUtils . isIdentifier ( node . callee ) ||
335
340
! helpers . isAsyncUtil ( node . callee , [ 'waitFor' ] )
336
341
) {
337
342
return ;
338
343
}
339
- // ensure the only argument is an arrow function expression - if the arrow function is a block
340
- // we skip it
344
+ // ensure the only argument is an arrow function expression
341
345
const argument = node . arguments [ 0 ] ;
342
- if (
343
- ! isArrowFunctionExpression ( argument ) ||
344
- ! isCallExpression ( argument . body )
345
- ) {
346
+
347
+ if ( ! isArrowFunctionExpression ( argument ) ) {
348
+ return ;
349
+ }
350
+
351
+ if ( isBlockStatement ( argument . body ) && argument . async ) {
352
+ const { body } = argument . body ;
353
+ const declarations = body
354
+ . filter ( isVariableDeclaration )
355
+ ?. flatMap ( ( declaration ) => declaration . declarations ) ;
356
+
357
+ const findByDeclarator = declarations . find ( ( declaration ) => {
358
+ if (
359
+ ! ASTUtils . isAwaitExpression ( declaration . init ) ||
360
+ ! isCallExpression ( declaration . init . argument )
361
+ ) {
362
+ return false ;
363
+ }
364
+
365
+ const { callee } = declaration . init . argument ;
366
+ const node = getDeepestIdentifierNode ( callee ) ;
367
+ return node ? helpers . isFindQueryVariant ( node ) : false ;
368
+ } ) ;
369
+
370
+ const init = ASTUtils . isAwaitExpression ( findByDeclarator ?. init )
371
+ ? findByDeclarator . init . argument
372
+ : null ;
373
+
374
+ if ( ! isCallExpression ( init ) ) {
375
+ return ;
376
+ }
377
+ const queryIdentifier = getDeepestIdentifierNode ( init . callee ) ;
378
+
379
+ // ensure the query is a supported async query like findBy*
380
+ if ( ! queryIdentifier || ! helpers . isAsyncQuery ( queryIdentifier ) ) {
381
+ return ;
382
+ }
383
+
384
+ const fullQueryMethod = queryIdentifier . name ;
385
+ const queryMethod = fullQueryMethod . split ( 'By' ) [ 1 ] ;
386
+ const queryVariant = getFindByQueryVariant ( fullQueryMethod ) ;
387
+
388
+ reportInvalidUsage ( node , {
389
+ queryMethod,
390
+ queryVariant,
391
+ prevQuery : fullQueryMethod ,
392
+ fix ( fixer ) {
393
+ const { parent : expressionStatement } = node . parent ;
394
+ const bodyText = sourceCode
395
+ . getText ( argument . body )
396
+ . slice ( 1 , - 1 )
397
+ . trim ( ) ;
398
+ const { line, column } = expressionStatement . loc . start ;
399
+ const indent = sourceCode . getLines ( ) [ line - 1 ] . slice ( 0 , column ) ;
400
+ const newText = bodyText
401
+ . split ( '\n' )
402
+ . map ( ( line ) => line . trim ( ) )
403
+ . join ( `\n${ indent } ` ) ;
404
+ return fixer . replaceText ( expressionStatement , newText ) ;
405
+ } ,
406
+ } ) ;
407
+ return ;
408
+ }
409
+
410
+ if ( ! isCallExpression ( argument . body ) ) {
346
411
return ;
347
412
}
348
413
0 commit comments