eslint-plugin-jest 26.7.0 → 26.8.7
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 +9 -1
- package/lib/rules/max-expects.js +10 -4
- package/lib/rules/no-alias-methods.js +7 -10
- package/lib/rules/no-conditional-expect.js +9 -3
- package/lib/rules/no-interpolation-in-snapshots.js +4 -12
- package/lib/rules/no-large-snapshots.js +5 -13
- package/lib/rules/no-restricted-matchers.js +26 -48
- package/lib/rules/no-standalone-expect.js +11 -5
- package/lib/rules/prefer-called-with.js +12 -10
- package/lib/rules/prefer-comparison-matcher.js +26 -33
- package/lib/rules/prefer-equality-matcher.js +28 -35
- package/lib/rules/prefer-expect-assertions.js +88 -71
- package/lib/rules/prefer-expect-resolves.js +18 -4
- package/lib/rules/prefer-mock-promise-shorthand.js +1 -1
- package/lib/rules/prefer-snapshot-hint.js +18 -21
- package/lib/rules/prefer-strict-equal.js +7 -5
- package/lib/rules/prefer-to-be.js +28 -37
- package/lib/rules/prefer-to-contain.js +25 -30
- package/lib/rules/prefer-to-have-length.js +16 -8
- package/lib/rules/require-to-throw-message.js +8 -8
- package/lib/rules/unbound-method.js +16 -33
- package/lib/rules/utils/index.js +0 -13
- package/lib/rules/utils/misc.js +64 -3
- package/lib/rules/utils/parseJestFnCall.js +132 -21
- package/lib/rules/valid-expect-in-promise.js +14 -37
- package/lib/rules/valid-expect.js +72 -60
- package/package.json +25 -29
- package/lib/rules/utils/parseExpectCall.js +0 -145
|
@@ -9,17 +9,33 @@ var _utils = require("@typescript-eslint/utils");
|
|
|
9
9
|
|
|
10
10
|
var _utils2 = require("./utils");
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const isFirstStatement = node => {
|
|
13
|
+
let parent = node;
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
while (parent) {
|
|
16
|
+
var _parent$parent;
|
|
17
|
+
|
|
18
|
+
if (((_parent$parent = parent.parent) === null || _parent$parent === void 0 ? void 0 : _parent$parent.type) === _utils.AST_NODE_TYPES.BlockStatement) {
|
|
19
|
+
return parent.parent.body[0] === parent;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
parent = parent.parent;
|
|
23
|
+
}
|
|
24
|
+
/* istanbul ignore next */
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
|
|
28
|
+
};
|
|
15
29
|
|
|
16
30
|
const suggestRemovingExtraArguments = (args, extraArgsStartAt) => ({
|
|
17
31
|
messageId: 'suggestRemovingExtraArguments',
|
|
18
32
|
fix: fixer => fixer.removeRange([args[extraArgsStartAt].range[0] - Math.sign(extraArgsStartAt), args[args.length - 1].range[1]])
|
|
19
33
|
});
|
|
20
34
|
|
|
21
|
-
const suggestions
|
|
22
|
-
|
|
35
|
+
// const suggestions: Array<[MessageIds, string]> = [
|
|
36
|
+
// ['suggestAddingHasAssertions', 'expect.hasAssertions();'],
|
|
37
|
+
// ['suggestAddingAssertions', 'expect.assertions();'],
|
|
38
|
+
// ];
|
|
23
39
|
var _default = (0, _utils2.createRule)({
|
|
24
40
|
name: __filename,
|
|
25
41
|
meta: {
|
|
@@ -66,6 +82,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
66
82
|
let expressionDepth = 0;
|
|
67
83
|
let hasExpectInCallback = false;
|
|
68
84
|
let hasExpectInLoop = false;
|
|
85
|
+
let hasExpectAssertionsAsFirstStatement = false;
|
|
69
86
|
let inTestCaseCall = false;
|
|
70
87
|
let inForLoop = false;
|
|
71
88
|
|
|
@@ -95,6 +112,50 @@ var _default = (0, _utils2.createRule)({
|
|
|
95
112
|
return false;
|
|
96
113
|
};
|
|
97
114
|
|
|
115
|
+
const checkExpectHasAssertions = expectFnCall => {
|
|
116
|
+
if ((0, _utils2.getAccessorValue)(expectFnCall.members[0]) === 'hasAssertions') {
|
|
117
|
+
if (expectFnCall.args.length) {
|
|
118
|
+
context.report({
|
|
119
|
+
messageId: 'hasAssertionsTakesNoArguments',
|
|
120
|
+
node: expectFnCall.matcher,
|
|
121
|
+
suggest: [suggestRemovingExtraArguments(expectFnCall.args, 0)]
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (expectFnCall.args.length !== 1) {
|
|
129
|
+
let {
|
|
130
|
+
loc
|
|
131
|
+
} = expectFnCall.matcher;
|
|
132
|
+
const suggest = [];
|
|
133
|
+
|
|
134
|
+
if (expectFnCall.args.length) {
|
|
135
|
+
loc = expectFnCall.args[1].loc;
|
|
136
|
+
suggest.push(suggestRemovingExtraArguments(expectFnCall.args, 1));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
context.report({
|
|
140
|
+
messageId: 'assertionsRequiresOneArgument',
|
|
141
|
+
suggest,
|
|
142
|
+
loc
|
|
143
|
+
});
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const [arg] = expectFnCall.args;
|
|
148
|
+
|
|
149
|
+
if (arg.type === _utils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value)) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
context.report({
|
|
154
|
+
messageId: 'assertionsRequiresNumberArgument',
|
|
155
|
+
node: arg
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
|
|
98
159
|
const enterExpression = () => inTestCaseCall && expressionDepth++;
|
|
99
160
|
|
|
100
161
|
const exitExpression = () => inTestCaseCall && expressionDepth--;
|
|
@@ -116,12 +177,21 @@ var _default = (0, _utils2.createRule)({
|
|
|
116
177
|
'ForOfStatement:exit': exitForLoop,
|
|
117
178
|
|
|
118
179
|
CallExpression(node) {
|
|
119
|
-
|
|
180
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
181
|
+
|
|
182
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test') {
|
|
120
183
|
inTestCaseCall = true;
|
|
121
184
|
return;
|
|
122
185
|
}
|
|
123
186
|
|
|
124
|
-
if ((0
|
|
187
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'expect' && inTestCaseCall) {
|
|
188
|
+
var _jestFnCall$head$node;
|
|
189
|
+
|
|
190
|
+
if (expressionDepth === 1 && isFirstStatement(node) && ((_jestFnCall$head$node = jestFnCall.head.node.parent) === null || _jestFnCall$head$node === void 0 ? void 0 : _jestFnCall$head$node.type) === _utils.AST_NODE_TYPES.MemberExpression && jestFnCall.members.length === 1 && ['assertions', 'hasAssertions'].includes((0, _utils2.getAccessorValue)(jestFnCall.members[0]))) {
|
|
191
|
+
checkExpectHasAssertions(jestFnCall);
|
|
192
|
+
hasExpectAssertionsAsFirstStatement = true;
|
|
193
|
+
}
|
|
194
|
+
|
|
125
195
|
if (inForLoop) {
|
|
126
196
|
hasExpectInLoop = true;
|
|
127
197
|
}
|
|
@@ -145,84 +215,31 @@ var _default = (0, _utils2.createRule)({
|
|
|
145
215
|
|
|
146
216
|
const [, testFn] = node.arguments;
|
|
147
217
|
|
|
148
|
-
if (!(0, _utils2.isFunction)(testFn) || testFn
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (!shouldCheckFunction(testFn)) {
|
|
218
|
+
if (!(0, _utils2.isFunction)(testFn) || !shouldCheckFunction(testFn)) {
|
|
153
219
|
return;
|
|
154
220
|
}
|
|
155
221
|
|
|
156
222
|
hasExpectInLoop = false;
|
|
157
223
|
hasExpectInCallback = false;
|
|
158
|
-
const testFuncBody = testFn.body.body;
|
|
159
|
-
|
|
160
|
-
if (!isFirstLineExprStmt(testFuncBody)) {
|
|
161
|
-
context.report({
|
|
162
|
-
messageId: 'haveExpectAssertions',
|
|
163
|
-
node,
|
|
164
|
-
suggest: suggestions.map(([messageId, text]) => ({
|
|
165
|
-
messageId,
|
|
166
|
-
fix: fixer => fixer.insertTextBeforeRange([testFn.body.range[0] + 1, testFn.body.range[1]], text)
|
|
167
|
-
}))
|
|
168
|
-
});
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const testFuncFirstLine = testFuncBody[0].expression;
|
|
173
|
-
|
|
174
|
-
if (!isExpectAssertionsOrHasAssertionsCall(testFuncFirstLine)) {
|
|
175
|
-
context.report({
|
|
176
|
-
messageId: 'haveExpectAssertions',
|
|
177
|
-
node,
|
|
178
|
-
suggest: suggestions.map(([messageId, text]) => ({
|
|
179
|
-
messageId,
|
|
180
|
-
fix: fixer => fixer.insertTextBefore(testFuncBody[0], text)
|
|
181
|
-
}))
|
|
182
|
-
});
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if ((0, _utils2.isSupportedAccessor)(testFuncFirstLine.callee.property, 'hasAssertions')) {
|
|
187
|
-
if (testFuncFirstLine.arguments.length) {
|
|
188
|
-
context.report({
|
|
189
|
-
messageId: 'hasAssertionsTakesNoArguments',
|
|
190
|
-
node: testFuncFirstLine.callee.property,
|
|
191
|
-
suggest: [suggestRemovingExtraArguments(testFuncFirstLine.arguments, 0)]
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
224
|
|
|
225
|
+
if (hasExpectAssertionsAsFirstStatement) {
|
|
226
|
+
hasExpectAssertionsAsFirstStatement = false;
|
|
195
227
|
return;
|
|
196
228
|
}
|
|
197
229
|
|
|
198
|
-
|
|
199
|
-
let {
|
|
200
|
-
loc
|
|
201
|
-
} = testFuncFirstLine.callee.property;
|
|
202
|
-
const suggest = [];
|
|
230
|
+
const suggestions = [];
|
|
203
231
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
suggest.push(suggestRemovingExtraArguments(testFuncFirstLine.arguments, 1));
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
context.report({
|
|
210
|
-
messageId: 'assertionsRequiresOneArgument',
|
|
211
|
-
suggest,
|
|
212
|
-
loc
|
|
213
|
-
});
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const [arg] = testFuncFirstLine.arguments;
|
|
218
|
-
|
|
219
|
-
if (arg.type === _utils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value)) {
|
|
220
|
-
return;
|
|
232
|
+
if (testFn.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
|
|
233
|
+
suggestions.push(['suggestAddingHasAssertions', 'expect.hasAssertions();'], ['suggestAddingAssertions', 'expect.assertions();']);
|
|
221
234
|
}
|
|
222
235
|
|
|
223
236
|
context.report({
|
|
224
|
-
messageId: '
|
|
225
|
-
node
|
|
237
|
+
messageId: 'haveExpectAssertions',
|
|
238
|
+
node,
|
|
239
|
+
suggest: suggestions.map(([messageId, text]) => ({
|
|
240
|
+
messageId,
|
|
241
|
+
fix: fixer => fixer.insertTextBeforeRange([testFn.body.range[0] + 1, testFn.body.range[1]], text)
|
|
242
|
+
}))
|
|
226
243
|
});
|
|
227
244
|
}
|
|
228
245
|
|
|
@@ -27,15 +27,29 @@ var _default = (0, _utils2.createRule)({
|
|
|
27
27
|
defaultOptions: [],
|
|
28
28
|
create: context => ({
|
|
29
29
|
CallExpression(node) {
|
|
30
|
-
const
|
|
30
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
31
31
|
|
|
32
|
-
if ((
|
|
32
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const {
|
|
37
|
+
parent
|
|
38
|
+
} = jestFnCall.head.node;
|
|
39
|
+
|
|
40
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const [awaitNode] = parent.arguments;
|
|
45
|
+
|
|
46
|
+
if ((awaitNode === null || awaitNode === void 0 ? void 0 : awaitNode.type) === _utils.AST_NODE_TYPES.AwaitExpression) {
|
|
33
47
|
context.report({
|
|
34
|
-
node:
|
|
48
|
+
node: awaitNode,
|
|
35
49
|
messageId: 'expectResolves',
|
|
36
50
|
|
|
37
51
|
fix(fixer) {
|
|
38
|
-
return [fixer.insertTextBefore(
|
|
52
|
+
return [fixer.insertTextBefore(parent, 'await '), fixer.removeRange([awaitNode.range[0], awaitNode.argument.range[0]]), fixer.insertTextAfter(parent, '.resolves')];
|
|
39
53
|
}
|
|
40
54
|
|
|
41
55
|
});
|
|
@@ -95,7 +95,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
95
95
|
} else if (mockFnName === withOnce('mockImplementation', isOnce)) {
|
|
96
96
|
const [arg] = node.arguments;
|
|
97
97
|
|
|
98
|
-
if (!(0, _utils2.isFunction)(arg)) {
|
|
98
|
+
if (!(0, _utils2.isFunction)(arg) || arg.params.length !== 0) {
|
|
99
99
|
return;
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -8,28 +8,25 @@ exports.default = void 0;
|
|
|
8
8
|
var _utils = require("./utils");
|
|
9
9
|
|
|
10
10
|
const snapshotMatchers = ['toMatchSnapshot', 'toThrowErrorMatchingSnapshot'];
|
|
11
|
+
const snapshotMatcherNames = snapshotMatchers;
|
|
11
12
|
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const isSnapshotMatcherWithoutHint = matcher => {
|
|
17
|
-
if (!matcher.arguments || matcher.arguments.length === 0) {
|
|
13
|
+
const isSnapshotMatcherWithoutHint = expectFnCall => {
|
|
14
|
+
if (expectFnCall.args.length === 0) {
|
|
18
15
|
return true;
|
|
19
16
|
} // this matcher only supports one argument which is the hint
|
|
20
17
|
|
|
21
18
|
|
|
22
|
-
if (matcher
|
|
23
|
-
return
|
|
19
|
+
if (!(0, _utils.isSupportedAccessor)(expectFnCall.matcher, 'toMatchSnapshot')) {
|
|
20
|
+
return expectFnCall.args.length !== 1;
|
|
24
21
|
} // if we're being passed two arguments,
|
|
25
22
|
// the second one should be the hint
|
|
26
23
|
|
|
27
24
|
|
|
28
|
-
if (
|
|
25
|
+
if (expectFnCall.args.length === 2) {
|
|
29
26
|
return false;
|
|
30
27
|
}
|
|
31
28
|
|
|
32
|
-
const [arg] =
|
|
29
|
+
const [arg] = expectFnCall.args; // the first argument to `toMatchSnapshot` can be _either_ a snapshot hint or
|
|
33
30
|
// an object with asymmetric matchers, so we can't just assume that the first
|
|
34
31
|
// argument is a hint when it's by itself.
|
|
35
32
|
|
|
@@ -67,7 +64,7 @@ var _default = (0, _utils.createRule)({
|
|
|
67
64
|
if (isSnapshotMatcherWithoutHint(snapshotMatcher)) {
|
|
68
65
|
context.report({
|
|
69
66
|
messageId: 'missingHint',
|
|
70
|
-
node: snapshotMatcher.
|
|
67
|
+
node: snapshotMatcher.matcher
|
|
71
68
|
});
|
|
72
69
|
}
|
|
73
70
|
}
|
|
@@ -115,24 +112,24 @@ var _default = (0, _utils.createRule)({
|
|
|
115
112
|
},
|
|
116
113
|
|
|
117
114
|
CallExpression(node) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
115
|
+
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
116
|
+
|
|
117
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
|
|
118
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'describe' || (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test') {
|
|
119
|
+
depths.push(expressionDepth);
|
|
120
|
+
expressionDepth = 0;
|
|
121
|
+
}
|
|
122
122
|
|
|
123
|
-
if (!(0, _utils.isExpectCall)(node)) {
|
|
124
123
|
return;
|
|
125
124
|
}
|
|
126
125
|
|
|
127
|
-
const
|
|
128
|
-
matcher
|
|
129
|
-
} = (0, _utils.parseExpectCall)(node);
|
|
126
|
+
const matcherName = (0, _utils.getAccessorValue)(jestFnCall.matcher);
|
|
130
127
|
|
|
131
|
-
if (!
|
|
128
|
+
if (!snapshotMatcherNames.includes(matcherName)) {
|
|
132
129
|
return;
|
|
133
130
|
}
|
|
134
131
|
|
|
135
|
-
snapshotMatchers.push(
|
|
132
|
+
snapshotMatchers.push(jestFnCall);
|
|
136
133
|
}
|
|
137
134
|
|
|
138
135
|
};
|
|
@@ -29,21 +29,23 @@ var _default = (0, _utils.createRule)({
|
|
|
29
29
|
create(context) {
|
|
30
30
|
return {
|
|
31
31
|
CallExpression(node) {
|
|
32
|
-
|
|
32
|
+
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
33
|
+
|
|
34
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
const {
|
|
37
39
|
matcher
|
|
38
|
-
} =
|
|
40
|
+
} = jestFnCall;
|
|
39
41
|
|
|
40
|
-
if (
|
|
42
|
+
if ((0, _utils.isSupportedAccessor)(matcher, 'toEqual')) {
|
|
41
43
|
context.report({
|
|
42
44
|
messageId: 'useToStrictEqual',
|
|
43
|
-
node: matcher
|
|
45
|
+
node: matcher,
|
|
44
46
|
suggest: [{
|
|
45
47
|
messageId: 'suggestReplaceWithStrictEqual',
|
|
46
|
-
fix: fixer => [(0, _utils.replaceAccessorFixer)(fixer, matcher
|
|
48
|
+
fix: fixer => [(0, _utils.replaceAccessorFixer)(fixer, matcher, _utils.EqualityMatcher.toStrictEqual)]
|
|
47
49
|
}]
|
|
48
50
|
});
|
|
49
51
|
}
|
|
@@ -16,12 +16,12 @@ const isNullLiteral = node => node.type === _utils.AST_NODE_TYPES.Literal && nod
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
const isNullEqualityMatcher =
|
|
19
|
+
const isNullEqualityMatcher = expectFnCall => isNullLiteral((0, _utils2.getFirstMatcherArg)(expectFnCall));
|
|
20
20
|
|
|
21
|
-
const isFirstArgumentIdentifier = (
|
|
21
|
+
const isFirstArgumentIdentifier = (expectFnCall, name) => (0, _utils2.isIdentifier)((0, _utils2.getFirstMatcherArg)(expectFnCall), name);
|
|
22
22
|
|
|
23
|
-
const shouldUseToBe =
|
|
24
|
-
const firstArg =
|
|
23
|
+
const shouldUseToBe = expectFnCall => {
|
|
24
|
+
const firstArg = (0, _utils2.getFirstMatcherArg)(expectFnCall);
|
|
25
25
|
|
|
26
26
|
if (firstArg.type === _utils.AST_NODE_TYPES.Literal) {
|
|
27
27
|
// regex literals are classed as literals, but they're actually objects
|
|
@@ -32,32 +32,27 @@ const shouldUseToBe = matcher => {
|
|
|
32
32
|
return firstArg.type === _utils.AST_NODE_TYPES.TemplateLiteral;
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
const
|
|
36
|
-
return (0, _utils2.followTypeAssertionChain)(matcher.arguments[0]);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const reportPreferToBe = (context, whatToBe, matcher, modifier) => {
|
|
40
|
-
const modifierNode = (modifier === null || modifier === void 0 ? void 0 : modifier.negation) || (modifier === null || modifier === void 0 ? void 0 : modifier.name) === _utils2.ModifierName.not && (modifier === null || modifier === void 0 ? void 0 : modifier.node);
|
|
35
|
+
const reportPreferToBe = (context, whatToBe, expectFnCall, modifierNode) => {
|
|
41
36
|
context.report({
|
|
42
37
|
messageId: `useToBe${whatToBe}`,
|
|
43
38
|
|
|
44
39
|
fix(fixer) {
|
|
45
|
-
var
|
|
40
|
+
var _expectFnCall$args;
|
|
46
41
|
|
|
47
|
-
const fixes = [(0, _utils2.replaceAccessorFixer)(fixer, matcher
|
|
42
|
+
const fixes = [(0, _utils2.replaceAccessorFixer)(fixer, expectFnCall.matcher, `toBe${whatToBe}`)];
|
|
48
43
|
|
|
49
|
-
if ((
|
|
50
|
-
fixes.push(fixer.remove(
|
|
44
|
+
if ((_expectFnCall$args = expectFnCall.args) !== null && _expectFnCall$args !== void 0 && _expectFnCall$args.length && whatToBe !== '') {
|
|
45
|
+
fixes.push(fixer.remove(expectFnCall.args[0]));
|
|
51
46
|
}
|
|
52
47
|
|
|
53
48
|
if (modifierNode) {
|
|
54
|
-
fixes.push(fixer.removeRange([modifierNode.
|
|
49
|
+
fixes.push(fixer.removeRange([modifierNode.range[0] - 1, modifierNode.range[1]]));
|
|
55
50
|
}
|
|
56
51
|
|
|
57
52
|
return fixes;
|
|
58
53
|
},
|
|
59
54
|
|
|
60
|
-
node: matcher
|
|
55
|
+
node: expectFnCall.matcher
|
|
61
56
|
});
|
|
62
57
|
};
|
|
63
58
|
|
|
@@ -85,46 +80,42 @@ var _default = (0, _utils2.createRule)({
|
|
|
85
80
|
create(context) {
|
|
86
81
|
return {
|
|
87
82
|
CallExpression(node) {
|
|
88
|
-
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const {
|
|
93
|
-
matcher,
|
|
94
|
-
modifier
|
|
95
|
-
} = (0, _utils2.parseExpectCall)(node);
|
|
83
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
96
84
|
|
|
97
|
-
if (
|
|
85
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
|
|
98
86
|
return;
|
|
99
87
|
}
|
|
100
88
|
|
|
101
|
-
|
|
102
|
-
|
|
89
|
+
const matcherName = (0, _utils2.getAccessorValue)(jestFnCall.matcher);
|
|
90
|
+
const notModifier = jestFnCall.modifiers.find(nod => (0, _utils2.getAccessorValue)(nod) === 'not');
|
|
91
|
+
|
|
92
|
+
if (notModifier && ['toBeUndefined', 'toBeDefined'].includes(matcherName)) {
|
|
93
|
+
reportPreferToBe(context, matcherName === 'toBeDefined' ? 'Undefined' : 'Defined', jestFnCall, notModifier);
|
|
103
94
|
return;
|
|
104
95
|
}
|
|
105
96
|
|
|
106
|
-
if (!
|
|
97
|
+
if (!_utils2.EqualityMatcher.hasOwnProperty(matcherName) || jestFnCall.args.length === 0) {
|
|
107
98
|
return;
|
|
108
99
|
}
|
|
109
100
|
|
|
110
|
-
if (isNullEqualityMatcher(
|
|
111
|
-
reportPreferToBe(context, 'Null',
|
|
101
|
+
if (isNullEqualityMatcher(jestFnCall)) {
|
|
102
|
+
reportPreferToBe(context, 'Null', jestFnCall);
|
|
112
103
|
return;
|
|
113
104
|
}
|
|
114
105
|
|
|
115
|
-
if (isFirstArgumentIdentifier(
|
|
116
|
-
const name =
|
|
117
|
-
reportPreferToBe(context, name,
|
|
106
|
+
if (isFirstArgumentIdentifier(jestFnCall, 'undefined')) {
|
|
107
|
+
const name = notModifier ? 'Defined' : 'Undefined';
|
|
108
|
+
reportPreferToBe(context, name, jestFnCall, notModifier);
|
|
118
109
|
return;
|
|
119
110
|
}
|
|
120
111
|
|
|
121
|
-
if (isFirstArgumentIdentifier(
|
|
122
|
-
reportPreferToBe(context, 'NaN',
|
|
112
|
+
if (isFirstArgumentIdentifier(jestFnCall, 'NaN')) {
|
|
113
|
+
reportPreferToBe(context, 'NaN', jestFnCall);
|
|
123
114
|
return;
|
|
124
115
|
}
|
|
125
116
|
|
|
126
|
-
if (shouldUseToBe(
|
|
127
|
-
reportPreferToBe(context, '',
|
|
117
|
+
if (shouldUseToBe(jestFnCall) && matcherName !== _utils2.EqualityMatcher.toBe) {
|
|
118
|
+
reportPreferToBe(context, '', jestFnCall);
|
|
128
119
|
}
|
|
129
120
|
}
|
|
130
121
|
|
|
@@ -9,22 +9,6 @@ var _utils = require("@typescript-eslint/utils");
|
|
|
9
9
|
|
|
10
10
|
var _utils2 = require("./utils");
|
|
11
11
|
|
|
12
|
-
const isBooleanLiteral = node => node.type === _utils.AST_NODE_TYPES.Literal && typeof node.value === 'boolean';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Checks if the given `ParsedExpectMatcher` is a call to one of the equality matchers,
|
|
16
|
-
* with a boolean literal as the sole argument.
|
|
17
|
-
*
|
|
18
|
-
* @example javascript
|
|
19
|
-
* toBe(true);
|
|
20
|
-
* toEqual(false);
|
|
21
|
-
*
|
|
22
|
-
* @param {ParsedExpectMatcher} matcher
|
|
23
|
-
*
|
|
24
|
-
* @return {matcher is ParsedBooleanEqualityMatcher}
|
|
25
|
-
*/
|
|
26
|
-
const isBooleanEqualityMatcher = matcher => (0, _utils2.isParsedEqualityMatcherCall)(matcher) && isBooleanLiteral((0, _utils2.followTypeAssertionChain)(matcher.arguments[0]));
|
|
27
|
-
|
|
28
12
|
/**
|
|
29
13
|
* Checks if the given `node` is a `CallExpression` representing the calling
|
|
30
14
|
* of an `includes`-like method that can be 'fixed' (using `toContain`).
|
|
@@ -33,7 +17,7 @@ const isBooleanEqualityMatcher = matcher => (0, _utils2.isParsedEqualityMatcherC
|
|
|
33
17
|
*
|
|
34
18
|
* @return {node is FixableIncludesCallExpression}
|
|
35
19
|
*/
|
|
36
|
-
const isFixableIncludesCallExpression = node => node.type === _utils.AST_NODE_TYPES.CallExpression && node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.property, 'includes') && (0, _utils2.hasOnlyOneArgument)(node); // expect(array.includes(<value>)[not.]{toBe,toEqual}(<boolean>)
|
|
20
|
+
const isFixableIncludesCallExpression = node => node.type === _utils.AST_NODE_TYPES.CallExpression && node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.property, 'includes') && (0, _utils2.hasOnlyOneArgument)(node) && node.arguments[0].type !== _utils.AST_NODE_TYPES.SpreadElement; // expect(array.includes(<value>)[not.]{toBe,toEqual}(<boolean>)
|
|
37
21
|
|
|
38
22
|
|
|
39
23
|
var _default = (0, _utils2.createRule)({
|
|
@@ -56,37 +40,48 @@ var _default = (0, _utils2.createRule)({
|
|
|
56
40
|
create(context) {
|
|
57
41
|
return {
|
|
58
42
|
CallExpression(node) {
|
|
59
|
-
|
|
43
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
44
|
+
|
|
45
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect' || jestFnCall.args.length === 0) {
|
|
60
46
|
return;
|
|
61
47
|
}
|
|
62
48
|
|
|
63
49
|
const {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
50
|
+
parent: expect
|
|
51
|
+
} = jestFnCall.head.node;
|
|
52
|
+
|
|
53
|
+
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const {
|
|
58
|
+
arguments: [includesCall],
|
|
59
|
+
range: [, expectCallEnd]
|
|
60
|
+
} = expect;
|
|
61
|
+
const {
|
|
62
|
+
matcher
|
|
63
|
+
} = jestFnCall;
|
|
64
|
+
const matcherArg = (0, _utils2.getFirstMatcherArg)(jestFnCall);
|
|
71
65
|
|
|
72
|
-
if (!
|
|
66
|
+
if (!includesCall || matcherArg.type === _utils.AST_NODE_TYPES.SpreadElement || !_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || !(0, _utils2.isBooleanLiteral)(matcherArg) || !isFixableIncludesCallExpression(includesCall)) {
|
|
73
67
|
return;
|
|
74
68
|
}
|
|
75
69
|
|
|
70
|
+
const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not');
|
|
76
71
|
context.report({
|
|
77
72
|
fix(fixer) {
|
|
78
73
|
const sourceCode = context.getSourceCode(); // we need to negate the expectation if the current expected
|
|
79
74
|
// value is itself negated by the "not" modifier
|
|
80
75
|
|
|
81
|
-
const addNotModifier =
|
|
76
|
+
const addNotModifier = matcherArg.value === hasNot;
|
|
82
77
|
return [// remove the "includes" call entirely
|
|
83
78
|
fixer.removeRange([includesCall.callee.property.range[0] - 1, includesCall.range[1]]), // replace the current matcher with "toContain", adding "not" if needed
|
|
84
|
-
fixer.replaceTextRange([expectCallEnd, matcher.
|
|
85
|
-
fixer.replaceText(
|
|
79
|
+
fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], addNotModifier ? `.${_utils2.ModifierName.not}.toContain` : '.toContain'), // replace the matcher argument with the value from the "includes"
|
|
80
|
+
fixer.replaceText(jestFnCall.args[0], sourceCode.getText(includesCall.arguments[0]))];
|
|
86
81
|
},
|
|
87
82
|
|
|
88
83
|
messageId: 'useToContain',
|
|
89
|
-
node: matcher
|
|
84
|
+
node: matcher
|
|
90
85
|
});
|
|
91
86
|
}
|
|
92
87
|
|
|
@@ -29,18 +29,26 @@ var _default = (0, _utils2.createRule)({
|
|
|
29
29
|
create(context) {
|
|
30
30
|
return {
|
|
31
31
|
CallExpression(node) {
|
|
32
|
-
|
|
32
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
33
|
+
|
|
34
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
const {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
parent: expect
|
|
40
|
+
} = jestFnCall.head.node;
|
|
41
|
+
|
|
42
|
+
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const [argument] = expect.arguments;
|
|
47
|
+
const {
|
|
40
48
|
matcher
|
|
41
|
-
} =
|
|
49
|
+
} = jestFnCall;
|
|
42
50
|
|
|
43
|
-
if (!
|
|
51
|
+
if (!_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || (argument === null || argument === void 0 ? void 0 : argument.type) !== _utils.AST_NODE_TYPES.MemberExpression || !(0, _utils2.isSupportedAccessor)(argument.property, 'length')) {
|
|
44
52
|
return;
|
|
45
53
|
}
|
|
46
54
|
|
|
@@ -48,11 +56,11 @@ var _default = (0, _utils2.createRule)({
|
|
|
48
56
|
fix(fixer) {
|
|
49
57
|
return [// remove the "length" property accessor
|
|
50
58
|
fixer.removeRange([argument.property.range[0] - 1, argument.range[1]]), // replace the current matcher with "toHaveLength"
|
|
51
|
-
fixer.replaceTextRange([matcher.
|
|
59
|
+
fixer.replaceTextRange([matcher.parent.object.range[1], matcher.parent.range[1]], '.toHaveLength')];
|
|
52
60
|
},
|
|
53
61
|
|
|
54
62
|
messageId: 'useToHaveLength',
|
|
55
|
-
node: matcher
|
|
63
|
+
node: matcher
|
|
56
64
|
});
|
|
57
65
|
}
|
|
58
66
|
|