1
+ import { ASTUtils , TSESTree } from '@typescript-eslint/experimental-utils' ;
2
+ import { createTestingLibraryRule } from '../create-testing-library-rule' ;
1
3
import {
2
- TSESTree ,
3
- ESLintUtils ,
4
- ASTUtils ,
5
- } from '@typescript-eslint/experimental-utils' ;
6
- import { getDocsUrl , ASYNC_QUERIES_VARIANTS } from '../utils' ;
7
- import {
8
- isNewExpression ,
9
- isImportSpecifier ,
4
+ findClosestCallExpressionNode ,
5
+ getIdentifierNode ,
10
6
isCallExpression ,
7
+ isNewExpression ,
8
+ isPromiseIdentifier ,
11
9
} from '../node-utils' ;
12
10
13
11
export const RULE_NAME = 'no-promise-in-fire-event' ;
14
12
export type MessageIds = 'noPromiseInFireEvent' ;
15
13
type Options = [ ] ;
16
14
17
- export default ESLintUtils . RuleCreator ( getDocsUrl ) < Options , MessageIds > ( {
15
+ export default createTestingLibraryRule < Options , MessageIds > ( {
18
16
name : RULE_NAME ,
19
17
meta : {
20
18
type : 'problem' ,
@@ -28,49 +26,74 @@ export default ESLintUtils.RuleCreator(getDocsUrl)<Options, MessageIds>({
28
26
noPromiseInFireEvent :
29
27
"A promise shouldn't be passed to a `fireEvent` method, instead pass the DOM element" ,
30
28
} ,
31
- fixable : 'code' ,
29
+ fixable : null ,
32
30
schema : [ ] ,
33
31
} ,
34
32
defaultOptions : [ ] ,
35
33
36
- create ( context ) {
37
- return {
38
- 'ImportDeclaration[source.value=/testing-library/]' (
39
- node : TSESTree . ImportDeclaration
40
- ) {
41
- const fireEventImportNode = node . specifiers . find (
42
- ( specifier ) =>
43
- isImportSpecifier ( specifier ) &&
44
- specifier . imported &&
45
- 'fireEvent' === specifier . imported . name
46
- ) as TSESTree . ImportSpecifier ;
34
+ create ( context , _ , helpers ) {
35
+ function checkSuspiciousNode (
36
+ node : TSESTree . Node ,
37
+ originalNode ?: TSESTree . Node
38
+ ) : void {
39
+ if ( ASTUtils . isAwaitExpression ( node ) ) {
40
+ return ;
41
+ }
47
42
48
- const { references } = context . getDeclaredVariables (
49
- fireEventImportNode
50
- ) [ 0 ] ;
43
+ if ( isNewExpression ( node ) ) {
44
+ if ( isPromiseIdentifier ( node . callee ) ) {
45
+ return context . report ( {
46
+ node : originalNode ?? node ,
47
+ messageId : 'noPromiseInFireEvent' ,
48
+ } ) ;
49
+ }
50
+ }
51
51
52
- for ( const reference of references ) {
53
- const referenceNode = reference . identifier ;
54
- const callExpression = referenceNode . parent
55
- . parent as TSESTree . CallExpression ;
56
- const [ element ] = callExpression . arguments as TSESTree . Node [ ] ;
57
- if ( isCallExpression ( element ) || isNewExpression ( element ) ) {
58
- const methodName = ASTUtils . isIdentifier ( element . callee )
59
- ? element . callee . name
60
- : ( ( element . callee as TSESTree . MemberExpression )
61
- . property as TSESTree . Identifier ) . name ;
52
+ if ( isCallExpression ( node ) ) {
53
+ const domElementIdentifier = getIdentifierNode ( node ) ;
54
+
55
+ if (
56
+ helpers . isAsyncQuery ( domElementIdentifier ) ||
57
+ isPromiseIdentifier ( domElementIdentifier )
58
+ ) {
59
+ return context . report ( {
60
+ node : originalNode ?? node ,
61
+ messageId : 'noPromiseInFireEvent' ,
62
+ } ) ;
63
+ }
64
+ }
65
+
66
+ if ( ASTUtils . isIdentifier ( node ) ) {
67
+ const nodeVariable = ASTUtils . findVariable (
68
+ context . getScope ( ) ,
69
+ node . name
70
+ ) ;
71
+ if ( ! nodeVariable || ! nodeVariable . defs ) {
72
+ return ;
73
+ }
62
74
63
- if (
64
- ASYNC_QUERIES_VARIANTS . some ( ( q ) => methodName . startsWith ( q ) ) ||
65
- methodName === 'Promise'
66
- ) {
67
- context . report ( {
68
- node : element ,
69
- messageId : 'noPromiseInFireEvent' ,
70
- } ) ;
71
- }
72
- }
75
+ for ( const definition of nodeVariable . defs ) {
76
+ const variableDeclarator = definition . node as TSESTree . VariableDeclarator ;
77
+ checkSuspiciousNode ( variableDeclarator . init , node ) ;
73
78
}
79
+ }
80
+ }
81
+
82
+ return {
83
+ 'CallExpression Identifier' ( node : TSESTree . Identifier ) {
84
+ if ( ! helpers . isFireEventMethod ( node ) ) {
85
+ return ;
86
+ }
87
+
88
+ const closestCallExpression = findClosestCallExpressionNode ( node , true ) ;
89
+
90
+ if ( ! closestCallExpression ) {
91
+ return ;
92
+ }
93
+
94
+ const domElementArgument = closestCallExpression . arguments [ 0 ] ;
95
+
96
+ checkSuspiciousNode ( domElementArgument ) ;
74
97
} ,
75
98
} ;
76
99
} ,
0 commit comments