eslint-plugin-jest 26.1.1 → 26.5.3
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 +50 -2
- package/docs/rules/no-conditional-expect.md +1 -1
- package/docs/rules/no-deprecated-functions.md +1 -2
- package/docs/rules/no-identical-title.md +1 -1
- package/docs/rules/no-jasmine-globals.md +2 -2
- package/docs/rules/no-jest-import.md +1 -1
- package/docs/rules/no-large-snapshots.md +2 -2
- package/docs/rules/no-standalone-expect.md +1 -1
- package/docs/rules/prefer-comparison-matcher.md +1 -1
- package/docs/rules/prefer-equality-matcher.md +1 -1
- package/docs/rules/prefer-expect-assertions.md +1 -1
- package/docs/rules/prefer-hooks-in-order.md +133 -0
- package/docs/rules/prefer-hooks-on-top.md +1 -1
- package/docs/rules/prefer-lowercase-title.md +2 -2
- package/docs/rules/valid-expect.md +2 -2
- package/lib/rules/consistent-test-it.js +9 -8
- package/lib/rules/expect-expect.js +4 -4
- package/lib/rules/max-nested-describe.js +2 -2
- package/lib/rules/no-alias-methods.js +1 -1
- package/lib/rules/no-conditional-expect.js +3 -3
- package/lib/rules/no-conditional-in-test.js +2 -2
- package/lib/rules/no-deprecated-functions.js +1 -3
- package/lib/rules/no-disabled-tests.js +36 -61
- package/lib/rules/no-done-callback.js +6 -4
- package/lib/rules/no-duplicate-hooks.js +23 -23
- package/lib/rules/no-export.js +1 -1
- package/lib/rules/no-focused-tests.js +40 -43
- package/lib/rules/no-hooks.js +4 -2
- package/lib/rules/no-identical-title.js +10 -7
- package/lib/rules/no-if.js +6 -4
- package/lib/rules/no-restricted-matchers.js +39 -43
- package/lib/rules/no-standalone-expect.js +5 -5
- package/lib/rules/no-test-prefixes.js +12 -20
- package/lib/rules/no-test-return-statement.js +5 -2
- package/lib/rules/prefer-called-with.js +14 -13
- package/lib/rules/prefer-comparison-matcher.js +9 -4
- package/lib/rules/prefer-equality-matcher.js +15 -5
- package/lib/rules/prefer-expect-assertions.js +4 -2
- package/lib/rules/prefer-hooks-in-order.js +84 -0
- package/lib/rules/prefer-hooks-on-top.js +2 -2
- package/lib/rules/prefer-lowercase-title.js +12 -22
- package/lib/rules/prefer-snapshot-hint.js +34 -3
- package/lib/rules/prefer-strict-equal.js +1 -1
- package/lib/rules/prefer-to-be.js +1 -1
- package/lib/rules/prefer-todo.js +22 -7
- package/lib/rules/require-hook.js +7 -7
- package/lib/rules/require-top-level-describe.js +10 -4
- package/lib/rules/utils/accessors.js +135 -0
- package/lib/rules/{detectJestVersion.js → utils/detectJestVersion.js} +0 -0
- package/lib/rules/utils/followTypeAssertionChain.js +14 -0
- package/lib/rules/utils/index.js +83 -0
- package/lib/rules/utils/misc.js +120 -0
- package/lib/rules/utils/parseExpectCall.js +145 -0
- package/lib/rules/utils/parseJestFnCall.js +323 -0
- package/lib/rules/valid-describe-callback.js +4 -2
- package/lib/rules/valid-expect-in-promise.js +13 -15
- package/lib/rules/valid-title.js +8 -6
- package/package.json +9 -12
- package/lib/rules/utils.js +0 -513
|
@@ -9,16 +9,18 @@ var _utils = require("@typescript-eslint/utils");
|
|
|
9
9
|
|
|
10
10
|
var _utils2 = require("./utils");
|
|
11
11
|
|
|
12
|
-
const findCallbackArg = (node, isJestEach) => {
|
|
12
|
+
const findCallbackArg = (node, isJestEach, context) => {
|
|
13
13
|
if (isJestEach) {
|
|
14
14
|
return node.arguments[1];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
18
|
+
|
|
19
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'hook' && node.arguments.length >= 1) {
|
|
18
20
|
return node.arguments[0];
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
if ((0
|
|
23
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test' && node.arguments.length >= 2) {
|
|
22
24
|
return node.arguments[1];
|
|
23
25
|
}
|
|
24
26
|
|
|
@@ -60,7 +62,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
60
62
|
return;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
const callback = findCallbackArg(node, isJestEach);
|
|
65
|
+
const callback = findCallbackArg(node, isJestEach, context);
|
|
64
66
|
const callbackArgIndex = Number(isJestEach);
|
|
65
67
|
|
|
66
68
|
if (!callback || !(0, _utils2.isFunction)(callback) || callback.params.length !== 1 + callbackArgIndex) {
|
|
@@ -7,13 +7,6 @@ exports.default = void 0;
|
|
|
7
7
|
|
|
8
8
|
var _utils = require("./utils");
|
|
9
9
|
|
|
10
|
-
const newHookContext = () => ({
|
|
11
|
-
beforeAll: 0,
|
|
12
|
-
beforeEach: 0,
|
|
13
|
-
afterAll: 0,
|
|
14
|
-
afterEach: 0
|
|
15
|
-
});
|
|
16
|
-
|
|
17
10
|
var _default = (0, _utils.createRule)({
|
|
18
11
|
name: __filename,
|
|
19
12
|
meta: {
|
|
@@ -31,31 +24,38 @@ var _default = (0, _utils.createRule)({
|
|
|
31
24
|
defaultOptions: [],
|
|
32
25
|
|
|
33
26
|
create(context) {
|
|
34
|
-
const hookContexts = [
|
|
27
|
+
const hookContexts = [{}];
|
|
35
28
|
return {
|
|
36
29
|
CallExpression(node) {
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
var _jestFnCall$name;
|
|
31
|
+
|
|
32
|
+
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
33
|
+
|
|
34
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'describe') {
|
|
35
|
+
hookContexts.push({});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'hook') {
|
|
39
|
+
return;
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
const currentLayer = hookContexts[hookContexts.length - 1];
|
|
43
|
+
currentLayer[_jestFnCall$name = jestFnCall.name] || (currentLayer[_jestFnCall$name] = 0);
|
|
44
|
+
currentLayer[jestFnCall.name] += 1;
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
46
|
+
if (currentLayer[jestFnCall.name] > 1) {
|
|
47
|
+
context.report({
|
|
48
|
+
messageId: 'noDuplicateHook',
|
|
49
|
+
data: {
|
|
50
|
+
hook: jestFnCall.name
|
|
51
|
+
},
|
|
52
|
+
node
|
|
53
|
+
});
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
|
|
57
57
|
'CallExpression:exit'(node) {
|
|
58
|
-
if ((0, _utils.
|
|
58
|
+
if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe'])) {
|
|
59
59
|
hookContexts.pop();
|
|
60
60
|
}
|
|
61
61
|
}
|
package/lib/rules/no-export.js
CHANGED
|
@@ -9,24 +9,6 @@ var _utils = require("@typescript-eslint/utils");
|
|
|
9
9
|
|
|
10
10
|
var _utils2 = require("./utils");
|
|
11
11
|
|
|
12
|
-
const findOnlyNode = node => {
|
|
13
|
-
const callee = node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression ? node.callee.tag : node.callee.type === _utils.AST_NODE_TYPES.CallExpression ? node.callee.callee : node.callee;
|
|
14
|
-
|
|
15
|
-
if (callee.type === _utils.AST_NODE_TYPES.MemberExpression) {
|
|
16
|
-
if (callee.object.type === _utils.AST_NODE_TYPES.MemberExpression) {
|
|
17
|
-
if ((0, _utils2.isSupportedAccessor)(callee.object.property, 'only')) {
|
|
18
|
-
return callee.object.property;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if ((0, _utils2.isSupportedAccessor)(callee.property, 'only')) {
|
|
23
|
-
return callee.property;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return null;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
12
|
var _default = (0, _utils2.createRule)({
|
|
31
13
|
name: __filename,
|
|
32
14
|
meta: {
|
|
@@ -45,41 +27,56 @@ var _default = (0, _utils2.createRule)({
|
|
|
45
27
|
hasSuggestions: true
|
|
46
28
|
},
|
|
47
29
|
defaultOptions: [],
|
|
48
|
-
create: context => ({
|
|
49
|
-
CallExpression(node) {
|
|
50
|
-
if (!(0, _utils2.isDescribeCall)(node) && !(0, _utils2.isTestCaseCall)(node)) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
30
|
|
|
54
|
-
|
|
31
|
+
create(context) {
|
|
32
|
+
return {
|
|
33
|
+
CallExpression(node) {
|
|
34
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
35
|
+
|
|
36
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'test' && (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe') {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (jestFnCall.name.startsWith('f')) {
|
|
41
|
+
context.report({
|
|
42
|
+
messageId: 'focusedTest',
|
|
43
|
+
node,
|
|
44
|
+
suggest: [{
|
|
45
|
+
messageId: 'suggestRemoveFocus',
|
|
46
|
+
|
|
47
|
+
fix(fixer) {
|
|
48
|
+
// don't apply the fixer if we're an aliased import
|
|
49
|
+
if (jestFnCall.head.type === 'import' && jestFnCall.name !== jestFnCall.head.local) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return fixer.removeRange([node.range[0], node.range[0] + 1]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
}]
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const onlyNode = jestFnCall.members.find(s => (0, _utils2.getAccessorValue)(s) === 'only');
|
|
62
|
+
|
|
63
|
+
if (!onlyNode) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
55
67
|
context.report({
|
|
56
68
|
messageId: 'focusedTest',
|
|
57
|
-
node,
|
|
69
|
+
node: onlyNode,
|
|
58
70
|
suggest: [{
|
|
59
71
|
messageId: 'suggestRemoveFocus',
|
|
60
|
-
fix: fixer => fixer.removeRange([
|
|
72
|
+
fix: fixer => fixer.removeRange([onlyNode.range[0] - 1, onlyNode.range[1] + Number(onlyNode.type !== _utils.AST_NODE_TYPES.Identifier)])
|
|
61
73
|
}]
|
|
62
74
|
});
|
|
63
|
-
return;
|
|
64
75
|
}
|
|
65
76
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (!onlyNode) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
71
79
|
|
|
72
|
-
context.report({
|
|
73
|
-
messageId: 'focusedTest',
|
|
74
|
-
node: onlyNode,
|
|
75
|
-
suggest: [{
|
|
76
|
-
messageId: 'suggestRemoveFocus',
|
|
77
|
-
fix: fixer => fixer.removeRange([onlyNode.range[0] - 1, onlyNode.range[1] + Number(onlyNode.type !== _utils.AST_NODE_TYPES.Identifier)])
|
|
78
|
-
}]
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
})
|
|
83
80
|
});
|
|
84
81
|
|
|
85
82
|
exports.default = _default;
|
package/lib/rules/no-hooks.js
CHANGED
|
@@ -39,12 +39,14 @@ var _default = (0, _utils.createRule)({
|
|
|
39
39
|
}]) {
|
|
40
40
|
return {
|
|
41
41
|
CallExpression(node) {
|
|
42
|
-
|
|
42
|
+
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
43
|
+
|
|
44
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'hook' && !allow.includes(jestFnCall.name)) {
|
|
43
45
|
context.report({
|
|
44
46
|
node,
|
|
45
47
|
messageId: 'unexpectedHook',
|
|
46
48
|
data: {
|
|
47
|
-
hookName:
|
|
49
|
+
hookName: jestFnCall.name
|
|
48
50
|
}
|
|
49
51
|
});
|
|
50
52
|
}
|
|
@@ -33,15 +33,18 @@ var _default = (0, _utils.createRule)({
|
|
|
33
33
|
const contexts = [newDescribeContext()];
|
|
34
34
|
return {
|
|
35
35
|
CallExpression(node) {
|
|
36
|
-
var _getNodeName;
|
|
37
|
-
|
|
38
36
|
const currentLayer = contexts[contexts.length - 1];
|
|
37
|
+
const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
|
|
38
|
+
|
|
39
|
+
if (!jestFnCall) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
39
42
|
|
|
40
|
-
if (
|
|
43
|
+
if (jestFnCall.type === 'describe') {
|
|
41
44
|
contexts.push(newDescribeContext());
|
|
42
45
|
}
|
|
43
46
|
|
|
44
|
-
if ((
|
|
47
|
+
if (jestFnCall.members.find(s => (0, _utils.isSupportedAccessor)(s, 'each'))) {
|
|
45
48
|
return;
|
|
46
49
|
}
|
|
47
50
|
|
|
@@ -53,7 +56,7 @@ var _default = (0, _utils.createRule)({
|
|
|
53
56
|
|
|
54
57
|
const title = (0, _utils.getStringValue)(argument);
|
|
55
58
|
|
|
56
|
-
if (
|
|
59
|
+
if (jestFnCall.type === 'test') {
|
|
57
60
|
if (currentLayer.testTitles.includes(title)) {
|
|
58
61
|
context.report({
|
|
59
62
|
messageId: 'multipleTestTitle',
|
|
@@ -64,7 +67,7 @@ var _default = (0, _utils.createRule)({
|
|
|
64
67
|
currentLayer.testTitles.push(title);
|
|
65
68
|
}
|
|
66
69
|
|
|
67
|
-
if (
|
|
70
|
+
if (jestFnCall.type !== 'describe') {
|
|
68
71
|
return;
|
|
69
72
|
}
|
|
70
73
|
|
|
@@ -79,7 +82,7 @@ var _default = (0, _utils.createRule)({
|
|
|
79
82
|
},
|
|
80
83
|
|
|
81
84
|
'CallExpression:exit'(node) {
|
|
82
|
-
if ((0, _utils.
|
|
85
|
+
if ((0, _utils.isTypeOfJestFnCall)(node, context, ['describe'])) {
|
|
83
86
|
contexts.pop();
|
|
84
87
|
}
|
|
85
88
|
}
|
package/lib/rules/no-if.js
CHANGED
|
@@ -9,7 +9,7 @@ var _utils = require("@typescript-eslint/utils");
|
|
|
9
9
|
|
|
10
10
|
var _utils2 = require("./utils");
|
|
11
11
|
|
|
12
|
-
const testCaseNames = new Set([...Object.keys(_utils2.TestCaseName), 'it.only', 'it.
|
|
12
|
+
const testCaseNames = new Set([...Object.keys(_utils2.TestCaseName), 'it.only', 'it.only', 'it.skip', 'it.skip', 'test.only', 'test.only', 'test.skip', 'test.skip', 'fit.concurrent']);
|
|
13
13
|
|
|
14
14
|
const isTestFunctionExpression = node => node.parent !== undefined && node.parent.type === _utils.AST_NODE_TYPES.CallExpression && testCaseNames.has((0, _utils2.getNodeName)(node.parent.callee));
|
|
15
15
|
|
|
@@ -58,10 +58,12 @@ var _default = (0, _utils2.createRule)({
|
|
|
58
58
|
|
|
59
59
|
return {
|
|
60
60
|
CallExpression(node) {
|
|
61
|
-
|
|
61
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
62
|
+
|
|
63
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test') {
|
|
62
64
|
stack.push(true);
|
|
63
65
|
|
|
64
|
-
if ((0, _utils2.
|
|
66
|
+
if (jestFnCall.members.some(s => (0, _utils2.getAccessorValue)(s) === 'each')) {
|
|
65
67
|
stack.push(true);
|
|
66
68
|
}
|
|
67
69
|
}
|
|
@@ -73,7 +75,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
73
75
|
|
|
74
76
|
FunctionDeclaration(node) {
|
|
75
77
|
const declaredVariables = context.getDeclaredVariables(node);
|
|
76
|
-
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables);
|
|
78
|
+
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables, context);
|
|
77
79
|
stack.push(testCallExpressions.length > 0);
|
|
78
80
|
},
|
|
79
81
|
|
|
@@ -30,6 +30,23 @@ var _default = (0, _utils.createRule)({
|
|
|
30
30
|
defaultOptions: [{}],
|
|
31
31
|
|
|
32
32
|
create(context, [restrictedChains]) {
|
|
33
|
+
const reportIfRestricted = (loc, chain) => {
|
|
34
|
+
if (!(chain in restrictedChains)) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const message = restrictedChains[chain];
|
|
39
|
+
context.report({
|
|
40
|
+
messageId: message ? 'restrictedChainWithMessage' : 'restrictedChain',
|
|
41
|
+
data: {
|
|
42
|
+
message,
|
|
43
|
+
chain
|
|
44
|
+
},
|
|
45
|
+
loc
|
|
46
|
+
});
|
|
47
|
+
return true;
|
|
48
|
+
};
|
|
49
|
+
|
|
33
50
|
return {
|
|
34
51
|
CallExpression(node) {
|
|
35
52
|
if (!(0, _utils.isExpectCall)(node)) {
|
|
@@ -41,58 +58,37 @@ var _default = (0, _utils.createRule)({
|
|
|
41
58
|
modifier
|
|
42
59
|
} = (0, _utils.parseExpectCall)(node);
|
|
43
60
|
|
|
44
|
-
if (matcher) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (chain in restrictedChains) {
|
|
48
|
-
const message = restrictedChains[chain];
|
|
49
|
-
context.report({
|
|
50
|
-
messageId: message ? 'restrictedChainWithMessage' : 'restrictedChain',
|
|
51
|
-
data: {
|
|
52
|
-
message,
|
|
53
|
-
chain
|
|
54
|
-
},
|
|
55
|
-
node: matcher.node.property
|
|
56
|
-
});
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
61
|
+
if (matcher && reportIfRestricted(matcher.node.property.loc, matcher.name)) {
|
|
62
|
+
return;
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
if (modifier) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (chain in restrictedChains) {
|
|
65
|
-
const message = restrictedChains[chain];
|
|
66
|
-
context.report({
|
|
67
|
-
messageId: message ? 'restrictedChainWithMessage' : 'restrictedChain',
|
|
68
|
-
data: {
|
|
69
|
-
message,
|
|
70
|
-
chain
|
|
71
|
-
},
|
|
72
|
-
node: modifier.node.property
|
|
73
|
-
});
|
|
66
|
+
if (reportIfRestricted(modifier.node.property.loc, modifier.name)) {
|
|
74
67
|
return;
|
|
75
68
|
}
|
|
69
|
+
|
|
70
|
+
if (modifier.negation) {
|
|
71
|
+
if (reportIfRestricted(modifier.negation.property.loc, 'not') || reportIfRestricted({
|
|
72
|
+
start: modifier.node.property.loc.start,
|
|
73
|
+
end: modifier.negation.property.loc.end
|
|
74
|
+
}, `${modifier.name}.not`)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
if (matcher && modifier) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
context.report({
|
|
84
|
-
messageId: message ? 'restrictedChainWithMessage' : 'restrictedChain',
|
|
85
|
-
data: {
|
|
86
|
-
message,
|
|
87
|
-
chain
|
|
88
|
-
},
|
|
89
|
-
loc: {
|
|
90
|
-
start: modifier.node.property.loc.start,
|
|
91
|
-
end: matcher.node.property.loc.end
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
return;
|
|
81
|
+
let chain = modifier.name;
|
|
82
|
+
|
|
83
|
+
if (modifier.negation) {
|
|
84
|
+
chain += '.not';
|
|
95
85
|
}
|
|
86
|
+
|
|
87
|
+
chain += `.${matcher.name}`;
|
|
88
|
+
reportIfRestricted({
|
|
89
|
+
start: modifier.node.property.loc.start,
|
|
90
|
+
end: matcher.node.property.loc.end
|
|
91
|
+
}, chain);
|
|
96
92
|
}
|
|
97
93
|
}
|
|
98
94
|
|
|
@@ -9,7 +9,7 @@ var _utils = require("@typescript-eslint/utils");
|
|
|
9
9
|
|
|
10
10
|
var _utils2 = require("./utils");
|
|
11
11
|
|
|
12
|
-
const getBlockType = statement => {
|
|
12
|
+
const getBlockType = (statement, context) => {
|
|
13
13
|
const func = statement.parent;
|
|
14
14
|
/* istanbul ignore if */
|
|
15
15
|
|
|
@@ -30,7 +30,7 @@ const getBlockType = statement => {
|
|
|
30
30
|
} // if it's not a variable, it will be callExpr, we only care about describe
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
if (expr.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.
|
|
33
|
+
if (expr.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTypeOfJestFnCall)(expr, context, ['describe'])) {
|
|
34
34
|
return 'describe';
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -73,7 +73,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
73
73
|
|
|
74
74
|
const isCustomTestBlockFunction = node => additionalTestBlockFunctions.includes((0, _utils2.getNodeName)(node) || '');
|
|
75
75
|
|
|
76
|
-
const isTestBlock = node => (0, _utils2.
|
|
76
|
+
const isTestBlock = node => (0, _utils2.isTypeOfJestFnCall)(node, context, ['test']) || isCustomTestBlockFunction(node);
|
|
77
77
|
|
|
78
78
|
return {
|
|
79
79
|
CallExpression(node) {
|
|
@@ -108,7 +108,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
108
108
|
},
|
|
109
109
|
|
|
110
110
|
BlockStatement(statement) {
|
|
111
|
-
const blockType = getBlockType(statement);
|
|
111
|
+
const blockType = getBlockType(statement, context);
|
|
112
112
|
|
|
113
113
|
if (blockType) {
|
|
114
114
|
callStack.push(blockType);
|
|
@@ -116,7 +116,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
116
116
|
},
|
|
117
117
|
|
|
118
118
|
'BlockStatement:exit'(statement) {
|
|
119
|
-
if (callStack[callStack.length - 1] === getBlockType(statement)) {
|
|
119
|
+
if (callStack[callStack.length - 1] === getBlockType(statement, context)) {
|
|
120
120
|
callStack.pop();
|
|
121
121
|
}
|
|
122
122
|
},
|
|
@@ -29,10 +29,17 @@ var _default = (0, _utils2.createRule)({
|
|
|
29
29
|
create(context) {
|
|
30
30
|
return {
|
|
31
31
|
CallExpression(node) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
33
|
+
|
|
34
|
+
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe' && (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'test') {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (jestFnCall.name[0] !== 'f' && jestFnCall.name[0] !== 'x') {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const preferredNodeName = [jestFnCall.name.slice(1), jestFnCall.name[0] === 'f' ? 'only' : 'skip', ...jestFnCall.members.map(s => (0, _utils2.getAccessorValue)(s))].join('.');
|
|
36
43
|
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;
|
|
37
44
|
context.report({
|
|
38
45
|
messageId: 'usePreferredName',
|
|
@@ -53,19 +60,4 @@ var _default = (0, _utils2.createRule)({
|
|
|
53
60
|
|
|
54
61
|
});
|
|
55
62
|
|
|
56
|
-
exports.default = _default;
|
|
57
|
-
|
|
58
|
-
function getPreferredNodeName(nodeName) {
|
|
59
|
-
const firstChar = nodeName.charAt(0);
|
|
60
|
-
const suffix = nodeName.endsWith('.each') ? '.each' : '';
|
|
61
|
-
|
|
62
|
-
if (firstChar === 'f') {
|
|
63
|
-
return `${nodeName.slice(1).replace('.each', '')}.only${suffix}`;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (firstChar === 'x') {
|
|
67
|
-
return `${nodeName.slice(1).replace('.each', '')}.skip${suffix}`;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
63
|
+
exports.default = _default;
|
|
@@ -38,7 +38,10 @@ var _default = (0, _utils2.createRule)({
|
|
|
38
38
|
create(context) {
|
|
39
39
|
return {
|
|
40
40
|
CallExpression(node) {
|
|
41
|
-
if (!(0, _utils2.
|
|
41
|
+
if (!(0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
42
45
|
const body = getBody(node.arguments);
|
|
43
46
|
const returnStmt = body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement);
|
|
44
47
|
if (!returnStmt) return;
|
|
@@ -50,7 +53,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
50
53
|
|
|
51
54
|
FunctionDeclaration(node) {
|
|
52
55
|
const declaredVariables = context.getDeclaredVariables(node);
|
|
53
|
-
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables);
|
|
56
|
+
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables, context);
|
|
54
57
|
if (testCallExpressions.length === 0) return;
|
|
55
58
|
const returnStmt = node.body.body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement);
|
|
56
59
|
if (!returnStmt) return;
|
|
@@ -33,19 +33,20 @@ var _default = (0, _utils.createRule)({
|
|
|
33
33
|
const {
|
|
34
34
|
modifier,
|
|
35
35
|
matcher
|
|
36
|
-
} = (0, _utils.parseExpectCall)(node);
|
|
37
|
-
|
|
38
|
-
if (matcher &&
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
36
|
+
} = (0, _utils.parseExpectCall)(node);
|
|
37
|
+
|
|
38
|
+
if (!matcher || (modifier === null || modifier === void 0 ? void 0 : modifier.name) === _utils.ModifierName.not || modifier !== null && modifier !== void 0 && modifier.negation) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (['toBeCalled', 'toHaveBeenCalled'].includes(matcher.name)) {
|
|
43
|
+
context.report({
|
|
44
|
+
data: {
|
|
45
|
+
name: matcher.name
|
|
46
|
+
},
|
|
47
|
+
messageId: 'preferCalledWith',
|
|
48
|
+
node: matcher.node.property
|
|
49
|
+
});
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
@@ -108,7 +108,10 @@ var _default = (0, _utils2.createRule)({
|
|
|
108
108
|
return;
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
const
|
|
111
|
+
const negation = modifier !== null && modifier !== void 0 && modifier.negation ? {
|
|
112
|
+
node: modifier.negation
|
|
113
|
+
} : (modifier === null || modifier === void 0 ? void 0 : modifier.name) === _utils2.ModifierName.not ? modifier : null;
|
|
114
|
+
const preferredMatcher = determineMatcher(comparison.operator, (0, _utils2.followTypeAssertionChain)(matcher.arguments[0]).value === !!negation);
|
|
112
115
|
|
|
113
116
|
if (!preferredMatcher) {
|
|
114
117
|
return;
|
|
@@ -116,10 +119,12 @@ var _default = (0, _utils2.createRule)({
|
|
|
116
119
|
|
|
117
120
|
context.report({
|
|
118
121
|
fix(fixer) {
|
|
119
|
-
const sourceCode = context.getSourceCode();
|
|
122
|
+
const sourceCode = context.getSourceCode(); // preserve the existing modifier if it's not a negation
|
|
123
|
+
|
|
124
|
+
const modifierText = modifier && (modifier === null || modifier === void 0 ? void 0 : modifier.node) !== (negation === null || negation === void 0 ? void 0 : negation.node) ? `.${modifier.name}` : '';
|
|
120
125
|
return [// replace the comparison argument with the left-hand side of the comparison
|
|
121
126
|
fixer.replaceText(comparison, sourceCode.getText(comparison.left)), // replace the current matcher & modifier with the preferred matcher
|
|
122
|
-
fixer.replaceTextRange([expectCallEnd, matcher.node.range[1]],
|
|
127
|
+
fixer.replaceTextRange([expectCallEnd, matcher.node.range[1]], `${modifierText}.${preferredMatcher}`), // replace the matcher argument with the right-hand side of the comparison
|
|
123
128
|
fixer.replaceText(matcher.arguments[0], sourceCode.getText(comparison.right))];
|
|
124
129
|
},
|
|
125
130
|
|
|
@@ -127,7 +132,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
127
132
|
data: {
|
|
128
133
|
preferredMatcher
|
|
129
134
|
},
|
|
130
|
-
node: (
|
|
135
|
+
node: (negation || matcher).node.property
|
|
131
136
|
});
|
|
132
137
|
}
|
|
133
138
|
|
|
@@ -64,16 +64,26 @@ var _default = (0, _utils2.createRule)({
|
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
const matcherValue = (0, _utils2.followTypeAssertionChain)(matcher.arguments[0]).value;
|
|
67
|
+
const matcherValue = (0, _utils2.followTypeAssertionChain)(matcher.arguments[0]).value;
|
|
68
|
+
const negation = modifier !== null && modifier !== void 0 && modifier.negation ? {
|
|
69
|
+
node: modifier.negation
|
|
70
|
+
} : (modifier === null || modifier === void 0 ? void 0 : modifier.name) === _utils2.ModifierName.not ? modifier : null; // we need to negate the expectation if the current expected
|
|
68
71
|
// value is itself negated by the "not" modifier
|
|
69
72
|
|
|
70
|
-
const addNotModifier = (comparison.operator === '!==' ? !matcherValue : matcherValue) === !!
|
|
73
|
+
const addNotModifier = (comparison.operator === '!==' ? !matcherValue : matcherValue) === !!negation;
|
|
71
74
|
|
|
72
75
|
const buildFixer = equalityMatcher => fixer => {
|
|
73
|
-
const sourceCode = context.getSourceCode();
|
|
76
|
+
const sourceCode = context.getSourceCode(); // preserve the existing modifier if it's not a negation
|
|
77
|
+
|
|
78
|
+
let modifierText = modifier && (modifier === null || modifier === void 0 ? void 0 : modifier.node) !== (negation === null || negation === void 0 ? void 0 : negation.node) ? `.${modifier.name}` : '';
|
|
79
|
+
|
|
80
|
+
if (addNotModifier) {
|
|
81
|
+
modifierText += `.${_utils2.ModifierName.not}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
74
84
|
return [// replace the comparison argument with the left-hand side of the comparison
|
|
75
85
|
fixer.replaceText(comparison, sourceCode.getText(comparison.left)), // replace the current matcher & modifier with the preferred matcher
|
|
76
|
-
fixer.replaceTextRange([expectCallEnd, matcher.node.range[1]],
|
|
86
|
+
fixer.replaceTextRange([expectCallEnd, matcher.node.range[1]], `${modifierText}.${equalityMatcher}`), // replace the matcher argument with the right-hand side of the comparison
|
|
77
87
|
fixer.replaceText(matcher.arguments[0], sourceCode.getText(comparison.right))];
|
|
78
88
|
};
|
|
79
89
|
|
|
@@ -86,7 +96,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
86
96
|
},
|
|
87
97
|
fix: buildFixer(equalityMatcher)
|
|
88
98
|
})),
|
|
89
|
-
node: (
|
|
99
|
+
node: (negation || matcher).node.property
|
|
90
100
|
});
|
|
91
101
|
}
|
|
92
102
|
|
|
@@ -116,7 +116,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
116
116
|
'ForOfStatement:exit': exitForLoop,
|
|
117
117
|
|
|
118
118
|
CallExpression(node) {
|
|
119
|
-
if ((0, _utils2.
|
|
119
|
+
if ((0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
|
|
120
120
|
inTestCaseCall = true;
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
@@ -133,10 +133,12 @@ var _default = (0, _utils2.createRule)({
|
|
|
133
133
|
},
|
|
134
134
|
|
|
135
135
|
'CallExpression:exit'(node) {
|
|
136
|
-
if (!(0, _utils2.
|
|
136
|
+
if (!(0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
inTestCaseCall = false;
|
|
141
|
+
|
|
140
142
|
if (node.arguments.length < 2) {
|
|
141
143
|
return;
|
|
142
144
|
}
|