eslint-plugin-jest 26.8.7 → 27.1.5
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 +82 -78
- package/docs/rules/consistent-test-it.md +9 -4
- package/docs/rules/expect-expect.md +5 -0
- package/docs/rules/max-expects.md +3 -1
- package/docs/rules/max-nested-describe.md +3 -1
- package/docs/rules/no-alias-methods.md +13 -2
- package/docs/rules/no-commented-out-tests.md +6 -1
- package/docs/rules/no-conditional-expect.md +7 -2
- package/docs/rules/no-conditional-in-test.md +3 -1
- package/docs/rules/no-deprecated-functions.md +14 -7
- package/docs/rules/no-disabled-tests.md +6 -1
- package/docs/rules/no-done-callback.md +9 -1
- package/docs/rules/no-duplicate-hooks.md +3 -1
- package/docs/rules/no-export.md +6 -1
- package/docs/rules/no-focused-tests.md +10 -1
- package/docs/rules/no-hooks.md +3 -1
- package/docs/rules/no-identical-title.md +6 -1
- package/docs/rules/no-if.md +4 -4
- package/docs/rules/no-interpolation-in-snapshots.md +6 -1
- package/docs/rules/no-jasmine-globals.md +10 -2
- package/docs/rules/no-large-snapshots.md +4 -2
- package/docs/rules/no-mocks-import.md +6 -1
- package/docs/rules/no-restricted-jest-methods.md +51 -0
- package/docs/rules/no-restricted-matchers.md +19 -4
- package/docs/rules/no-standalone-expect.md +6 -1
- package/docs/rules/no-test-prefixes.md +9 -1
- package/docs/rules/no-test-return-statement.md +2 -0
- package/docs/rules/prefer-called-with.md +2 -0
- package/docs/rules/prefer-comparison-matcher.md +5 -0
- package/docs/rules/prefer-each.md +56 -0
- package/docs/rules/prefer-equality-matcher.md +5 -0
- package/docs/rules/prefer-expect-assertions.md +5 -2
- package/docs/rules/prefer-expect-resolves.md +8 -1
- package/docs/rules/prefer-hooks-in-order.md +3 -1
- package/docs/rules/prefer-hooks-on-top.md +3 -1
- package/docs/rules/prefer-lowercase-title.md +5 -0
- package/docs/rules/prefer-mock-promise-shorthand.md +6 -1
- package/docs/rules/prefer-snapshot-hint.md +2 -0
- package/docs/rules/prefer-spy-on.md +5 -2
- package/docs/rules/prefer-strict-equal.md +5 -2
- package/docs/rules/prefer-to-be.md +8 -0
- package/docs/rules/prefer-to-contain.md +8 -2
- package/docs/rules/prefer-to-have-length.md +8 -2
- package/docs/rules/prefer-todo.md +5 -2
- package/docs/rules/require-hook.md +2 -0
- package/docs/rules/require-to-throw-message.md +2 -2
- package/docs/rules/require-top-level-describe.md +5 -1
- package/docs/rules/unbound-method.md +7 -2
- package/docs/rules/valid-describe-callback.md +6 -1
- package/docs/rules/valid-expect-in-promise.md +6 -1
- package/docs/rules/valid-expect.md +5 -2
- package/docs/rules/valid-title.md +9 -1
- package/lib/index.js +14 -25
- package/lib/processors/snapshot-processor.js +3 -5
- package/lib/rules/consistent-test-it.js +1 -19
- package/lib/rules/expect-expect.js +1 -18
- package/lib/rules/max-expects.js +0 -16
- package/lib/rules/max-nested-describe.js +0 -13
- package/lib/rules/no-alias-methods.js +1 -10
- package/lib/rules/no-commented-out-tests.js +0 -10
- package/lib/rules/no-conditional-expect.js +2 -23
- 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 +3 -19
- package/lib/rules/no-done-callback.js +5 -35
- package/lib/rules/no-duplicate-hooks.js +0 -12
- package/lib/rules/no-export.js +0 -12
- package/lib/rules/no-focused-tests.js +1 -17
- 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 +1 -23
- package/lib/rules/no-large-snapshots.js +4 -24
- package/lib/rules/no-mocks-import.js +0 -12
- package/lib/rules/no-restricted-jest-methods.js +56 -0
- package/lib/rules/no-restricted-matchers.js +13 -28
- 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 +80 -0
- package/lib/rules/prefer-equality-matcher.js +12 -25
- package/lib/rules/prefer-expect-assertions.js +8 -54
- 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 +8 -34
- package/lib/rules/prefer-spy-on.js +0 -17
- package/lib/rules/prefer-strict-equal.js +1 -11
- package/lib/rules/prefer-to-be.js +5 -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 +1 -25
- package/lib/rules/require-to-throw-message.js +0 -9
- package/lib/rules/require-top-level-describe.js +1 -18
- package/lib/rules/unbound-method.js +3 -30
- 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 +51 -154
- package/lib/rules/valid-describe-callback.js +0 -17
- package/lib/rules/valid-expect-in-promise.js +28 -95
- package/lib/rules/valid-expect.js +5 -48
- package/lib/rules/valid-title.js +5 -40
- package/package.json +20 -16
- package/docs/rules/no-jest-import.md +0 -20
- package/lib/rules/no-jest-import.js +0 -48
|
@@ -4,17 +4,14 @@ 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: {
|
|
15
12
|
docs: {
|
|
16
13
|
category: 'Best Practices',
|
|
17
|
-
description: '
|
|
14
|
+
description: 'Require using `.only` and `.skip` over `f` and `x`',
|
|
18
15
|
recommended: 'error'
|
|
19
16
|
},
|
|
20
17
|
messages: {
|
|
@@ -25,20 +22,16 @@ var _default = (0, _utils2.createRule)({
|
|
|
25
22
|
type: 'suggestion'
|
|
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) !== 'describe' && (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'test') {
|
|
35
30
|
return;
|
|
36
31
|
}
|
|
37
|
-
|
|
38
32
|
if (jestFnCall.name[0] !== 'f' && jestFnCall.name[0] !== 'x') {
|
|
39
33
|
return;
|
|
40
34
|
}
|
|
41
|
-
|
|
42
35
|
const preferredNodeName = [jestFnCall.name.slice(1), jestFnCall.name[0] === 'f' ? 'only' : 'skip', ...jestFnCall.members.map(s => (0, _utils2.getAccessorValue)(s))].join('.');
|
|
43
36
|
const funcNode = node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression ? node.callee.tag : node.callee.type === _utils.AST_NODE_TYPES.CallExpression ? node.callee.callee : node.callee;
|
|
44
37
|
context.report({
|
|
@@ -47,17 +40,12 @@ var _default = (0, _utils2.createRule)({
|
|
|
47
40
|
data: {
|
|
48
41
|
preferredNodeName
|
|
49
42
|
},
|
|
50
|
-
|
|
51
43
|
fix(fixer) {
|
|
52
44
|
return [fixer.replaceText(funcNode, preferredNodeName)];
|
|
53
45
|
}
|
|
54
|
-
|
|
55
46
|
});
|
|
56
47
|
}
|
|
57
|
-
|
|
58
48
|
};
|
|
59
49
|
}
|
|
60
|
-
|
|
61
50
|
});
|
|
62
|
-
|
|
63
51
|
exports.default = _default;
|
|
@@ -4,21 +4,15 @@ 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 getBody = args => {
|
|
13
10
|
const [, secondArg] = args;
|
|
14
|
-
|
|
15
11
|
if (secondArg && (0, _utils2.isFunction)(secondArg) && secondArg.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
|
|
16
12
|
return secondArg.body.body;
|
|
17
13
|
}
|
|
18
|
-
|
|
19
14
|
return [];
|
|
20
15
|
};
|
|
21
|
-
|
|
22
16
|
var _default = (0, _utils2.createRule)({
|
|
23
17
|
name: __filename,
|
|
24
18
|
meta: {
|
|
@@ -34,14 +28,12 @@ var _default = (0, _utils2.createRule)({
|
|
|
34
28
|
type: 'suggestion'
|
|
35
29
|
},
|
|
36
30
|
defaultOptions: [],
|
|
37
|
-
|
|
38
31
|
create(context) {
|
|
39
32
|
return {
|
|
40
33
|
CallExpression(node) {
|
|
41
34
|
if (!(0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
|
|
42
35
|
return;
|
|
43
36
|
}
|
|
44
|
-
|
|
45
37
|
const body = getBody(node.arguments);
|
|
46
38
|
const returnStmt = body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement);
|
|
47
39
|
if (!returnStmt) return;
|
|
@@ -50,7 +42,6 @@ var _default = (0, _utils2.createRule)({
|
|
|
50
42
|
node: returnStmt
|
|
51
43
|
});
|
|
52
44
|
},
|
|
53
|
-
|
|
54
45
|
FunctionDeclaration(node) {
|
|
55
46
|
const declaredVariables = context.getDeclaredVariables(node);
|
|
56
47
|
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables, context);
|
|
@@ -62,10 +53,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
62
53
|
node: returnStmt
|
|
63
54
|
});
|
|
64
55
|
}
|
|
65
|
-
|
|
66
56
|
};
|
|
67
57
|
}
|
|
68
|
-
|
|
69
58
|
});
|
|
70
|
-
|
|
71
59
|
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: {
|
|
@@ -22,25 +20,20 @@ var _default = (0, _utils.createRule)({
|
|
|
22
20
|
schema: []
|
|
23
21
|
},
|
|
24
22
|
defaultOptions: [],
|
|
25
|
-
|
|
26
23
|
create(context) {
|
|
27
24
|
return {
|
|
28
25
|
CallExpression(node) {
|
|
29
26
|
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
30
|
-
|
|
31
27
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
|
|
32
28
|
return;
|
|
33
29
|
}
|
|
34
|
-
|
|
35
30
|
if (jestFnCall.modifiers.some(nod => (0, _utils.getAccessorValue)(nod) === 'not')) {
|
|
36
31
|
return;
|
|
37
32
|
}
|
|
38
|
-
|
|
39
33
|
const {
|
|
40
34
|
matcher
|
|
41
35
|
} = jestFnCall;
|
|
42
36
|
const matcherName = (0, _utils.getAccessorValue)(matcher);
|
|
43
|
-
|
|
44
37
|
if (['toBeCalled', 'toHaveBeenCalled'].includes(matcherName)) {
|
|
45
38
|
context.report({
|
|
46
39
|
data: {
|
|
@@ -51,10 +44,7 @@ var _default = (0, _utils.createRule)({
|
|
|
51
44
|
});
|
|
52
45
|
}
|
|
53
46
|
}
|
|
54
|
-
|
|
55
47
|
};
|
|
56
48
|
}
|
|
57
|
-
|
|
58
49
|
});
|
|
59
|
-
|
|
60
50
|
exports.default = _default;
|
|
@@ -4,57 +4,41 @@ 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 isString = node => {
|
|
13
10
|
return (0, _utils2.isStringNode)(node) || node.type === _utils.AST_NODE_TYPES.TemplateLiteral;
|
|
14
11
|
};
|
|
15
|
-
|
|
16
12
|
const isComparingToString = expression => {
|
|
17
13
|
return isString(expression.left) || isString(expression.right);
|
|
18
14
|
};
|
|
19
|
-
|
|
20
15
|
const invertOperator = operator => {
|
|
21
16
|
switch (operator) {
|
|
22
17
|
case '>':
|
|
23
18
|
return '<=';
|
|
24
|
-
|
|
25
19
|
case '<':
|
|
26
20
|
return '>=';
|
|
27
|
-
|
|
28
21
|
case '>=':
|
|
29
22
|
return '<';
|
|
30
|
-
|
|
31
23
|
case '<=':
|
|
32
24
|
return '>';
|
|
33
25
|
}
|
|
34
|
-
|
|
35
26
|
return null;
|
|
36
27
|
};
|
|
37
|
-
|
|
38
28
|
const determineMatcher = (operator, negated) => {
|
|
39
29
|
const op = negated ? invertOperator(operator) : operator;
|
|
40
|
-
|
|
41
30
|
switch (op) {
|
|
42
31
|
case '>':
|
|
43
32
|
return 'toBeGreaterThan';
|
|
44
|
-
|
|
45
33
|
case '<':
|
|
46
34
|
return 'toBeLessThan';
|
|
47
|
-
|
|
48
35
|
case '>=':
|
|
49
36
|
return 'toBeGreaterThanOrEqual';
|
|
50
|
-
|
|
51
37
|
case '<=':
|
|
52
38
|
return 'toBeLessThanOrEqual';
|
|
53
39
|
}
|
|
54
|
-
|
|
55
40
|
return null;
|
|
56
41
|
};
|
|
57
|
-
|
|
58
42
|
var _default = (0, _utils2.createRule)({
|
|
59
43
|
name: __filename,
|
|
60
44
|
meta: {
|
|
@@ -71,24 +55,19 @@ var _default = (0, _utils2.createRule)({
|
|
|
71
55
|
schema: []
|
|
72
56
|
},
|
|
73
57
|
defaultOptions: [],
|
|
74
|
-
|
|
75
58
|
create(context) {
|
|
76
59
|
return {
|
|
77
60
|
CallExpression(node) {
|
|
78
61
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
79
|
-
|
|
80
62
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect' || jestFnCall.args.length === 0) {
|
|
81
63
|
return;
|
|
82
64
|
}
|
|
83
|
-
|
|
84
65
|
const {
|
|
85
66
|
parent: expect
|
|
86
67
|
} = jestFnCall.head.node;
|
|
87
|
-
|
|
88
68
|
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
89
69
|
return;
|
|
90
70
|
}
|
|
91
|
-
|
|
92
71
|
const {
|
|
93
72
|
arguments: [comparison],
|
|
94
73
|
range: [, expectCallEnd]
|
|
@@ -97,30 +76,29 @@ var _default = (0, _utils2.createRule)({
|
|
|
97
76
|
matcher
|
|
98
77
|
} = jestFnCall;
|
|
99
78
|
const matcherArg = (0, _utils2.getFirstMatcherArg)(jestFnCall);
|
|
100
|
-
|
|
101
79
|
if ((comparison === null || comparison === void 0 ? void 0 : comparison.type) !== _utils.AST_NODE_TYPES.BinaryExpression || isComparingToString(comparison) || !_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || !(0, _utils2.isBooleanLiteral)(matcherArg)) {
|
|
102
80
|
return;
|
|
103
81
|
}
|
|
104
|
-
|
|
105
82
|
const [modifier] = jestFnCall.modifiers;
|
|
106
83
|
const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not');
|
|
107
84
|
const preferredMatcher = determineMatcher(comparison.operator, matcherArg.value === hasNot);
|
|
108
|
-
|
|
109
85
|
if (!preferredMatcher) {
|
|
110
86
|
return;
|
|
111
87
|
}
|
|
112
|
-
|
|
113
88
|
context.report({
|
|
114
89
|
fix(fixer) {
|
|
115
|
-
const sourceCode = context.getSourceCode();
|
|
90
|
+
const sourceCode = context.getSourceCode();
|
|
116
91
|
|
|
92
|
+
// preserve the existing modifier if it's not a negation
|
|
117
93
|
const modifierText = modifier && (0, _utils2.getAccessorValue)(modifier) !== 'not' ? `.${(0, _utils2.getAccessorValue)(modifier)}` : '';
|
|
118
|
-
return [
|
|
119
|
-
|
|
120
|
-
fixer.
|
|
94
|
+
return [
|
|
95
|
+
// replace the comparison argument with the left-hand side of the comparison
|
|
96
|
+
fixer.replaceText(comparison, sourceCode.getText(comparison.left)),
|
|
97
|
+
// replace the current matcher & modifier with the preferred matcher
|
|
98
|
+
fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${preferredMatcher}`),
|
|
99
|
+
// replace the matcher argument with the right-hand side of the comparison
|
|
121
100
|
fixer.replaceText(matcherArg, sourceCode.getText(comparison.right))];
|
|
122
101
|
},
|
|
123
|
-
|
|
124
102
|
messageId: 'useToBeComparison',
|
|
125
103
|
data: {
|
|
126
104
|
preferredMatcher
|
|
@@ -128,10 +106,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
128
106
|
node: matcher
|
|
129
107
|
});
|
|
130
108
|
}
|
|
131
|
-
|
|
132
109
|
};
|
|
133
110
|
}
|
|
134
|
-
|
|
135
111
|
});
|
|
136
|
-
|
|
137
112
|
exports.default = _default;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _utils = require("./utils");
|
|
8
|
+
var _default = (0, _utils.createRule)({
|
|
9
|
+
name: __filename,
|
|
10
|
+
meta: {
|
|
11
|
+
docs: {
|
|
12
|
+
category: 'Best Practices',
|
|
13
|
+
description: 'Prefer using `.each` rather than manual loops',
|
|
14
|
+
recommended: false
|
|
15
|
+
},
|
|
16
|
+
messages: {
|
|
17
|
+
preferEach: 'prefer using `{{ fn }}.each` rather than a manual loop'
|
|
18
|
+
},
|
|
19
|
+
type: 'suggestion',
|
|
20
|
+
schema: []
|
|
21
|
+
},
|
|
22
|
+
defaultOptions: [],
|
|
23
|
+
create(context) {
|
|
24
|
+
const jestFnCalls = [];
|
|
25
|
+
let inTestCaseCall = false;
|
|
26
|
+
const recommendFn = () => {
|
|
27
|
+
if (jestFnCalls.length === 1 && jestFnCalls[0] === 'test') {
|
|
28
|
+
return 'it';
|
|
29
|
+
}
|
|
30
|
+
return 'describe';
|
|
31
|
+
};
|
|
32
|
+
const enterForLoop = () => {
|
|
33
|
+
if (jestFnCalls.length === 0 || inTestCaseCall) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
jestFnCalls.length = 0;
|
|
37
|
+
};
|
|
38
|
+
const exitForLoop = node => {
|
|
39
|
+
if (jestFnCalls.length === 0 || inTestCaseCall) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
context.report({
|
|
43
|
+
node,
|
|
44
|
+
messageId: 'preferEach',
|
|
45
|
+
data: {
|
|
46
|
+
fn: recommendFn()
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
jestFnCalls.length = 0;
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
ForStatement: enterForLoop,
|
|
53
|
+
'ForStatement:exit': exitForLoop,
|
|
54
|
+
ForInStatement: enterForLoop,
|
|
55
|
+
'ForInStatement:exit': exitForLoop,
|
|
56
|
+
ForOfStatement: enterForLoop,
|
|
57
|
+
'ForOfStatement:exit': exitForLoop,
|
|
58
|
+
CallExpression(node) {
|
|
59
|
+
const {
|
|
60
|
+
type: jestFnCallType
|
|
61
|
+
} = (0, _utils.parseJestFnCall)(node, context) ?? {};
|
|
62
|
+
if (jestFnCallType === 'hook' || jestFnCallType === 'describe' || jestFnCallType === 'test') {
|
|
63
|
+
jestFnCalls.push(jestFnCallType);
|
|
64
|
+
}
|
|
65
|
+
if (jestFnCallType === 'test') {
|
|
66
|
+
inTestCaseCall = true;
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
'CallExpression:exit'(node) {
|
|
70
|
+
const {
|
|
71
|
+
type: jestFnCallType
|
|
72
|
+
} = (0, _utils.parseJestFnCall)(node, context) ?? {};
|
|
73
|
+
if (jestFnCallType === 'test') {
|
|
74
|
+
inTestCaseCall = false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
exports.default = _default;
|
|
@@ -4,19 +4,15 @@ 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: {
|
|
15
12
|
docs: {
|
|
16
13
|
category: 'Best Practices',
|
|
17
14
|
description: 'Suggest using the built-in equality matchers',
|
|
18
|
-
recommended: false
|
|
19
|
-
suggestion: true
|
|
15
|
+
recommended: false
|
|
20
16
|
},
|
|
21
17
|
messages: {
|
|
22
18
|
useEqualityMatcher: 'Prefer using one of the equality matchers instead',
|
|
@@ -27,24 +23,19 @@ var _default = (0, _utils2.createRule)({
|
|
|
27
23
|
schema: []
|
|
28
24
|
},
|
|
29
25
|
defaultOptions: [],
|
|
30
|
-
|
|
31
26
|
create(context) {
|
|
32
27
|
return {
|
|
33
28
|
CallExpression(node) {
|
|
34
29
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
35
|
-
|
|
36
30
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect' || jestFnCall.args.length === 0) {
|
|
37
31
|
return;
|
|
38
32
|
}
|
|
39
|
-
|
|
40
33
|
const {
|
|
41
34
|
parent: expect
|
|
42
35
|
} = jestFnCall.head.node;
|
|
43
|
-
|
|
44
36
|
if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
45
37
|
return;
|
|
46
38
|
}
|
|
47
|
-
|
|
48
39
|
const {
|
|
49
40
|
arguments: [comparison],
|
|
50
41
|
range: [, expectCallEnd]
|
|
@@ -53,33 +44,32 @@ var _default = (0, _utils2.createRule)({
|
|
|
53
44
|
matcher
|
|
54
45
|
} = jestFnCall;
|
|
55
46
|
const matcherArg = (0, _utils2.getFirstMatcherArg)(jestFnCall);
|
|
56
|
-
|
|
57
47
|
if ((comparison === null || comparison === void 0 ? void 0 : comparison.type) !== _utils.AST_NODE_TYPES.BinaryExpression || comparison.operator !== '===' && comparison.operator !== '!==' || !_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || !(0, _utils2.isBooleanLiteral)(matcherArg)) {
|
|
58
48
|
return;
|
|
59
49
|
}
|
|
60
|
-
|
|
61
50
|
const matcherValue = matcherArg.value;
|
|
62
51
|
const [modifier] = jestFnCall.modifiers;
|
|
63
|
-
const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not');
|
|
64
|
-
// value is itself negated by the "not" modifier
|
|
52
|
+
const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not');
|
|
65
53
|
|
|
54
|
+
// we need to negate the expectation if the current expected
|
|
55
|
+
// value is itself negated by the "not" modifier
|
|
66
56
|
const addNotModifier = (comparison.operator === '!==' ? !matcherValue : matcherValue) === hasNot;
|
|
67
|
-
|
|
68
57
|
const buildFixer = equalityMatcher => fixer => {
|
|
69
|
-
const sourceCode = context.getSourceCode();
|
|
58
|
+
const sourceCode = context.getSourceCode();
|
|
70
59
|
|
|
60
|
+
// preserve the existing modifier if it's not a negation
|
|
71
61
|
let modifierText = modifier && (0, _utils2.getAccessorValue)(modifier) !== 'not' ? `.${(0, _utils2.getAccessorValue)(modifier)}` : '';
|
|
72
|
-
|
|
73
62
|
if (addNotModifier) {
|
|
74
63
|
modifierText += `.${_utils2.ModifierName.not}`;
|
|
75
64
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
fixer.replaceText(comparison, sourceCode.getText(comparison.left)),
|
|
79
|
-
|
|
65
|
+
return [
|
|
66
|
+
// replace the comparison argument with the left-hand side of the comparison
|
|
67
|
+
fixer.replaceText(comparison, sourceCode.getText(comparison.left)),
|
|
68
|
+
// replace the current matcher & modifier with the preferred matcher
|
|
69
|
+
fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${equalityMatcher}`),
|
|
70
|
+
// replace the matcher argument with the right-hand side of the comparison
|
|
80
71
|
fixer.replaceText(matcherArg, sourceCode.getText(comparison.right))];
|
|
81
72
|
};
|
|
82
|
-
|
|
83
73
|
context.report({
|
|
84
74
|
messageId: 'useEqualityMatcher',
|
|
85
75
|
suggest: ['toBe', 'toEqual', 'toStrictEqual'].map(equalityMatcher => ({
|
|
@@ -92,10 +82,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
92
82
|
node: matcher
|
|
93
83
|
});
|
|
94
84
|
}
|
|
95
|
-
|
|
96
85
|
};
|
|
97
86
|
}
|
|
98
|
-
|
|
99
87
|
});
|
|
100
|
-
|
|
101
88
|
exports.default = _default;
|
|
@@ -4,46 +4,38 @@ 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 isFirstStatement = node => {
|
|
13
10
|
let parent = node;
|
|
14
|
-
|
|
15
11
|
while (parent) {
|
|
16
|
-
var _parent$parent;
|
|
17
|
-
|
|
12
|
+
var _parent$parent, _parent$parent2;
|
|
18
13
|
if (((_parent$parent = parent.parent) === null || _parent$parent === void 0 ? void 0 : _parent$parent.type) === _utils.AST_NODE_TYPES.BlockStatement) {
|
|
19
14
|
return parent.parent.body[0] === parent;
|
|
20
15
|
}
|
|
21
16
|
|
|
17
|
+
// if we've hit an arrow function, then it must have a single expression
|
|
18
|
+
// as its body, as otherwise we would have hit the block statement already
|
|
19
|
+
if (((_parent$parent2 = parent.parent) === null || _parent$parent2 === void 0 ? void 0 : _parent$parent2.type) === _utils.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
22
|
parent = parent.parent;
|
|
23
23
|
}
|
|
24
|
-
/* istanbul ignore next */
|
|
25
|
-
|
|
26
24
|
|
|
25
|
+
/* istanbul ignore next */
|
|
27
26
|
throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
|
|
28
27
|
};
|
|
29
|
-
|
|
30
28
|
const suggestRemovingExtraArguments = (args, extraArgsStartAt) => ({
|
|
31
29
|
messageId: 'suggestRemovingExtraArguments',
|
|
32
30
|
fix: fixer => fixer.removeRange([args[extraArgsStartAt].range[0] - Math.sign(extraArgsStartAt), args[args.length - 1].range[1]])
|
|
33
31
|
});
|
|
34
|
-
|
|
35
|
-
// const suggestions: Array<[MessageIds, string]> = [
|
|
36
|
-
// ['suggestAddingHasAssertions', 'expect.hasAssertions();'],
|
|
37
|
-
// ['suggestAddingAssertions', 'expect.assertions();'],
|
|
38
|
-
// ];
|
|
39
32
|
var _default = (0, _utils2.createRule)({
|
|
40
33
|
name: __filename,
|
|
41
34
|
meta: {
|
|
42
35
|
docs: {
|
|
43
36
|
category: 'Best Practices',
|
|
44
37
|
description: 'Suggest using `expect.assertions()` OR `expect.hasAssertions()`',
|
|
45
|
-
recommended: false
|
|
46
|
-
suggestion: true
|
|
38
|
+
recommended: false
|
|
47
39
|
},
|
|
48
40
|
messages: {
|
|
49
41
|
hasAssertionsTakesNoArguments: '`expect.hasAssertions` expects no arguments',
|
|
@@ -77,7 +69,6 @@ var _default = (0, _utils2.createRule)({
|
|
|
77
69
|
onlyFunctionsWithExpectInLoop: false,
|
|
78
70
|
onlyFunctionsWithExpectInCallback: false
|
|
79
71
|
}],
|
|
80
|
-
|
|
81
72
|
create(context, [options]) {
|
|
82
73
|
let expressionDepth = 0;
|
|
83
74
|
let hasExpectInCallback = false;
|
|
@@ -85,33 +76,27 @@ var _default = (0, _utils2.createRule)({
|
|
|
85
76
|
let hasExpectAssertionsAsFirstStatement = false;
|
|
86
77
|
let inTestCaseCall = false;
|
|
87
78
|
let inForLoop = false;
|
|
88
|
-
|
|
89
79
|
const shouldCheckFunction = testFunction => {
|
|
90
80
|
if (!options.onlyFunctionsWithAsyncKeyword && !options.onlyFunctionsWithExpectInLoop && !options.onlyFunctionsWithExpectInCallback) {
|
|
91
81
|
return true;
|
|
92
82
|
}
|
|
93
|
-
|
|
94
83
|
if (options.onlyFunctionsWithAsyncKeyword) {
|
|
95
84
|
if (testFunction.async) {
|
|
96
85
|
return true;
|
|
97
86
|
}
|
|
98
87
|
}
|
|
99
|
-
|
|
100
88
|
if (options.onlyFunctionsWithExpectInLoop) {
|
|
101
89
|
if (hasExpectInLoop) {
|
|
102
90
|
return true;
|
|
103
91
|
}
|
|
104
92
|
}
|
|
105
|
-
|
|
106
93
|
if (options.onlyFunctionsWithExpectInCallback) {
|
|
107
94
|
if (hasExpectInCallback) {
|
|
108
95
|
return true;
|
|
109
96
|
}
|
|
110
97
|
}
|
|
111
|
-
|
|
112
98
|
return false;
|
|
113
99
|
};
|
|
114
|
-
|
|
115
100
|
const checkExpectHasAssertions = expectFnCall => {
|
|
116
101
|
if ((0, _utils2.getAccessorValue)(expectFnCall.members[0]) === 'hasAssertions') {
|
|
117
102
|
if (expectFnCall.args.length) {
|
|
@@ -121,21 +106,17 @@ var _default = (0, _utils2.createRule)({
|
|
|
121
106
|
suggest: [suggestRemovingExtraArguments(expectFnCall.args, 0)]
|
|
122
107
|
});
|
|
123
108
|
}
|
|
124
|
-
|
|
125
109
|
return;
|
|
126
110
|
}
|
|
127
|
-
|
|
128
111
|
if (expectFnCall.args.length !== 1) {
|
|
129
112
|
let {
|
|
130
113
|
loc
|
|
131
114
|
} = expectFnCall.matcher;
|
|
132
115
|
const suggest = [];
|
|
133
|
-
|
|
134
116
|
if (expectFnCall.args.length) {
|
|
135
117
|
loc = expectFnCall.args[1].loc;
|
|
136
118
|
suggest.push(suggestRemovingExtraArguments(expectFnCall.args, 1));
|
|
137
119
|
}
|
|
138
|
-
|
|
139
120
|
context.report({
|
|
140
121
|
messageId: 'assertionsRequiresOneArgument',
|
|
141
122
|
suggest,
|
|
@@ -143,27 +124,19 @@ var _default = (0, _utils2.createRule)({
|
|
|
143
124
|
});
|
|
144
125
|
return;
|
|
145
126
|
}
|
|
146
|
-
|
|
147
127
|
const [arg] = expectFnCall.args;
|
|
148
|
-
|
|
149
128
|
if (arg.type === _utils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value)) {
|
|
150
129
|
return;
|
|
151
130
|
}
|
|
152
|
-
|
|
153
131
|
context.report({
|
|
154
132
|
messageId: 'assertionsRequiresNumberArgument',
|
|
155
133
|
node: arg
|
|
156
134
|
});
|
|
157
135
|
};
|
|
158
|
-
|
|
159
136
|
const enterExpression = () => inTestCaseCall && expressionDepth++;
|
|
160
|
-
|
|
161
137
|
const exitExpression = () => inTestCaseCall && expressionDepth--;
|
|
162
|
-
|
|
163
138
|
const enterForLoop = () => inForLoop = true;
|
|
164
|
-
|
|
165
139
|
const exitForLoop = () => inForLoop = false;
|
|
166
|
-
|
|
167
140
|
return {
|
|
168
141
|
FunctionExpression: enterExpression,
|
|
169
142
|
'FunctionExpression:exit': exitExpression,
|
|
@@ -175,64 +148,48 @@ var _default = (0, _utils2.createRule)({
|
|
|
175
148
|
'ForInStatement:exit': exitForLoop,
|
|
176
149
|
ForOfStatement: enterForLoop,
|
|
177
150
|
'ForOfStatement:exit': exitForLoop,
|
|
178
|
-
|
|
179
151
|
CallExpression(node) {
|
|
180
152
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
181
|
-
|
|
182
153
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test') {
|
|
183
154
|
inTestCaseCall = true;
|
|
184
155
|
return;
|
|
185
156
|
}
|
|
186
|
-
|
|
187
157
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'expect' && inTestCaseCall) {
|
|
188
158
|
var _jestFnCall$head$node;
|
|
189
|
-
|
|
190
159
|
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
160
|
checkExpectHasAssertions(jestFnCall);
|
|
192
161
|
hasExpectAssertionsAsFirstStatement = true;
|
|
193
162
|
}
|
|
194
|
-
|
|
195
163
|
if (inForLoop) {
|
|
196
164
|
hasExpectInLoop = true;
|
|
197
165
|
}
|
|
198
|
-
|
|
199
166
|
if (expressionDepth > 1) {
|
|
200
167
|
hasExpectInCallback = true;
|
|
201
168
|
}
|
|
202
169
|
}
|
|
203
170
|
},
|
|
204
|
-
|
|
205
171
|
'CallExpression:exit'(node) {
|
|
206
172
|
if (!(0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
|
|
207
173
|
return;
|
|
208
174
|
}
|
|
209
|
-
|
|
210
175
|
inTestCaseCall = false;
|
|
211
|
-
|
|
212
176
|
if (node.arguments.length < 2) {
|
|
213
177
|
return;
|
|
214
178
|
}
|
|
215
|
-
|
|
216
179
|
const [, testFn] = node.arguments;
|
|
217
|
-
|
|
218
180
|
if (!(0, _utils2.isFunction)(testFn) || !shouldCheckFunction(testFn)) {
|
|
219
181
|
return;
|
|
220
182
|
}
|
|
221
|
-
|
|
222
183
|
hasExpectInLoop = false;
|
|
223
184
|
hasExpectInCallback = false;
|
|
224
|
-
|
|
225
185
|
if (hasExpectAssertionsAsFirstStatement) {
|
|
226
186
|
hasExpectAssertionsAsFirstStatement = false;
|
|
227
187
|
return;
|
|
228
188
|
}
|
|
229
|
-
|
|
230
189
|
const suggestions = [];
|
|
231
|
-
|
|
232
190
|
if (testFn.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
|
|
233
191
|
suggestions.push(['suggestAddingHasAssertions', 'expect.hasAssertions();'], ['suggestAddingAssertions', 'expect.assertions();']);
|
|
234
192
|
}
|
|
235
|
-
|
|
236
193
|
context.report({
|
|
237
194
|
messageId: 'haveExpectAssertions',
|
|
238
195
|
node,
|
|
@@ -242,10 +199,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
242
199
|
}))
|
|
243
200
|
});
|
|
244
201
|
}
|
|
245
|
-
|
|
246
202
|
};
|
|
247
203
|
}
|
|
248
|
-
|
|
249
204
|
});
|
|
250
|
-
|
|
251
205
|
exports.default = _default;
|