eslint-plugin-jest 27.1.2 → 27.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -80
- package/docs/rules/consistent-test-it.md +4 -11
- package/docs/rules/expect-expect.md +3 -4
- package/docs/rules/max-expects.md +1 -5
- package/docs/rules/max-nested-describe.md +1 -5
- package/docs/rules/no-alias-methods.md +8 -10
- package/docs/rules/no-commented-out-tests.md +3 -4
- package/docs/rules/no-conditional-expect.md +4 -5
- package/docs/rules/no-conditional-in-test.md +1 -5
- package/docs/rules/no-deprecated-functions.md +5 -7
- package/docs/rules/no-disabled-tests.md +3 -4
- package/docs/rules/no-done-callback.md +6 -8
- package/docs/rules/no-duplicate-hooks.md +1 -5
- package/docs/rules/no-export.md +3 -4
- package/docs/rules/no-focused-tests.md +5 -7
- package/docs/rules/no-hooks.md +1 -5
- package/docs/rules/no-identical-title.md +3 -4
- package/docs/rules/no-if.md +2 -2
- package/docs/rules/no-interpolation-in-snapshots.md +3 -4
- package/docs/rules/no-jasmine-globals.md +6 -8
- package/docs/rules/no-large-snapshots.md +2 -6
- package/docs/rules/no-mocks-import.md +3 -4
- package/docs/rules/no-restricted-jest-methods.md +1 -5
- package/docs/rules/no-restricted-matchers.md +1 -5
- package/docs/rules/no-standalone-expect.md +3 -4
- package/docs/rules/no-test-prefixes.md +6 -8
- package/docs/rules/no-test-return-statement.md +1 -5
- package/docs/rules/prefer-called-with.md +1 -5
- package/docs/rules/prefer-comparison-matcher.md +3 -8
- package/docs/rules/prefer-each.md +1 -5
- package/docs/rules/prefer-equality-matcher.md +3 -8
- package/docs/rules/prefer-expect-assertions.md +3 -10
- package/docs/rules/prefer-expect-resolves.md +3 -8
- package/docs/rules/prefer-hooks-in-order.md +1 -5
- package/docs/rules/prefer-hooks-on-top.md +1 -5
- package/docs/rules/prefer-lowercase-title.md +3 -8
- package/docs/rules/prefer-mock-promise-shorthand.md +3 -8
- package/docs/rules/prefer-snapshot-hint.md +1 -5
- package/docs/rules/prefer-spy-on.md +3 -10
- package/docs/rules/prefer-strict-equal.md +3 -10
- package/docs/rules/prefer-to-be.md +5 -7
- package/docs/rules/prefer-to-contain.md +5 -9
- package/docs/rules/prefer-to-have-length.md +5 -9
- package/docs/rules/prefer-todo.md +3 -10
- package/docs/rules/require-hook.md +1 -5
- package/docs/rules/require-to-throw-message.md +1 -7
- package/docs/rules/require-top-level-describe.md +1 -5
- package/docs/rules/unbound-method.md +2 -4
- package/docs/rules/valid-describe-callback.md +3 -4
- package/docs/rules/valid-expect-in-promise.md +4 -5
- package/docs/rules/valid-expect.md +3 -6
- package/docs/rules/valid-title.md +5 -7
- package/lib/index.js +8 -16
- package/lib/processors/snapshot-processor.js +3 -5
- package/lib/rules/consistent-test-it.js +1 -19
- package/lib/rules/expect-expect.js +0 -15
- package/lib/rules/max-expects.js +0 -16
- package/lib/rules/max-nested-describe.js +0 -13
- package/lib/rules/no-alias-methods.js +0 -9
- package/lib/rules/no-commented-out-tests.js +0 -10
- package/lib/rules/no-conditional-expect.js +1 -20
- package/lib/rules/no-conditional-in-test.js +0 -9
- package/lib/rules/no-deprecated-functions.js +2 -18
- package/lib/rules/no-disabled-tests.js +2 -18
- package/lib/rules/no-done-callback.js +2 -31
- package/lib/rules/no-duplicate-hooks.js +0 -12
- package/lib/rules/no-export.js +0 -12
- package/lib/rules/no-focused-tests.js +0 -15
- package/lib/rules/no-hooks.js +0 -7
- package/lib/rules/no-identical-title.js +0 -19
- package/lib/rules/no-if.js +0 -24
- package/lib/rules/no-interpolation-in-snapshots.js +0 -9
- package/lib/rules/no-jasmine-globals.js +0 -22
- package/lib/rules/no-large-snapshots.js +3 -21
- package/lib/rules/no-mocks-import.js +0 -12
- package/lib/rules/no-restricted-jest-methods.js +1 -11
- package/lib/rules/no-restricted-matchers.js +0 -11
- package/lib/rules/no-standalone-expect.js +7 -33
- package/lib/rules/no-test-prefixes.js +1 -13
- package/lib/rules/no-test-return-statement.js +0 -12
- package/lib/rules/prefer-called-with.js +0 -10
- package/lib/rules/prefer-comparison-matcher.js +8 -33
- package/lib/rules/prefer-each.js +0 -18
- package/lib/rules/prefer-equality-matcher.js +11 -23
- package/lib/rules/prefer-expect-assertions.js +4 -51
- package/lib/rules/prefer-expect-resolves.js +0 -12
- package/lib/rules/prefer-hooks-in-order.js +2 -16
- package/lib/rules/prefer-hooks-on-top.js +0 -9
- package/lib/rules/prefer-lowercase-title.js +0 -23
- package/lib/rules/prefer-mock-promise-shorthand.js +5 -26
- package/lib/rules/prefer-snapshot-hint.js +7 -31
- package/lib/rules/prefer-spy-on.js +0 -17
- package/lib/rules/prefer-strict-equal.js +0 -9
- package/lib/rules/prefer-to-be.js +1 -30
- package/lib/rules/prefer-to-contain.js +11 -21
- package/lib/rules/prefer-to-have-length.js +4 -16
- package/lib/rules/prefer-todo.js +2 -18
- package/lib/rules/require-hook.js +0 -22
- package/lib/rules/require-to-throw-message.js +0 -9
- package/lib/rules/require-top-level-describe.js +0 -15
- package/lib/rules/unbound-method.js +2 -21
- package/lib/rules/utils/accessors.js +6 -18
- package/lib/rules/utils/detectJestVersion.js +2 -7
- package/lib/rules/utils/followTypeAssertionChain.js +0 -4
- package/lib/rules/utils/index.js +0 -10
- package/lib/rules/utils/misc.js +2 -46
- package/lib/rules/utils/parseJestFnCall.js +62 -118
- package/lib/rules/valid-describe-callback.js +0 -17
- package/lib/rules/valid-expect-in-promise.js +27 -94
- package/lib/rules/valid-expect.js +5 -48
- package/lib/rules/valid-title.js +0 -33
- package/package.json +3 -2
|
@@ -4,11 +4,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _utils = require("@typescript-eslint/utils");
|
|
9
|
-
|
|
10
8
|
var _utils2 = require("./utils");
|
|
11
|
-
|
|
12
9
|
const paramsLocation = params => {
|
|
13
10
|
const [first] = params;
|
|
14
11
|
const last = params[params.length - 1];
|
|
@@ -17,7 +14,6 @@ const paramsLocation = params => {
|
|
|
17
14
|
end: last.loc.end
|
|
18
15
|
};
|
|
19
16
|
};
|
|
20
|
-
|
|
21
17
|
var _default = (0, _utils2.createRule)({
|
|
22
18
|
name: __filename,
|
|
23
19
|
meta: {
|
|
@@ -37,25 +33,20 @@ var _default = (0, _utils2.createRule)({
|
|
|
37
33
|
schema: []
|
|
38
34
|
},
|
|
39
35
|
defaultOptions: [],
|
|
40
|
-
|
|
41
36
|
create(context) {
|
|
42
37
|
return {
|
|
43
38
|
CallExpression(node) {
|
|
44
39
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
45
|
-
|
|
46
40
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe') {
|
|
47
41
|
return;
|
|
48
42
|
}
|
|
49
|
-
|
|
50
43
|
if (node.arguments.length < 1) {
|
|
51
44
|
return context.report({
|
|
52
45
|
messageId: 'nameAndCallback',
|
|
53
46
|
loc: node.loc
|
|
54
47
|
});
|
|
55
48
|
}
|
|
56
|
-
|
|
57
49
|
const [, callback] = node.arguments;
|
|
58
|
-
|
|
59
50
|
if (!callback) {
|
|
60
51
|
context.report({
|
|
61
52
|
messageId: 'nameAndCallback',
|
|
@@ -63,7 +54,6 @@ var _default = (0, _utils2.createRule)({
|
|
|
63
54
|
});
|
|
64
55
|
return;
|
|
65
56
|
}
|
|
66
|
-
|
|
67
57
|
if (!(0, _utils2.isFunction)(callback)) {
|
|
68
58
|
context.report({
|
|
69
59
|
messageId: 'secondArgumentMustBeFunction',
|
|
@@ -71,28 +61,24 @@ var _default = (0, _utils2.createRule)({
|
|
|
71
61
|
});
|
|
72
62
|
return;
|
|
73
63
|
}
|
|
74
|
-
|
|
75
64
|
if (callback.async) {
|
|
76
65
|
context.report({
|
|
77
66
|
messageId: 'noAsyncDescribeCallback',
|
|
78
67
|
node: callback
|
|
79
68
|
});
|
|
80
69
|
}
|
|
81
|
-
|
|
82
70
|
if (jestFnCall.members.every(s => (0, _utils2.getAccessorValue)(s) !== 'each') && callback.params.length) {
|
|
83
71
|
context.report({
|
|
84
72
|
messageId: 'unexpectedDescribeArgument',
|
|
85
73
|
loc: paramsLocation(callback.params)
|
|
86
74
|
});
|
|
87
75
|
}
|
|
88
|
-
|
|
89
76
|
if (callback.body.type === _utils.AST_NODE_TYPES.CallExpression) {
|
|
90
77
|
context.report({
|
|
91
78
|
messageId: 'unexpectedReturnInDescribe',
|
|
92
79
|
node: callback
|
|
93
80
|
});
|
|
94
81
|
}
|
|
95
|
-
|
|
96
82
|
if (callback.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
|
|
97
83
|
callback.body.body.forEach(node => {
|
|
98
84
|
if (node.type === _utils.AST_NODE_TYPES.ReturnStatement) {
|
|
@@ -104,10 +90,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
104
90
|
});
|
|
105
91
|
}
|
|
106
92
|
}
|
|
107
|
-
|
|
108
93
|
};
|
|
109
94
|
}
|
|
110
|
-
|
|
111
95
|
});
|
|
112
|
-
|
|
113
96
|
exports.default = _default;
|
|
@@ -4,40 +4,30 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _utils = require("@typescript-eslint/utils");
|
|
9
|
-
|
|
10
8
|
var _utils2 = require("./utils");
|
|
11
|
-
|
|
12
9
|
const isPromiseChainCall = node => {
|
|
13
10
|
if (node.type === _utils.AST_NODE_TYPES.CallExpression && node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.property)) {
|
|
14
11
|
// promise methods should have at least 1 argument
|
|
15
12
|
if (node.arguments.length === 0) {
|
|
16
13
|
return false;
|
|
17
14
|
}
|
|
18
|
-
|
|
19
15
|
switch ((0, _utils2.getAccessorValue)(node.callee.property)) {
|
|
20
16
|
case 'then':
|
|
21
17
|
return node.arguments.length < 3;
|
|
22
|
-
|
|
23
18
|
case 'catch':
|
|
24
19
|
case 'finally':
|
|
25
20
|
return node.arguments.length < 2;
|
|
26
21
|
}
|
|
27
22
|
}
|
|
28
|
-
|
|
29
23
|
return false;
|
|
30
24
|
};
|
|
31
|
-
|
|
32
25
|
const isTestCaseCallWithCallbackArg = (node, context) => {
|
|
33
26
|
const jestCallFn = (0, _utils2.parseJestFnCall)(node, context);
|
|
34
|
-
|
|
35
27
|
if ((jestCallFn === null || jestCallFn === void 0 ? void 0 : jestCallFn.type) !== 'test') {
|
|
36
28
|
return false;
|
|
37
29
|
}
|
|
38
|
-
|
|
39
30
|
const isJestEach = jestCallFn.members.some(s => (0, _utils2.getAccessorValue)(s) === 'each');
|
|
40
|
-
|
|
41
31
|
if (isJestEach && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression) {
|
|
42
32
|
// isJestEach but not a TaggedTemplateExpression, so this must be
|
|
43
33
|
// the `jest.each([])()` syntax which this rule doesn't support due
|
|
@@ -45,137 +35,109 @@ const isTestCaseCallWithCallbackArg = (node, context) => {
|
|
|
45
35
|
// so we return true to trigger bailout
|
|
46
36
|
return true;
|
|
47
37
|
}
|
|
48
|
-
|
|
49
38
|
const [, callback] = node.arguments;
|
|
50
39
|
const callbackArgIndex = Number(isJestEach);
|
|
51
40
|
return callback && (0, _utils2.isFunction)(callback) && callback.params.length === 1 + callbackArgIndex;
|
|
52
41
|
};
|
|
53
|
-
|
|
54
42
|
const isPromiseMethodThatUsesValue = (node, identifier) => {
|
|
55
43
|
const {
|
|
56
44
|
name
|
|
57
45
|
} = identifier;
|
|
58
|
-
|
|
59
46
|
if (node.argument === null) {
|
|
60
47
|
return false;
|
|
61
48
|
}
|
|
62
|
-
|
|
63
49
|
if (node.argument.type === _utils.AST_NODE_TYPES.CallExpression && node.argument.arguments.length > 0) {
|
|
64
50
|
const nodeName = (0, _utils2.getNodeName)(node.argument);
|
|
65
|
-
|
|
66
51
|
if (['Promise.all', 'Promise.allSettled'].includes(nodeName)) {
|
|
67
52
|
const [firstArg] = node.argument.arguments;
|
|
68
|
-
|
|
69
53
|
if (firstArg.type === _utils.AST_NODE_TYPES.ArrayExpression && firstArg.elements.some(nod => (0, _utils2.isIdentifier)(nod, name))) {
|
|
70
54
|
return true;
|
|
71
55
|
}
|
|
72
56
|
}
|
|
73
|
-
|
|
74
57
|
if (['Promise.resolve', 'Promise.reject'].includes(nodeName) && node.argument.arguments.length === 1) {
|
|
75
58
|
return (0, _utils2.isIdentifier)(node.argument.arguments[0], name);
|
|
76
59
|
}
|
|
77
60
|
}
|
|
78
|
-
|
|
79
61
|
return (0, _utils2.isIdentifier)(node.argument, name);
|
|
80
62
|
};
|
|
63
|
+
|
|
81
64
|
/**
|
|
82
65
|
* Attempts to determine if the runtime value represented by the given `identifier`
|
|
83
66
|
* is `await`ed within the given array of elements
|
|
84
67
|
*/
|
|
85
|
-
|
|
86
|
-
|
|
87
68
|
const isValueAwaitedInElements = (name, elements) => {
|
|
88
69
|
for (const element of elements) {
|
|
89
70
|
if (element.type === _utils.AST_NODE_TYPES.AwaitExpression && (0, _utils2.isIdentifier)(element.argument, name)) {
|
|
90
71
|
return true;
|
|
91
72
|
}
|
|
92
|
-
|
|
93
73
|
if (element.type === _utils.AST_NODE_TYPES.ArrayExpression && isValueAwaitedInElements(name, element.elements)) {
|
|
94
74
|
return true;
|
|
95
75
|
}
|
|
96
76
|
}
|
|
97
|
-
|
|
98
77
|
return false;
|
|
99
78
|
};
|
|
79
|
+
|
|
100
80
|
/**
|
|
101
81
|
* Attempts to determine if the runtime value represented by the given `identifier`
|
|
102
82
|
* is `await`ed as an argument along the given call expression
|
|
103
83
|
*/
|
|
104
|
-
|
|
105
|
-
|
|
106
84
|
const isValueAwaitedInArguments = (name, call) => {
|
|
107
85
|
let node = call;
|
|
108
|
-
|
|
109
86
|
while (node) {
|
|
110
87
|
if (node.type === _utils.AST_NODE_TYPES.CallExpression) {
|
|
111
88
|
if (isValueAwaitedInElements(name, node.arguments)) {
|
|
112
89
|
return true;
|
|
113
90
|
}
|
|
114
|
-
|
|
115
91
|
node = node.callee;
|
|
116
92
|
}
|
|
117
|
-
|
|
118
93
|
if (node.type !== _utils.AST_NODE_TYPES.MemberExpression) {
|
|
119
94
|
break;
|
|
120
95
|
}
|
|
121
|
-
|
|
122
96
|
node = node.object;
|
|
123
97
|
}
|
|
124
|
-
|
|
125
98
|
return false;
|
|
126
99
|
};
|
|
127
|
-
|
|
128
100
|
const getLeftMostCallExpression = call => {
|
|
129
101
|
let leftMostCallExpression = call;
|
|
130
102
|
let node = call;
|
|
131
|
-
|
|
132
103
|
while (node) {
|
|
133
104
|
if (node.type === _utils.AST_NODE_TYPES.CallExpression) {
|
|
134
105
|
leftMostCallExpression = node;
|
|
135
106
|
node = node.callee;
|
|
136
107
|
}
|
|
137
|
-
|
|
138
108
|
if (node.type !== _utils.AST_NODE_TYPES.MemberExpression) {
|
|
139
109
|
break;
|
|
140
110
|
}
|
|
141
|
-
|
|
142
111
|
node = node.object;
|
|
143
112
|
}
|
|
144
|
-
|
|
145
113
|
return leftMostCallExpression;
|
|
146
114
|
};
|
|
115
|
+
|
|
147
116
|
/**
|
|
148
117
|
* Attempts to determine if the runtime value represented by the given `identifier`
|
|
149
118
|
* is `await`ed or `return`ed within the given `body` of statements
|
|
150
119
|
*/
|
|
151
|
-
|
|
152
|
-
|
|
153
120
|
const isValueAwaitedOrReturned = (identifier, body, context) => {
|
|
154
121
|
const {
|
|
155
122
|
name
|
|
156
123
|
} = identifier;
|
|
157
|
-
|
|
158
124
|
for (const node of body) {
|
|
159
125
|
// skip all nodes that are before this identifier, because they'd probably
|
|
160
126
|
// be affecting a different runtime value (e.g. due to reassignment)
|
|
161
127
|
if (node.range[0] <= identifier.range[0]) {
|
|
162
128
|
continue;
|
|
163
129
|
}
|
|
164
|
-
|
|
165
130
|
if (node.type === _utils.AST_NODE_TYPES.ReturnStatement) {
|
|
166
131
|
return isPromiseMethodThatUsesValue(node, identifier);
|
|
167
132
|
}
|
|
168
|
-
|
|
169
133
|
if (node.type === _utils.AST_NODE_TYPES.ExpressionStatement) {
|
|
170
134
|
// it's possible that we're awaiting the value as an argument
|
|
171
135
|
if (node.expression.type === _utils.AST_NODE_TYPES.CallExpression) {
|
|
172
136
|
if (isValueAwaitedInArguments(name, node.expression)) {
|
|
173
137
|
return true;
|
|
174
138
|
}
|
|
175
|
-
|
|
176
139
|
const leftMostCall = getLeftMostCallExpression(node.expression);
|
|
177
140
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node.expression, context);
|
|
178
|
-
|
|
179
141
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'expect' && leftMostCall.arguments.length > 0 && (0, _utils2.isIdentifier)(leftMostCall.arguments[0], name)) {
|
|
180
142
|
if (jestFnCall.members.some(m => {
|
|
181
143
|
const v = (0, _utils2.getAccessorValue)(m);
|
|
@@ -185,84 +147,68 @@ const isValueAwaitedOrReturned = (identifier, body, context) => {
|
|
|
185
147
|
}
|
|
186
148
|
}
|
|
187
149
|
}
|
|
188
|
-
|
|
189
150
|
if (node.expression.type === _utils.AST_NODE_TYPES.AwaitExpression && isPromiseMethodThatUsesValue(node.expression, identifier)) {
|
|
190
151
|
return true;
|
|
191
|
-
}
|
|
192
|
-
// await or return already we act as if we've reached the end of the body
|
|
193
|
-
|
|
152
|
+
}
|
|
194
153
|
|
|
154
|
+
// (re)assignment changes the runtime value, so if we've not found an
|
|
155
|
+
// await or return already we act as if we've reached the end of the body
|
|
195
156
|
if (node.expression.type === _utils.AST_NODE_TYPES.AssignmentExpression) {
|
|
196
157
|
var _getNodeName;
|
|
197
|
-
|
|
198
158
|
// unless we're assigning to the same identifier, in which case
|
|
199
159
|
// we might be chaining off the existing promise value
|
|
200
160
|
if ((0, _utils2.isIdentifier)(node.expression.left, name) && (_getNodeName = (0, _utils2.getNodeName)(node.expression.right)) !== null && _getNodeName !== void 0 && _getNodeName.startsWith(`${name}.`) && isPromiseChainCall(node.expression.right)) {
|
|
201
161
|
continue;
|
|
202
162
|
}
|
|
203
|
-
|
|
204
163
|
break;
|
|
205
164
|
}
|
|
206
165
|
}
|
|
207
|
-
|
|
208
166
|
if (node.type === _utils.AST_NODE_TYPES.BlockStatement && isValueAwaitedOrReturned(identifier, node.body, context)) {
|
|
209
167
|
return true;
|
|
210
168
|
}
|
|
211
169
|
}
|
|
212
|
-
|
|
213
170
|
return false;
|
|
214
171
|
};
|
|
215
|
-
|
|
216
172
|
const findFirstBlockBodyUp = node => {
|
|
217
173
|
let parent = node;
|
|
218
|
-
|
|
219
174
|
while (parent) {
|
|
220
175
|
if (parent.type === _utils.AST_NODE_TYPES.BlockStatement) {
|
|
221
176
|
return parent.body;
|
|
222
177
|
}
|
|
223
|
-
|
|
224
178
|
parent = parent.parent;
|
|
225
179
|
}
|
|
226
|
-
/* istanbul ignore next */
|
|
227
|
-
|
|
228
180
|
|
|
181
|
+
/* istanbul ignore next */
|
|
229
182
|
throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
|
|
230
183
|
};
|
|
231
|
-
|
|
232
184
|
const isDirectlyWithinTestCaseCall = (node, context) => {
|
|
233
185
|
let parent = node;
|
|
234
|
-
|
|
235
186
|
while (parent) {
|
|
236
187
|
if ((0, _utils2.isFunction)(parent)) {
|
|
237
188
|
var _parent;
|
|
238
|
-
|
|
239
189
|
parent = parent.parent;
|
|
240
190
|
return ((_parent = parent) === null || _parent === void 0 ? void 0 : _parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTypeOfJestFnCall)(parent, context, ['test']);
|
|
241
191
|
}
|
|
242
|
-
|
|
243
192
|
parent = parent.parent;
|
|
244
193
|
}
|
|
245
|
-
|
|
246
194
|
return false;
|
|
247
195
|
};
|
|
248
|
-
|
|
249
196
|
const isVariableAwaitedOrReturned = (variable, context) => {
|
|
250
|
-
const body = findFirstBlockBodyUp(variable);
|
|
251
|
-
// so we return true to bailout gracefully
|
|
197
|
+
const body = findFirstBlockBodyUp(variable);
|
|
252
198
|
|
|
199
|
+
// it's pretty much impossible for us to track destructuring assignments,
|
|
200
|
+
// so we return true to bailout gracefully
|
|
253
201
|
if (!(0, _utils2.isIdentifier)(variable.id)) {
|
|
254
202
|
return true;
|
|
255
203
|
}
|
|
256
|
-
|
|
257
204
|
return isValueAwaitedOrReturned(variable.id, body, context);
|
|
258
205
|
};
|
|
259
|
-
|
|
260
206
|
var _default = (0, _utils2.createRule)({
|
|
261
207
|
name: __filename,
|
|
262
208
|
meta: {
|
|
263
209
|
docs: {
|
|
264
210
|
category: 'Best Practices',
|
|
265
|
-
description: '
|
|
211
|
+
description: 'Require promises that have expectations in their chain to be valid',
|
|
266
212
|
recommended: 'error'
|
|
267
213
|
},
|
|
268
214
|
messages: {
|
|
@@ -272,16 +218,15 @@ var _default = (0, _utils2.createRule)({
|
|
|
272
218
|
schema: []
|
|
273
219
|
},
|
|
274
220
|
defaultOptions: [],
|
|
275
|
-
|
|
276
221
|
create(context) {
|
|
277
|
-
let inTestCaseWithDoneCallback = false;
|
|
222
|
+
let inTestCaseWithDoneCallback = false;
|
|
223
|
+
// an array of booleans representing each promise chain we enter, with the
|
|
278
224
|
// boolean value representing if we think a given chain contains an expect
|
|
279
225
|
// in it's body.
|
|
280
226
|
//
|
|
281
227
|
// since we only care about the inner-most chain, we represent the state in
|
|
282
228
|
// reverse with the inner-most being the first item, as that makes it
|
|
283
229
|
// slightly less code to assign to by not needing to know the length
|
|
284
|
-
|
|
285
230
|
const chains = [];
|
|
286
231
|
return {
|
|
287
232
|
CallExpression(node) {
|
|
@@ -290,22 +235,21 @@ var _default = (0, _utils2.createRule)({
|
|
|
290
235
|
if (isTestCaseCallWithCallbackArg(node, context)) {
|
|
291
236
|
inTestCaseWithDoneCallback = true;
|
|
292
237
|
return;
|
|
293
|
-
}
|
|
294
|
-
// value of "false", as we assume there are no expect calls initially
|
|
295
|
-
|
|
238
|
+
}
|
|
296
239
|
|
|
240
|
+
// if this call expression is a promise chain, add it to the stack with
|
|
241
|
+
// value of "false", as we assume there are no expect calls initially
|
|
297
242
|
if (isPromiseChainCall(node)) {
|
|
298
243
|
chains.unshift(false);
|
|
299
244
|
return;
|
|
300
|
-
}
|
|
301
|
-
// an expect call, mark the deepest chain as having an expect call
|
|
302
|
-
|
|
245
|
+
}
|
|
303
246
|
|
|
247
|
+
// if we're within a promise chain, and this call expression looks like
|
|
248
|
+
// an expect call, mark the deepest chain as having an expect call
|
|
304
249
|
if (chains.length > 0 && (0, _utils2.isTypeOfJestFnCall)(node, context, ['expect'])) {
|
|
305
250
|
chains[0] = true;
|
|
306
251
|
}
|
|
307
252
|
},
|
|
308
|
-
|
|
309
253
|
'CallExpression:exit'(node) {
|
|
310
254
|
// there are too many ways that the "done" argument could be used to
|
|
311
255
|
// make promises containing expects safe in a test for us to be able to
|
|
@@ -314,71 +258,60 @@ var _default = (0, _utils2.createRule)({
|
|
|
314
258
|
if ((0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
|
|
315
259
|
inTestCaseWithDoneCallback = false;
|
|
316
260
|
}
|
|
317
|
-
|
|
318
261
|
return;
|
|
319
262
|
}
|
|
320
|
-
|
|
321
263
|
if (!isPromiseChainCall(node)) {
|
|
322
264
|
return;
|
|
323
|
-
}
|
|
324
|
-
// we remove it from the stack of chains, since we're unwinding
|
|
265
|
+
}
|
|
325
266
|
|
|
267
|
+
// since we're exiting this call expression (which is a promise chain)
|
|
268
|
+
// we remove it from the stack of chains, since we're unwinding
|
|
269
|
+
const hasExpectCall = chains.shift();
|
|
326
270
|
|
|
327
|
-
|
|
271
|
+
// if the promise chain we're exiting doesn't contain an expect,
|
|
328
272
|
// then we don't need to check it for anything
|
|
329
|
-
|
|
330
273
|
if (!hasExpectCall) {
|
|
331
274
|
return;
|
|
332
275
|
}
|
|
333
|
-
|
|
334
276
|
const {
|
|
335
277
|
parent
|
|
336
|
-
} = (0, _utils2.findTopMostCallExpression)(node);
|
|
278
|
+
} = (0, _utils2.findTopMostCallExpression)(node);
|
|
279
|
+
|
|
280
|
+
// if we don't have a parent (which is technically impossible at runtime)
|
|
337
281
|
// or our parent is not directly within the test case, we stop checking
|
|
338
282
|
// because we're most likely in the body of a function being defined
|
|
339
283
|
// within the test, which we can't track
|
|
340
|
-
|
|
341
284
|
if (!parent || !isDirectlyWithinTestCaseCall(parent, context)) {
|
|
342
285
|
return;
|
|
343
286
|
}
|
|
344
|
-
|
|
345
287
|
switch (parent.type) {
|
|
346
288
|
case _utils.AST_NODE_TYPES.VariableDeclarator:
|
|
347
289
|
{
|
|
348
290
|
if (isVariableAwaitedOrReturned(parent, context)) {
|
|
349
291
|
return;
|
|
350
292
|
}
|
|
351
|
-
|
|
352
293
|
break;
|
|
353
294
|
}
|
|
354
|
-
|
|
355
295
|
case _utils.AST_NODE_TYPES.AssignmentExpression:
|
|
356
296
|
{
|
|
357
297
|
if (parent.left.type === _utils.AST_NODE_TYPES.Identifier && isValueAwaitedOrReturned(parent.left, findFirstBlockBodyUp(parent), context)) {
|
|
358
298
|
return;
|
|
359
299
|
}
|
|
360
|
-
|
|
361
300
|
break;
|
|
362
301
|
}
|
|
363
|
-
|
|
364
302
|
case _utils.AST_NODE_TYPES.ExpressionStatement:
|
|
365
303
|
break;
|
|
366
|
-
|
|
367
304
|
case _utils.AST_NODE_TYPES.ReturnStatement:
|
|
368
305
|
case _utils.AST_NODE_TYPES.AwaitExpression:
|
|
369
306
|
default:
|
|
370
307
|
return;
|
|
371
308
|
}
|
|
372
|
-
|
|
373
309
|
context.report({
|
|
374
310
|
messageId: 'expectInFloatingPromise',
|
|
375
311
|
node: parent
|
|
376
312
|
});
|
|
377
313
|
}
|
|
378
|
-
|
|
379
314
|
};
|
|
380
315
|
}
|
|
381
|
-
|
|
382
316
|
});
|
|
383
|
-
|
|
384
317
|
exports.default = _default;
|