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,29 +4,21 @@ 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 withOnce = (name, addOnce) => {
|
|
13
10
|
return `${name}${addOnce ? 'Once' : ''}`;
|
|
14
11
|
};
|
|
15
|
-
|
|
16
12
|
const findSingleReturnArgumentNode = fnNode => {
|
|
17
13
|
var _fnNode$body$body$;
|
|
18
|
-
|
|
19
14
|
if (fnNode.body.type !== _utils.AST_NODE_TYPES.BlockStatement) {
|
|
20
15
|
return fnNode.body;
|
|
21
16
|
}
|
|
22
|
-
|
|
23
17
|
if (((_fnNode$body$body$ = fnNode.body.body[0]) === null || _fnNode$body$body$ === void 0 ? void 0 : _fnNode$body$body$.type) === _utils.AST_NODE_TYPES.ReturnStatement) {
|
|
24
18
|
return fnNode.body.body[0].argument;
|
|
25
19
|
}
|
|
26
|
-
|
|
27
20
|
return null;
|
|
28
21
|
};
|
|
29
|
-
|
|
30
22
|
var _default = (0, _utils2.createRule)({
|
|
31
23
|
name: __filename,
|
|
32
24
|
meta: {
|
|
@@ -43,19 +35,15 @@ var _default = (0, _utils2.createRule)({
|
|
|
43
35
|
fixable: 'code'
|
|
44
36
|
},
|
|
45
37
|
defaultOptions: [],
|
|
46
|
-
|
|
47
38
|
create(context) {
|
|
48
39
|
const report = (property, isOnce, outerArgNode, innerArgNode = outerArgNode) => {
|
|
49
40
|
if ((innerArgNode === null || innerArgNode === void 0 ? void 0 : innerArgNode.type) !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
50
41
|
return;
|
|
51
42
|
}
|
|
52
|
-
|
|
53
43
|
const argName = (0, _utils2.getNodeName)(innerArgNode);
|
|
54
|
-
|
|
55
44
|
if (argName !== 'Promise.resolve' && argName !== 'Promise.reject') {
|
|
56
45
|
return;
|
|
57
46
|
}
|
|
58
|
-
|
|
59
47
|
const replacement = withOnce(argName.endsWith('reject') ? 'mockRejectedValue' : 'mockResolvedValue', isOnce);
|
|
60
48
|
context.report({
|
|
61
49
|
node: property,
|
|
@@ -63,49 +51,40 @@ var _default = (0, _utils2.createRule)({
|
|
|
63
51
|
data: {
|
|
64
52
|
replacement
|
|
65
53
|
},
|
|
66
|
-
|
|
67
54
|
fix(fixer) {
|
|
68
|
-
const sourceCode = context.getSourceCode();
|
|
69
|
-
// fixing since we have no idea what to do with the extra arguments
|
|
55
|
+
const sourceCode = context.getSourceCode();
|
|
70
56
|
|
|
57
|
+
// there shouldn't be more than one argument, but if there is don't try
|
|
58
|
+
// fixing since we have no idea what to do with the extra arguments
|
|
71
59
|
if (innerArgNode.arguments.length > 1) {
|
|
72
60
|
return null;
|
|
73
61
|
}
|
|
74
|
-
|
|
75
|
-
|
|
62
|
+
return [fixer.replaceText(property, replacement), fixer.replaceText(outerArgNode,
|
|
63
|
+
// the value argument for both Promise methods is optional,
|
|
76
64
|
// whereas for Jest they're required so use an explicit undefined
|
|
77
65
|
// if no argument is being passed to the call we're replacing
|
|
78
66
|
innerArgNode.arguments.length === 1 ? sourceCode.getText(innerArgNode.arguments[0]) : 'undefined')];
|
|
79
67
|
}
|
|
80
|
-
|
|
81
68
|
});
|
|
82
69
|
};
|
|
83
|
-
|
|
84
70
|
return {
|
|
85
71
|
CallExpression(node) {
|
|
86
72
|
if (node.callee.type !== _utils.AST_NODE_TYPES.MemberExpression || !(0, _utils2.isSupportedAccessor)(node.callee.property) || node.arguments.length === 0) {
|
|
87
73
|
return;
|
|
88
74
|
}
|
|
89
|
-
|
|
90
75
|
const mockFnName = (0, _utils2.getAccessorValue)(node.callee.property);
|
|
91
76
|
const isOnce = mockFnName.endsWith('Once');
|
|
92
|
-
|
|
93
77
|
if (mockFnName === withOnce('mockReturnValue', isOnce)) {
|
|
94
78
|
report(node.callee.property, isOnce, node.arguments[0]);
|
|
95
79
|
} else if (mockFnName === withOnce('mockImplementation', isOnce)) {
|
|
96
80
|
const [arg] = node.arguments;
|
|
97
|
-
|
|
98
81
|
if (!(0, _utils2.isFunction)(arg) || arg.params.length !== 0) {
|
|
99
82
|
return;
|
|
100
83
|
}
|
|
101
|
-
|
|
102
84
|
report(node.callee.property, isOnce, arg, findSingleReturnArgumentNode(arg));
|
|
103
85
|
}
|
|
104
86
|
}
|
|
105
|
-
|
|
106
87
|
};
|
|
107
88
|
}
|
|
108
|
-
|
|
109
89
|
});
|
|
110
|
-
|
|
111
90
|
exports.default = _default;
|
|
@@ -4,39 +4,34 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _utils = require("./utils");
|
|
9
|
-
|
|
10
8
|
const snapshotMatchers = ['toMatchSnapshot', 'toThrowErrorMatchingSnapshot'];
|
|
11
9
|
const snapshotMatcherNames = snapshotMatchers;
|
|
12
|
-
|
|
13
10
|
const isSnapshotMatcherWithoutHint = expectFnCall => {
|
|
14
11
|
if (expectFnCall.args.length === 0) {
|
|
15
12
|
return true;
|
|
16
|
-
}
|
|
17
|
-
|
|
13
|
+
}
|
|
18
14
|
|
|
15
|
+
// this matcher only supports one argument which is the hint
|
|
19
16
|
if (!(0, _utils.isSupportedAccessor)(expectFnCall.matcher, 'toMatchSnapshot')) {
|
|
20
17
|
return expectFnCall.args.length !== 1;
|
|
21
|
-
}
|
|
22
|
-
// the second one should be the hint
|
|
23
|
-
|
|
18
|
+
}
|
|
24
19
|
|
|
20
|
+
// if we're being passed two arguments,
|
|
21
|
+
// the second one should be the hint
|
|
25
22
|
if (expectFnCall.args.length === 2) {
|
|
26
23
|
return false;
|
|
27
24
|
}
|
|
25
|
+
const [arg] = expectFnCall.args;
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
// the first argument to `toMatchSnapshot` can be _either_ a snapshot hint or
|
|
30
28
|
// an object with asymmetric matchers, so we can't just assume that the first
|
|
31
29
|
// argument is a hint when it's by itself.
|
|
32
|
-
|
|
33
30
|
return !(0, _utils.isStringNode)(arg);
|
|
34
31
|
};
|
|
35
|
-
|
|
36
32
|
const messages = {
|
|
37
33
|
missingHint: 'You should provide a hint for this snapshot'
|
|
38
34
|
};
|
|
39
|
-
|
|
40
35
|
var _default = (0, _utils.createRule)({
|
|
41
36
|
name: __filename,
|
|
42
37
|
meta: {
|
|
@@ -53,12 +48,10 @@ var _default = (0, _utils.createRule)({
|
|
|
53
48
|
}]
|
|
54
49
|
},
|
|
55
50
|
defaultOptions: ['multi'],
|
|
56
|
-
|
|
57
51
|
create(context, [mode]) {
|
|
58
52
|
const snapshotMatchers = [];
|
|
59
53
|
const depths = [];
|
|
60
54
|
let expressionDepth = 0;
|
|
61
|
-
|
|
62
55
|
const reportSnapshotMatchersWithoutHints = () => {
|
|
63
56
|
for (const snapshotMatcher of snapshotMatchers) {
|
|
64
57
|
if (isSnapshotMatcherWithoutHint(snapshotMatcher)) {
|
|
@@ -69,70 +62,53 @@ var _default = (0, _utils.createRule)({
|
|
|
69
62
|
}
|
|
70
63
|
}
|
|
71
64
|
};
|
|
72
|
-
|
|
73
65
|
const enterExpression = () => {
|
|
74
66
|
expressionDepth++;
|
|
75
67
|
};
|
|
76
|
-
|
|
77
68
|
const exitExpression = () => {
|
|
78
69
|
expressionDepth--;
|
|
79
|
-
|
|
80
70
|
if (mode === 'always') {
|
|
81
71
|
reportSnapshotMatchersWithoutHints();
|
|
82
72
|
snapshotMatchers.length = 0;
|
|
83
73
|
}
|
|
84
|
-
|
|
85
74
|
if (mode === 'multi' && expressionDepth === 0) {
|
|
86
75
|
if (snapshotMatchers.length > 1) {
|
|
87
76
|
reportSnapshotMatchersWithoutHints();
|
|
88
77
|
}
|
|
89
|
-
|
|
90
78
|
snapshotMatchers.length = 0;
|
|
91
79
|
}
|
|
92
80
|
};
|
|
93
|
-
|
|
94
81
|
return {
|
|
95
82
|
'Program:exit'() {
|
|
96
83
|
enterExpression();
|
|
97
84
|
exitExpression();
|
|
98
85
|
},
|
|
99
|
-
|
|
100
86
|
FunctionExpression: enterExpression,
|
|
101
87
|
'FunctionExpression:exit': exitExpression,
|
|
102
88
|
ArrowFunctionExpression: enterExpression,
|
|
103
89
|
'ArrowFunctionExpression:exit': exitExpression,
|
|
104
|
-
|
|
105
90
|
'CallExpression:exit'(node) {
|
|
106
91
|
if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe', 'test'])) {
|
|
107
92
|
/* istanbul ignore next */
|
|
108
93
|
expressionDepth = depths.pop() ?? 0;
|
|
109
94
|
}
|
|
110
95
|
},
|
|
111
|
-
|
|
112
96
|
CallExpression(node) {
|
|
113
97
|
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
114
|
-
|
|
115
98
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
|
|
116
99
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'describe' || (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test') {
|
|
117
100
|
depths.push(expressionDepth);
|
|
118
101
|
expressionDepth = 0;
|
|
119
102
|
}
|
|
120
|
-
|
|
121
103
|
return;
|
|
122
104
|
}
|
|
123
|
-
|
|
124
105
|
const matcherName = (0, _utils.getAccessorValue)(jestFnCall.matcher);
|
|
125
|
-
|
|
126
106
|
if (!snapshotMatcherNames.includes(matcherName)) {
|
|
127
107
|
return;
|
|
128
108
|
}
|
|
129
|
-
|
|
130
109
|
snapshotMatchers.push(jestFnCall);
|
|
131
110
|
}
|
|
132
|
-
|
|
133
111
|
};
|
|
134
112
|
}
|
|
135
|
-
|
|
136
113
|
});
|
|
137
|
-
|
|
138
114
|
exports.default = _default;
|
|
@@ -4,41 +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 findNodeObject = node => {
|
|
13
10
|
if ('object' in node) {
|
|
14
11
|
return node.object;
|
|
15
12
|
}
|
|
16
|
-
|
|
17
13
|
if (node.callee.type === _utils.AST_NODE_TYPES.MemberExpression) {
|
|
18
14
|
return node.callee.object;
|
|
19
15
|
}
|
|
20
|
-
|
|
21
16
|
return null;
|
|
22
17
|
};
|
|
23
|
-
|
|
24
18
|
const getJestFnCall = node => {
|
|
25
19
|
if (node.type !== _utils.AST_NODE_TYPES.CallExpression && node.type !== _utils.AST_NODE_TYPES.MemberExpression) {
|
|
26
20
|
return null;
|
|
27
21
|
}
|
|
28
|
-
|
|
29
22
|
const obj = findNodeObject(node);
|
|
30
|
-
|
|
31
23
|
if (!obj) {
|
|
32
24
|
return null;
|
|
33
25
|
}
|
|
34
|
-
|
|
35
26
|
if (obj.type === _utils.AST_NODE_TYPES.Identifier) {
|
|
36
27
|
return node.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.getNodeName)(node.callee) === 'jest.fn' ? node : null;
|
|
37
28
|
}
|
|
38
|
-
|
|
39
29
|
return getJestFnCall(obj);
|
|
40
30
|
};
|
|
41
|
-
|
|
42
31
|
var _default = (0, _utils2.createRule)({
|
|
43
32
|
name: __filename,
|
|
44
33
|
meta: {
|
|
@@ -55,7 +44,6 @@ var _default = (0, _utils2.createRule)({
|
|
|
55
44
|
type: 'suggestion'
|
|
56
45
|
},
|
|
57
46
|
defaultOptions: [],
|
|
58
|
-
|
|
59
47
|
create(context) {
|
|
60
48
|
return {
|
|
61
49
|
AssignmentExpression(node) {
|
|
@@ -69,7 +57,6 @@ var _default = (0, _utils2.createRule)({
|
|
|
69
57
|
context.report({
|
|
70
58
|
node,
|
|
71
59
|
messageId: 'useJestSpyOn',
|
|
72
|
-
|
|
73
60
|
fix(fixer) {
|
|
74
61
|
const leftPropQuote = left.property.type === _utils.AST_NODE_TYPES.Identifier ? "'" : '';
|
|
75
62
|
const [arg] = jestFnCall.arguments;
|
|
@@ -77,13 +64,9 @@ var _default = (0, _utils2.createRule)({
|
|
|
77
64
|
const mockImplementation = argSource ? `.mockImplementation(${argSource})` : '.mockImplementation()';
|
|
78
65
|
return [fixer.insertTextBefore(left, `jest.spyOn(`), fixer.replaceTextRange([left.object.range[1], left.property.range[0]], `, ${leftPropQuote}`), fixer.replaceTextRange([left.property.range[1], jestFnCall.range[1]], `${leftPropQuote})${mockImplementation}`)];
|
|
79
66
|
}
|
|
80
|
-
|
|
81
67
|
});
|
|
82
68
|
}
|
|
83
|
-
|
|
84
69
|
};
|
|
85
70
|
}
|
|
86
|
-
|
|
87
71
|
});
|
|
88
|
-
|
|
89
72
|
exports.default = _default;
|
|
@@ -4,9 +4,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _utils = require("./utils");
|
|
9
|
-
|
|
10
8
|
var _default = (0, _utils.createRule)({
|
|
11
9
|
name: __filename,
|
|
12
10
|
meta: {
|
|
@@ -24,20 +22,16 @@ var _default = (0, _utils.createRule)({
|
|
|
24
22
|
hasSuggestions: true
|
|
25
23
|
},
|
|
26
24
|
defaultOptions: [],
|
|
27
|
-
|
|
28
25
|
create(context) {
|
|
29
26
|
return {
|
|
30
27
|
CallExpression(node) {
|
|
31
28
|
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
32
|
-
|
|
33
29
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
|
|
34
30
|
return;
|
|
35
31
|
}
|
|
36
|
-
|
|
37
32
|
const {
|
|
38
33
|
matcher
|
|
39
34
|
} = jestFnCall;
|
|
40
|
-
|
|
41
35
|
if ((0, _utils.isSupportedAccessor)(matcher, 'toEqual')) {
|
|
42
36
|
context.report({
|
|
43
37
|
messageId: 'useToStrictEqual',
|
|
@@ -49,10 +43,7 @@ var _default = (0, _utils.createRule)({
|
|
|
49
43
|
});
|
|
50
44
|
}
|
|
51
45
|
}
|
|
52
|
-
|
|
53
46
|
};
|
|
54
47
|
}
|
|
55
|
-
|
|
56
48
|
});
|
|
57
|
-
|
|
58
49
|
exports.default = _default;
|
|
@@ -4,62 +4,45 @@ 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 isNullLiteral = node => node.type === _utils.AST_NODE_TYPES.Literal && node.value === null;
|
|
10
|
+
|
|
13
11
|
/**
|
|
14
12
|
* Checks if the given `ParsedEqualityMatcherCall` is a call to one of the equality matchers,
|
|
15
13
|
* with a `null` literal as the sole argument.
|
|
16
14
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
15
|
const isNullEqualityMatcher = expectFnCall => isNullLiteral((0, _utils2.getFirstMatcherArg)(expectFnCall));
|
|
20
|
-
|
|
21
16
|
const isFirstArgumentIdentifier = (expectFnCall, name) => (0, _utils2.isIdentifier)((0, _utils2.getFirstMatcherArg)(expectFnCall), name);
|
|
22
|
-
|
|
23
17
|
const shouldUseToBe = expectFnCall => {
|
|
24
18
|
let firstArg = (0, _utils2.getFirstMatcherArg)(expectFnCall);
|
|
25
|
-
|
|
26
19
|
if (firstArg.type === _utils.AST_NODE_TYPES.UnaryExpression && firstArg.operator === '-') {
|
|
27
20
|
firstArg = firstArg.argument;
|
|
28
21
|
}
|
|
29
|
-
|
|
30
22
|
if (firstArg.type === _utils.AST_NODE_TYPES.Literal) {
|
|
31
23
|
// regex literals are classed as literals, but they're actually objects
|
|
32
24
|
// which means "toBe" will give different results than other matchers
|
|
33
25
|
return !('regex' in firstArg);
|
|
34
26
|
}
|
|
35
|
-
|
|
36
27
|
return firstArg.type === _utils.AST_NODE_TYPES.TemplateLiteral;
|
|
37
28
|
};
|
|
38
|
-
|
|
39
29
|
const reportPreferToBe = (context, whatToBe, expectFnCall, modifierNode) => {
|
|
40
30
|
context.report({
|
|
41
31
|
messageId: `useToBe${whatToBe}`,
|
|
42
|
-
|
|
43
32
|
fix(fixer) {
|
|
44
33
|
var _expectFnCall$args;
|
|
45
|
-
|
|
46
34
|
const fixes = [(0, _utils2.replaceAccessorFixer)(fixer, expectFnCall.matcher, `toBe${whatToBe}`)];
|
|
47
|
-
|
|
48
35
|
if ((_expectFnCall$args = expectFnCall.args) !== null && _expectFnCall$args !== void 0 && _expectFnCall$args.length && whatToBe !== '') {
|
|
49
36
|
fixes.push(fixer.remove(expectFnCall.args[0]));
|
|
50
37
|
}
|
|
51
|
-
|
|
52
38
|
if (modifierNode) {
|
|
53
39
|
fixes.push(fixer.removeRange([modifierNode.range[0] - 1, modifierNode.range[1]]));
|
|
54
40
|
}
|
|
55
|
-
|
|
56
41
|
return fixes;
|
|
57
42
|
},
|
|
58
|
-
|
|
59
43
|
node: expectFnCall.matcher
|
|
60
44
|
});
|
|
61
45
|
};
|
|
62
|
-
|
|
63
46
|
var _default = (0, _utils2.createRule)({
|
|
64
47
|
name: __filename,
|
|
65
48
|
meta: {
|
|
@@ -80,52 +63,40 @@ var _default = (0, _utils2.createRule)({
|
|
|
80
63
|
schema: []
|
|
81
64
|
},
|
|
82
65
|
defaultOptions: [],
|
|
83
|
-
|
|
84
66
|
create(context) {
|
|
85
67
|
return {
|
|
86
68
|
CallExpression(node) {
|
|
87
69
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
88
|
-
|
|
89
70
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
|
|
90
71
|
return;
|
|
91
72
|
}
|
|
92
|
-
|
|
93
73
|
const matcherName = (0, _utils2.getAccessorValue)(jestFnCall.matcher);
|
|
94
74
|
const notModifier = jestFnCall.modifiers.find(nod => (0, _utils2.getAccessorValue)(nod) === 'not');
|
|
95
|
-
|
|
96
75
|
if (notModifier && ['toBeUndefined', 'toBeDefined'].includes(matcherName)) {
|
|
97
76
|
reportPreferToBe(context, matcherName === 'toBeDefined' ? 'Undefined' : 'Defined', jestFnCall, notModifier);
|
|
98
77
|
return;
|
|
99
78
|
}
|
|
100
|
-
|
|
101
79
|
if (!_utils2.EqualityMatcher.hasOwnProperty(matcherName) || jestFnCall.args.length === 0) {
|
|
102
80
|
return;
|
|
103
81
|
}
|
|
104
|
-
|
|
105
82
|
if (isNullEqualityMatcher(jestFnCall)) {
|
|
106
83
|
reportPreferToBe(context, 'Null', jestFnCall);
|
|
107
84
|
return;
|
|
108
85
|
}
|
|
109
|
-
|
|
110
86
|
if (isFirstArgumentIdentifier(jestFnCall, 'undefined')) {
|
|
111
87
|
const name = notModifier ? 'Defined' : 'Undefined';
|
|
112
88
|
reportPreferToBe(context, name, jestFnCall, notModifier);
|
|
113
89
|
return;
|
|
114
90
|
}
|
|
115
|
-
|
|
116
91
|
if (isFirstArgumentIdentifier(jestFnCall, 'NaN')) {
|
|
117
92
|
reportPreferToBe(context, 'NaN', jestFnCall);
|
|
118
93
|
return;
|
|
119
94
|
}
|
|
120
|
-
|
|
121
95
|
if (shouldUseToBe(jestFnCall) && matcherName !== _utils2.EqualityMatcher.toBe) {
|
|
122
96
|
reportPreferToBe(context, '', jestFnCall);
|
|
123
97
|
}
|
|
124
98
|
}
|
|
125
|
-
|
|
126
99
|
};
|
|
127
100
|
}
|
|
128
|
-
|
|
129
101
|
});
|
|
130
|
-
|
|
131
102
|
exports.default = _default;
|
|
@@ -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
|
/**
|
|
13
10
|
* Checks if the given `node` is a `CallExpression` representing the calling
|
|
14
11
|
* of an `includes`-like method that can be 'fixed' (using `toContain`).
|
|
@@ -17,9 +14,9 @@ var _utils2 = require("./utils");
|
|
|
17
14
|
*
|
|
18
15
|
* @return {node is FixableIncludesCallExpression}
|
|
19
16
|
*/
|
|
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;
|
|
21
|
-
|
|
17
|
+
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;
|
|
22
18
|
|
|
19
|
+
// expect(array.includes(<value>)[not.]{toBe,toEqual}(<boolean>)
|
|
23
20
|
var _default = (0, _utils2.createRule)({
|
|
24
21
|
name: __filename,
|
|
25
22
|
meta: {
|
|
@@ -36,24 +33,19 @@ var _default = (0, _utils2.createRule)({
|
|
|
36
33
|
schema: []
|
|
37
34
|
},
|
|
38
35
|
defaultOptions: [],
|
|
39
|
-
|
|
40
36
|
create(context) {
|
|
41
37
|
return {
|
|
42
38
|
CallExpression(node) {
|
|
43
39
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
44
|
-
|
|
45
40
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect' || jestFnCall.args.length === 0) {
|
|
46
41
|
return;
|
|
47
42
|
}
|
|
48
|
-
|
|
49
43
|
const {
|
|
50
44
|
parent: expect
|
|
51
45
|
} = jestFnCall.head.node;
|
|
52
|
-
|
|
53
46
|
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
54
47
|
return;
|
|
55
48
|
}
|
|
56
|
-
|
|
57
49
|
const {
|
|
58
50
|
arguments: [includesCall],
|
|
59
51
|
range: [, expectCallEnd]
|
|
@@ -62,32 +54,30 @@ var _default = (0, _utils2.createRule)({
|
|
|
62
54
|
matcher
|
|
63
55
|
} = jestFnCall;
|
|
64
56
|
const matcherArg = (0, _utils2.getFirstMatcherArg)(jestFnCall);
|
|
65
|
-
|
|
66
57
|
if (!includesCall || matcherArg.type === _utils.AST_NODE_TYPES.SpreadElement || !_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || !(0, _utils2.isBooleanLiteral)(matcherArg) || !isFixableIncludesCallExpression(includesCall)) {
|
|
67
58
|
return;
|
|
68
59
|
}
|
|
69
|
-
|
|
70
60
|
const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not');
|
|
71
61
|
context.report({
|
|
72
62
|
fix(fixer) {
|
|
73
|
-
const sourceCode = context.getSourceCode();
|
|
74
|
-
// value is itself negated by the "not" modifier
|
|
63
|
+
const sourceCode = context.getSourceCode();
|
|
75
64
|
|
|
65
|
+
// we need to negate the expectation if the current expected
|
|
66
|
+
// value is itself negated by the "not" modifier
|
|
76
67
|
const addNotModifier = matcherArg.value === hasNot;
|
|
77
|
-
return [
|
|
78
|
-
|
|
79
|
-
fixer.
|
|
68
|
+
return [
|
|
69
|
+
// remove the "includes" call entirely
|
|
70
|
+
fixer.removeRange([includesCall.callee.property.range[0] - 1, includesCall.range[1]]),
|
|
71
|
+
// replace the current matcher with "toContain", adding "not" if needed
|
|
72
|
+
fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], addNotModifier ? `.${_utils2.ModifierName.not}.toContain` : '.toContain'),
|
|
73
|
+
// replace the matcher argument with the value from the "includes"
|
|
80
74
|
fixer.replaceText(jestFnCall.args[0], sourceCode.getText(includesCall.arguments[0]))];
|
|
81
75
|
},
|
|
82
|
-
|
|
83
76
|
messageId: 'useToContain',
|
|
84
77
|
node: matcher
|
|
85
78
|
});
|
|
86
79
|
}
|
|
87
|
-
|
|
88
80
|
};
|
|
89
81
|
}
|
|
90
|
-
|
|
91
82
|
});
|
|
92
|
-
|
|
93
83
|
exports.default = _default;
|
|
@@ -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
|
var _default = (0, _utils2.createRule)({
|
|
13
10
|
name: __filename,
|
|
14
11
|
meta: {
|
|
@@ -25,48 +22,39 @@ var _default = (0, _utils2.createRule)({
|
|
|
25
22
|
schema: []
|
|
26
23
|
},
|
|
27
24
|
defaultOptions: [],
|
|
28
|
-
|
|
29
25
|
create(context) {
|
|
30
26
|
return {
|
|
31
27
|
CallExpression(node) {
|
|
32
28
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
33
|
-
|
|
34
29
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
|
|
35
30
|
return;
|
|
36
31
|
}
|
|
37
|
-
|
|
38
32
|
const {
|
|
39
33
|
parent: expect
|
|
40
34
|
} = jestFnCall.head.node;
|
|
41
|
-
|
|
42
35
|
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
43
36
|
return;
|
|
44
37
|
}
|
|
45
|
-
|
|
46
38
|
const [argument] = expect.arguments;
|
|
47
39
|
const {
|
|
48
40
|
matcher
|
|
49
41
|
} = jestFnCall;
|
|
50
|
-
|
|
51
42
|
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')) {
|
|
52
43
|
return;
|
|
53
44
|
}
|
|
54
|
-
|
|
55
45
|
context.report({
|
|
56
46
|
fix(fixer) {
|
|
57
|
-
return [
|
|
58
|
-
|
|
47
|
+
return [
|
|
48
|
+
// remove the "length" property accessor
|
|
49
|
+
fixer.removeRange([argument.property.range[0] - 1, argument.range[1]]),
|
|
50
|
+
// replace the current matcher with "toHaveLength"
|
|
59
51
|
fixer.replaceTextRange([matcher.parent.object.range[1], matcher.parent.range[1]], '.toHaveLength')];
|
|
60
52
|
},
|
|
61
|
-
|
|
62
53
|
messageId: 'useToHaveLength',
|
|
63
54
|
node: matcher
|
|
64
55
|
});
|
|
65
56
|
}
|
|
66
|
-
|
|
67
57
|
};
|
|
68
58
|
}
|
|
69
|
-
|
|
70
59
|
});
|
|
71
|
-
|
|
72
60
|
exports.default = _default;
|