@@ -6,37 +6,41 @@ import {
6
6
DescribeAlias ,
7
7
TestCaseName ,
8
8
createRule ,
9
+ getNodeName ,
9
10
isDescribe ,
10
11
isExpectCall ,
11
12
isFunction ,
12
13
isTestCase ,
13
14
} from './utils' ;
14
15
15
16
const getBlockType = (
16
- stmt : TSESTree . BlockStatement ,
17
- ) : 'function' | DescribeAlias . describe | null => {
18
- const func = stmt . parent ;
17
+ statement : TSESTree . BlockStatement ,
18
+ ) : 'function' | ' describe' | null => {
19
+ const func = statement . parent ;
19
20
20
21
/* istanbul ignore if */
21
22
if ( ! func ) {
22
23
throw new Error (
23
24
`Unexpected BlockStatement. No parent defined. - please file a github issue at https://github.com/jest-community/eslint-plugin-jest` ,
24
25
) ;
25
26
}
27
+
26
28
// functionDeclaration: function func() {}
27
29
if ( func . type === AST_NODE_TYPES . FunctionDeclaration ) {
28
30
return 'function' ;
29
31
}
32
+
30
33
if ( isFunction ( func ) && func . parent ) {
31
34
const expr = func . parent ;
32
35
33
- // arrowfunction or function expr
36
+ // arrow function or function expr
34
37
if ( expr . type === AST_NODE_TYPES . VariableDeclarator ) {
35
38
return 'function' ;
36
39
}
40
+
37
41
// if it's not a variable, it will be callExpr, we only care about describe
38
42
if ( expr . type === AST_NODE_TYPES . CallExpression && isDescribe ( expr ) ) {
39
- return DescribeAlias . describe ;
43
+ return ' describe' ;
40
44
}
41
45
}
42
46
@@ -51,14 +55,12 @@ const isEach = (node: TSESTree.CallExpression): boolean =>
51
55
node . callee . callee . object . type === AST_NODE_TYPES . Identifier &&
52
56
TestCaseName . hasOwnProperty ( node . callee . callee . object . name ) ;
53
57
54
- type callStackEntry =
55
- | TestCaseName . test
56
- | 'function'
57
- | DescribeAlias . describe
58
- | 'arrowFunc'
59
- | 'template' ;
58
+ type BlockType = 'test' | 'function' | 'describe' | 'arrow' | 'template' ;
60
59
61
- export default createRule ( {
60
+ export default createRule <
61
+ [ { additionalTestBlockFunctions : string [ ] } ] ,
62
+ 'unexpectedExpect'
63
+ > ( {
62
64
name : __filename ,
63
65
meta : {
64
66
docs : {
@@ -70,11 +72,29 @@ export default createRule({
70
72
unexpectedExpect : 'Expect must be inside of a test block.' ,
71
73
} ,
72
74
type : 'suggestion' ,
73
- schema : [ ] ,
75
+ schema : [
76
+ {
77
+ properties : {
78
+ additionalTestBlockFunctions : {
79
+ type : 'array' ,
80
+ items : { type : 'string' } ,
81
+ } ,
82
+ } ,
83
+ additionalProperties : false ,
84
+ } ,
85
+ ] ,
74
86
} ,
75
- defaultOptions : [ ] ,
76
- create ( context ) {
77
- const callStack : callStackEntry [ ] = [ ] ;
87
+ defaultOptions : [ { additionalTestBlockFunctions : [ ] } ] ,
88
+ create ( context , [ { additionalTestBlockFunctions = [ ] } ] ) {
89
+ const callStack : BlockType [ ] = [ ] ;
90
+
91
+ const isCustomTestBlockFunction = (
92
+ node : TSESTree . CallExpression ,
93
+ ) : boolean =>
94
+ additionalTestBlockFunctions . includes ( getNodeName ( node ) || '' ) ;
95
+
96
+ const isTestBlock = ( node : TSESTree . CallExpression ) : boolean =>
97
+ isTestCase ( node ) || isCustomTestBlockFunction ( node ) ;
78
98
79
99
return {
80
100
CallExpression ( node ) {
@@ -87,9 +107,11 @@ export default createRule({
87
107
88
108
return ;
89
109
}
90
- if ( isTestCase ( node ) ) {
91
- callStack . push ( TestCaseName . test ) ;
110
+
111
+ if ( isTestBlock ( node ) ) {
112
+ callStack . push ( 'test' ) ;
92
113
}
114
+
93
115
if ( node . callee . type === AST_NODE_TYPES . TaggedTemplateExpression ) {
94
116
callStack . push ( 'template' ) ;
95
117
}
@@ -98,37 +120,37 @@ export default createRule({
98
120
const top = callStack [ callStack . length - 1 ] ;
99
121
100
122
if (
101
- ( ( ( isTestCase ( node ) &&
102
- node . callee . type !== AST_NODE_TYPES . MemberExpression ) ||
103
- isEach ( node ) ) &&
104
- top === TestCaseName . test ) ||
105
- ( node . callee . type === AST_NODE_TYPES . TaggedTemplateExpression &&
106
- top === 'template' )
123
+ ( top === 'test' &&
124
+ ( isEach ( node ) ||
125
+ ( isTestBlock ( node ) &&
126
+ node . callee . type !== AST_NODE_TYPES . MemberExpression ) ) ) ||
127
+ ( top === 'template' &&
128
+ node . callee . type === AST_NODE_TYPES . TaggedTemplateExpression )
107
129
) {
108
130
callStack . pop ( ) ;
109
131
}
110
132
} ,
111
- BlockStatement ( stmt ) {
112
- const blockType = getBlockType ( stmt ) ;
133
+
134
+ BlockStatement ( statement ) {
135
+ const blockType = getBlockType ( statement ) ;
113
136
114
137
if ( blockType ) {
115
138
callStack . push ( blockType ) ;
116
139
}
117
140
} ,
118
- 'BlockStatement:exit' ( stmt : TSESTree . BlockStatement ) {
119
- const blockType = getBlockType ( stmt ) ;
120
-
121
- if ( blockType && blockType === callStack [ callStack . length - 1 ] ) {
141
+ 'BlockStatement:exit' ( statement : TSESTree . BlockStatement ) {
142
+ if ( callStack [ callStack . length - 1 ] === getBlockType ( statement ) ) {
122
143
callStack . pop ( ) ;
123
144
}
124
145
} ,
146
+
125
147
ArrowFunctionExpression ( node ) {
126
- if ( node . parent && node . parent . type !== AST_NODE_TYPES . CallExpression ) {
127
- callStack . push ( 'arrowFunc ' ) ;
148
+ if ( node . parent ? .type !== AST_NODE_TYPES . CallExpression ) {
149
+ callStack . push ( 'arrow ' ) ;
128
150
}
129
151
} ,
130
152
'ArrowFunctionExpression:exit' ( ) {
131
- if ( callStack [ callStack . length - 1 ] === 'arrowFunc ' ) {
153
+ if ( callStack [ callStack . length - 1 ] === 'arrow ' ) {
132
154
callStack . pop ( ) ;
133
155
}
134
156
} ,
0 commit comments