eslint-plugin-jest 26.1.4 → 26.2.1
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 +30 -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-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 +5 -4
- package/lib/rules/expect-expect.js +2 -2
- package/lib/rules/max-nested-describe.js +2 -2
- package/lib/rules/no-conditional-expect.js +3 -3
- package/lib/rules/no-conditional-in-test.js +2 -2
- package/lib/rules/no-done-callback.js +4 -4
- package/lib/rules/no-duplicate-hooks.js +5 -3
- package/lib/rules/no-export.js +1 -1
- package/lib/rules/no-focused-tests.js +31 -25
- package/lib/rules/no-hooks.js +1 -1
- package/lib/rules/no-identical-title.js +5 -4
- package/lib/rules/no-if.js +2 -2
- package/lib/rules/no-standalone-expect.js +5 -5
- package/lib/rules/no-test-prefixes.js +2 -1
- package/lib/rules/no-test-return-statement.js +2 -2
- package/lib/rules/prefer-expect-assertions.js +4 -2
- package/lib/rules/prefer-hooks-on-top.js +4 -2
- package/lib/rules/prefer-lowercase-title.js +7 -5
- package/lib/rules/prefer-snapshot-hint.js +6 -2
- package/lib/rules/prefer-todo.js +2 -2
- package/lib/rules/require-hook.js +7 -7
- package/lib/rules/require-top-level-describe.js +6 -4
- package/lib/rules/utils.js +187 -50
- package/lib/rules/valid-describe-callback.js +1 -1
- package/lib/rules/valid-expect-in-promise.js +7 -7
- package/lib/rules/valid-title.js +5 -3
- package/package.json +5 -8
package/README.md
CHANGED
|
@@ -59,6 +59,34 @@ doing:
|
|
|
59
59
|
This is included in all configs shared by this plugin, so can be omitted if
|
|
60
60
|
extending them.
|
|
61
61
|
|
|
62
|
+
### Running rules only on test-related files
|
|
63
|
+
|
|
64
|
+
The rules provided by this plugin assume that the files they are checking are
|
|
65
|
+
test-related. This means it's generally not suitable to include them in your
|
|
66
|
+
top-level configuration as that applies to all files being linted which can
|
|
67
|
+
include source files.
|
|
68
|
+
|
|
69
|
+
You can use
|
|
70
|
+
[overrides](https://eslint.org/docs/user-guide/configuring/configuration-files#how-do-overrides-work)
|
|
71
|
+
to have ESLint apply additional rules to specific files:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"extends": ["eslint:recommended"],
|
|
76
|
+
"overrides": [
|
|
77
|
+
{
|
|
78
|
+
"files": ["test/**"],
|
|
79
|
+
"plugins": ["jest"],
|
|
80
|
+
"extends": ["plugin:jest/recommended"],
|
|
81
|
+
"rules": { "jest/prefer-expect-assertions": "off" }
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"rules": {
|
|
85
|
+
"indent": ["error", 2]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
62
90
|
### Jest `version` setting
|
|
63
91
|
|
|
64
92
|
The behaviour of some rules (specifically [`no-deprecated-functions`][]) change
|
|
@@ -211,8 +239,8 @@ adjust your eslint config as outlined
|
|
|
211
239
|
|
|
212
240
|
Note that unlike the type-checking rules in `@typescript-eslint/eslint-plugin`,
|
|
213
241
|
the rules here will fallback to doing nothing if type information is not
|
|
214
|
-
available, meaning
|
|
215
|
-
on JavaScript and TypeScript projects.
|
|
242
|
+
available, meaning it's safe to include them in shared configs that could be
|
|
243
|
+
used on JavaScript and TypeScript projects.
|
|
216
244
|
|
|
217
245
|
Also note that `unbound-method` depends on `@typescript-eslint/eslint-plugin`,
|
|
218
246
|
as it extends the original `unbound-method` rule from that plugin.
|
|
@@ -107,7 +107,7 @@ While you can use `expect.assertions` & `expect.hasAssertions` for these
|
|
|
107
107
|
situations, they only work with `expect`.
|
|
108
108
|
|
|
109
109
|
A better way to handle this situation is to introduce a wrapper to handle the
|
|
110
|
-
catching, and otherwise
|
|
110
|
+
catching, and otherwise return a specific "no error thrown" error if nothing is
|
|
111
111
|
thrown by the wrapped function:
|
|
112
112
|
|
|
113
113
|
```typescript
|
|
@@ -37,8 +37,7 @@ Originally, the `requireActual` & `requireMock` the `requireActual`&
|
|
|
37
37
|
|
|
38
38
|
These functions were later moved onto the `jest` object in order to be easier
|
|
39
39
|
for type checkers to handle, and their use via `require` deprecated. Finally,
|
|
40
|
-
the release of Jest 26 saw them removed from the `require` function
|
|
41
|
-
together.
|
|
40
|
+
the release of Jest 26 saw them removed from the `require` function altogether.
|
|
42
41
|
|
|
43
42
|
### `jest.runTimersToTime`
|
|
44
43
|
|
|
@@ -7,7 +7,7 @@ fix.
|
|
|
7
7
|
|
|
8
8
|
## Rule Details
|
|
9
9
|
|
|
10
|
-
This rule looks at the title of every test and test
|
|
10
|
+
This rule looks at the title of every test and test suite. It will report when
|
|
11
11
|
two test suites or two test cases at the same level of a test suite have the
|
|
12
12
|
same title.
|
|
13
13
|
|
|
@@ -9,8 +9,8 @@ API.
|
|
|
9
9
|
|
|
10
10
|
### Rule details
|
|
11
11
|
|
|
12
|
-
This rule reports on any usage of Jasmine globals which is not ported to Jest,
|
|
13
|
-
and suggests
|
|
12
|
+
This rule reports on any usage of Jasmine globals, which is not ported to Jest,
|
|
13
|
+
and suggests alternatives from Jest's own API.
|
|
14
14
|
|
|
15
15
|
### Default configuration
|
|
16
16
|
|
|
@@ -118,8 +118,8 @@ External). Use `inlineMaxSize` for
|
|
|
118
118
|
[Inline Snapshots](https://jestjs.io/docs/en/snapshot-testing#inline-snapshots)
|
|
119
119
|
size and `maxSize` for
|
|
120
120
|
[External Snapshots](https://jestjs.io/docs/en/snapshot-testing#snapshot-testing-with-jest).
|
|
121
|
-
If only `maxSize` is provided on options, the value of `maxSize` will be used
|
|
122
|
-
both snapshot types (Inline and External).
|
|
121
|
+
If only `maxSize` is provided on options, the value of `maxSize` will be used
|
|
122
|
+
for both snapshot types (Inline and External).
|
|
123
123
|
|
|
124
124
|
Since `eslint-disable` comments are not preserved by Jest when updating
|
|
125
125
|
snapshots, you can use the `allowedSnapshots` option to have specific snapshots
|
|
@@ -61,7 +61,7 @@ describe('a test', () => {
|
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
\*Note that this rule will not trigger if the helper function is never used even
|
|
64
|
-
|
|
64
|
+
though the `expect` will not execute. Rely on a rule like no-unused-vars for
|
|
65
65
|
this case.
|
|
66
66
|
|
|
67
67
|
### Options
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Suggest using the built-in comparison matchers (`prefer-comparison-matcher`)
|
|
2
2
|
|
|
3
|
-
Jest has a number of built-in matchers for comparing numbers which allow for
|
|
3
|
+
Jest has a number of built-in matchers for comparing numbers, which allow for
|
|
4
4
|
more readable tests and error messages if an expectation fails.
|
|
5
5
|
|
|
6
6
|
## Rule details
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Suggest using the built-in equality matchers (`prefer-equality-matcher`)
|
|
2
2
|
|
|
3
|
-
Jest has built-in matchers for expecting equality which allow for more readable
|
|
3
|
+
Jest has built-in matchers for expecting equality, which allow for more readable
|
|
4
4
|
tests and error messages if an expectation fails.
|
|
5
5
|
|
|
6
6
|
## Rule details
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Suggest having hooks before any test cases (`prefer-hooks-on-top`)
|
|
2
2
|
|
|
3
3
|
While hooks can be setup anywhere in a test file, they are always called in a
|
|
4
|
-
specific order which means it can be confusing if they're intermixed with test
|
|
4
|
+
specific order, which means it can be confusing if they're intermixed with test
|
|
5
5
|
cases.
|
|
6
6
|
|
|
7
7
|
This rule helps to ensure that hooks are always defined before test cases.
|
|
@@ -73,8 +73,8 @@ it('Uppercase description');
|
|
|
73
73
|
|
|
74
74
|
### `allowedPrefixes`
|
|
75
75
|
|
|
76
|
-
This array option allows specifying prefixes which contain capitals that titles
|
|
77
|
-
can start with. This can be useful when writing tests for
|
|
76
|
+
This array option allows specifying prefixes, which contain capitals that titles
|
|
77
|
+
can start with. This can be useful when writing tests for API endpoints, where
|
|
78
78
|
you'd like to prefix with the HTTP method.
|
|
79
79
|
|
|
80
80
|
By default, nothing is allowed (the equivalent of `{ "allowedPrefixes": [] }`).
|
|
@@ -136,9 +136,9 @@ test('all the things', async () => {
|
|
|
136
136
|
await Promise.resolve(
|
|
137
137
|
expect(Promise.resolve('hello')).resolves.toEqual('hello'),
|
|
138
138
|
);
|
|
139
|
-
await Promise.all(
|
|
139
|
+
await Promise.all([
|
|
140
140
|
expect(Promise.resolve('hello')).resolves.toEqual('hello'),
|
|
141
141
|
expect(Promise.resolve('hi')).resolves.toEqual('hi'),
|
|
142
|
-
);
|
|
142
|
+
]);
|
|
143
143
|
});
|
|
144
144
|
```
|
|
@@ -50,19 +50,20 @@ var _default = (0, _utils2.createRule)({
|
|
|
50
50
|
let describeNestingLevel = 0;
|
|
51
51
|
return {
|
|
52
52
|
CallExpression(node) {
|
|
53
|
+
const scope = context.getScope();
|
|
53
54
|
const nodeName = (0, _utils2.getNodeName)(node.callee);
|
|
54
55
|
|
|
55
56
|
if (!nodeName) {
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
if ((0, _utils2.isDescribeCall)(node)) {
|
|
60
|
+
if ((0, _utils2.isDescribeCall)(node, scope)) {
|
|
60
61
|
describeNestingLevel++;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
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;
|
|
64
65
|
|
|
65
|
-
if ((0, _utils2.isTestCaseCall)(node) && describeNestingLevel === 0 && !nodeName.includes(testKeyword)) {
|
|
66
|
+
if ((0, _utils2.isTestCaseCall)(node, scope) && describeNestingLevel === 0 && !nodeName.includes(testKeyword)) {
|
|
66
67
|
const oppositeTestKeyword = getOppositeTestKeyword(testKeyword);
|
|
67
68
|
context.report({
|
|
68
69
|
messageId: 'consistentMethod',
|
|
@@ -75,7 +76,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
75
76
|
});
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
if ((0, _utils2.isTestCaseCall)(node) && describeNestingLevel > 0 && !nodeName.includes(testKeywordWithinDescribe)) {
|
|
79
|
+
if ((0, _utils2.isTestCaseCall)(node, scope) && describeNestingLevel > 0 && !nodeName.includes(testKeywordWithinDescribe)) {
|
|
79
80
|
const oppositeTestKeyword = getOppositeTestKeyword(testKeywordWithinDescribe);
|
|
80
81
|
context.report({
|
|
81
82
|
messageId: 'consistentMethodWithinDescribe',
|
|
@@ -90,7 +91,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
90
91
|
},
|
|
91
92
|
|
|
92
93
|
'CallExpression:exit'(node) {
|
|
93
|
-
if ((0, _utils2.isDescribeCall)(node)) {
|
|
94
|
+
if ((0, _utils2.isDescribeCall)(node, context.getScope())) {
|
|
94
95
|
describeNestingLevel--;
|
|
95
96
|
}
|
|
96
97
|
}
|
|
@@ -76,7 +76,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
76
76
|
|
|
77
77
|
if (node.type === _utils.AST_NODE_TYPES.FunctionDeclaration) {
|
|
78
78
|
const declaredVariables = context.getDeclaredVariables(node);
|
|
79
|
-
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables);
|
|
79
|
+
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables, context.getScope());
|
|
80
80
|
checkCallExpressionUsed(testCallExpressions);
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -93,7 +93,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
93
93
|
|
|
94
94
|
const name = (_getNodeName = (0, _utils2.getNodeName)(node.callee)) !== null && _getNodeName !== void 0 ? _getNodeName : '';
|
|
95
95
|
|
|
96
|
-
if ((0, _utils2.isTestCaseCall)(node) || additionalTestBlockFunctions.includes(name)) {
|
|
96
|
+
if ((0, _utils2.isTestCaseCall)(node, context.getScope()) || additionalTestBlockFunctions.includes(name)) {
|
|
97
97
|
if (node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.property, 'todo')) {
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
@@ -46,7 +46,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
46
46
|
parent
|
|
47
47
|
} = node;
|
|
48
48
|
|
|
49
|
-
if ((parent === null || parent === void 0 ? void 0 : parent.type) !== _utils.AST_NODE_TYPES.CallExpression || !(0, _utils2.isDescribeCall)(parent)) {
|
|
49
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) !== _utils.AST_NODE_TYPES.CallExpression || !(0, _utils2.isDescribeCall)(parent, context.getScope())) {
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -69,7 +69,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
69
69
|
parent
|
|
70
70
|
} = node;
|
|
71
71
|
|
|
72
|
-
if ((parent === null || parent === void 0 ? void 0 : parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isDescribeCall)(parent)) {
|
|
72
|
+
if ((parent === null || parent === void 0 ? void 0 : parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isDescribeCall)(parent, context.getScope())) {
|
|
73
73
|
describeCallbackStack.pop();
|
|
74
74
|
}
|
|
75
75
|
}
|
|
@@ -39,7 +39,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
39
39
|
return {
|
|
40
40
|
FunctionDeclaration(node) {
|
|
41
41
|
const declaredVariables = context.getDeclaredVariables(node);
|
|
42
|
-
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables);
|
|
42
|
+
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables, context.getScope());
|
|
43
43
|
|
|
44
44
|
if (testCallExpressions.length > 0) {
|
|
45
45
|
inTestCase = true;
|
|
@@ -47,7 +47,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
47
47
|
},
|
|
48
48
|
|
|
49
49
|
CallExpression(node) {
|
|
50
|
-
if ((0, _utils2.isTestCaseCall)(node)) {
|
|
50
|
+
if ((0, _utils2.isTestCaseCall)(node, context.getScope())) {
|
|
51
51
|
inTestCase = true;
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -71,7 +71,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
71
71
|
},
|
|
72
72
|
|
|
73
73
|
'CallExpression:exit'(node) {
|
|
74
|
-
if ((0, _utils2.isTestCaseCall)(node)) {
|
|
74
|
+
if ((0, _utils2.isTestCaseCall)(node, context.getScope())) {
|
|
75
75
|
inTestCase = false;
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -37,13 +37,13 @@ var _default = (0, _utils.createRule)({
|
|
|
37
37
|
|
|
38
38
|
return {
|
|
39
39
|
CallExpression(node) {
|
|
40
|
-
if ((0, _utils.isTestCaseCall)(node)) {
|
|
40
|
+
if ((0, _utils.isTestCaseCall)(node, context.getScope())) {
|
|
41
41
|
inTestCase = true;
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
|
|
45
45
|
'CallExpression:exit'(node) {
|
|
46
|
-
if ((0, _utils.isTestCaseCall)(node)) {
|
|
46
|
+
if ((0, _utils.isTestCaseCall)(node, context.getScope())) {
|
|
47
47
|
inTestCase = false;
|
|
48
48
|
}
|
|
49
49
|
},
|
|
@@ -9,16 +9,16 @@ 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, scope) => {
|
|
13
13
|
if (isJestEach) {
|
|
14
14
|
return node.arguments[1];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
if ((0, _utils2.
|
|
17
|
+
if ((0, _utils2.isHookCall)(node, scope) && node.arguments.length >= 1) {
|
|
18
18
|
return node.arguments[0];
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
if ((0, _utils2.isTestCaseCall)(node) && node.arguments.length >= 2) {
|
|
21
|
+
if ((0, _utils2.isTestCaseCall)(node, scope) && node.arguments.length >= 2) {
|
|
22
22
|
return node.arguments[1];
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -60,7 +60,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
const callback = findCallbackArg(node, isJestEach);
|
|
63
|
+
const callback = findCallbackArg(node, isJestEach, context.getScope());
|
|
64
64
|
const callbackArgIndex = Number(isJestEach);
|
|
65
65
|
|
|
66
66
|
if (!callback || !(0, _utils2.isFunction)(callback) || callback.params.length !== 1 + callbackArgIndex) {
|
|
@@ -34,11 +34,13 @@ var _default = (0, _utils.createRule)({
|
|
|
34
34
|
const hookContexts = [newHookContext()];
|
|
35
35
|
return {
|
|
36
36
|
CallExpression(node) {
|
|
37
|
-
|
|
37
|
+
const scope = context.getScope();
|
|
38
|
+
|
|
39
|
+
if ((0, _utils.isDescribeCall)(node, scope)) {
|
|
38
40
|
hookContexts.push(newHookContext());
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
if ((0, _utils.
|
|
43
|
+
if ((0, _utils.isHookCall)(node, scope)) {
|
|
42
44
|
const currentLayer = hookContexts[hookContexts.length - 1];
|
|
43
45
|
currentLayer[node.callee.name] += 1;
|
|
44
46
|
|
|
@@ -55,7 +57,7 @@ var _default = (0, _utils.createRule)({
|
|
|
55
57
|
},
|
|
56
58
|
|
|
57
59
|
'CallExpression:exit'(node) {
|
|
58
|
-
if ((0, _utils.isDescribeCall)(node)) {
|
|
60
|
+
if ((0, _utils.isDescribeCall)(node, context.getScope())) {
|
|
59
61
|
hookContexts.pop();
|
|
60
62
|
}
|
|
61
63
|
}
|
package/lib/rules/no-export.js
CHANGED
|
@@ -45,41 +45,47 @@ var _default = (0, _utils2.createRule)({
|
|
|
45
45
|
hasSuggestions: true
|
|
46
46
|
},
|
|
47
47
|
defaultOptions: [],
|
|
48
|
-
create: context => ({
|
|
49
|
-
CallExpression(node) {
|
|
50
|
-
if (!(0, _utils2.isDescribeCall)(node) && !(0, _utils2.isTestCaseCall)(node)) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
48
|
|
|
54
|
-
|
|
49
|
+
create(context) {
|
|
50
|
+
return {
|
|
51
|
+
CallExpression(node) {
|
|
52
|
+
const scope = context.getScope();
|
|
53
|
+
|
|
54
|
+
if (!(0, _utils2.isDescribeCall)(node, scope) && !(0, _utils2.isTestCaseCall)(node, scope)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if ((0, _utils2.getNodeName)(node).startsWith('f')) {
|
|
59
|
+
context.report({
|
|
60
|
+
messageId: 'focusedTest',
|
|
61
|
+
node,
|
|
62
|
+
suggest: [{
|
|
63
|
+
messageId: 'suggestRemoveFocus',
|
|
64
|
+
fix: fixer => fixer.removeRange([node.range[0], node.range[0] + 1])
|
|
65
|
+
}]
|
|
66
|
+
});
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const onlyNode = findOnlyNode(node);
|
|
71
|
+
|
|
72
|
+
if (!onlyNode) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
55
76
|
context.report({
|
|
56
77
|
messageId: 'focusedTest',
|
|
57
|
-
node,
|
|
78
|
+
node: onlyNode,
|
|
58
79
|
suggest: [{
|
|
59
80
|
messageId: 'suggestRemoveFocus',
|
|
60
|
-
fix: fixer => fixer.removeRange([
|
|
81
|
+
fix: fixer => fixer.removeRange([onlyNode.range[0] - 1, onlyNode.range[1] + Number(onlyNode.type !== _utils.AST_NODE_TYPES.Identifier)])
|
|
61
82
|
}]
|
|
62
83
|
});
|
|
63
|
-
return;
|
|
64
84
|
}
|
|
65
85
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (!onlyNode) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
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
|
-
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
81
88
|
|
|
82
|
-
})
|
|
83
89
|
});
|
|
84
90
|
|
|
85
91
|
exports.default = _default;
|
package/lib/rules/no-hooks.js
CHANGED
|
@@ -39,7 +39,7 @@ var _default = (0, _utils.createRule)({
|
|
|
39
39
|
}]) {
|
|
40
40
|
return {
|
|
41
41
|
CallExpression(node) {
|
|
42
|
-
if ((0, _utils.
|
|
42
|
+
if ((0, _utils.isHookCall)(node, context.getScope()) && !allow.includes(node.callee.name)) {
|
|
43
43
|
context.report({
|
|
44
44
|
node,
|
|
45
45
|
messageId: 'unexpectedHook',
|
|
@@ -35,9 +35,10 @@ var _default = (0, _utils.createRule)({
|
|
|
35
35
|
CallExpression(node) {
|
|
36
36
|
var _getNodeName;
|
|
37
37
|
|
|
38
|
+
const scope = context.getScope();
|
|
38
39
|
const currentLayer = contexts[contexts.length - 1];
|
|
39
40
|
|
|
40
|
-
if ((0, _utils.isDescribeCall)(node)) {
|
|
41
|
+
if ((0, _utils.isDescribeCall)(node, scope)) {
|
|
41
42
|
contexts.push(newDescribeContext());
|
|
42
43
|
}
|
|
43
44
|
|
|
@@ -53,7 +54,7 @@ var _default = (0, _utils.createRule)({
|
|
|
53
54
|
|
|
54
55
|
const title = (0, _utils.getStringValue)(argument);
|
|
55
56
|
|
|
56
|
-
if ((0, _utils.isTestCaseCall)(node)) {
|
|
57
|
+
if ((0, _utils.isTestCaseCall)(node, scope)) {
|
|
57
58
|
if (currentLayer.testTitles.includes(title)) {
|
|
58
59
|
context.report({
|
|
59
60
|
messageId: 'multipleTestTitle',
|
|
@@ -64,7 +65,7 @@ var _default = (0, _utils.createRule)({
|
|
|
64
65
|
currentLayer.testTitles.push(title);
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
if (!(0, _utils.isDescribeCall)(node)) {
|
|
68
|
+
if (!(0, _utils.isDescribeCall)(node, scope)) {
|
|
68
69
|
return;
|
|
69
70
|
}
|
|
70
71
|
|
|
@@ -79,7 +80,7 @@ var _default = (0, _utils.createRule)({
|
|
|
79
80
|
},
|
|
80
81
|
|
|
81
82
|
'CallExpression:exit'(node) {
|
|
82
|
-
if ((0, _utils.isDescribeCall)(node)) {
|
|
83
|
+
if ((0, _utils.isDescribeCall)(node, context.getScope())) {
|
|
83
84
|
contexts.pop();
|
|
84
85
|
}
|
|
85
86
|
}
|
package/lib/rules/no-if.js
CHANGED
|
@@ -58,7 +58,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
58
58
|
|
|
59
59
|
return {
|
|
60
60
|
CallExpression(node) {
|
|
61
|
-
if ((0, _utils2.isTestCaseCall)(node)) {
|
|
61
|
+
if ((0, _utils2.isTestCaseCall)(node, context.getScope())) {
|
|
62
62
|
stack.push(true);
|
|
63
63
|
|
|
64
64
|
if ((0, _utils2.getNodeName)(node).endsWith('each')) {
|
|
@@ -73,7 +73,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
73
73
|
|
|
74
74
|
FunctionDeclaration(node) {
|
|
75
75
|
const declaredVariables = context.getDeclaredVariables(node);
|
|
76
|
-
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables);
|
|
76
|
+
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables, context.getScope());
|
|
77
77
|
stack.push(testCallExpressions.length > 0);
|
|
78
78
|
},
|
|
79
79
|
|
|
@@ -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, scope) => {
|
|
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.isDescribeCall)(expr)) {
|
|
33
|
+
if (expr.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isDescribeCall)(expr, scope)) {
|
|
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.isTestCaseCall)(node) || isCustomTestBlockFunction(node);
|
|
76
|
+
const isTestBlock = node => (0, _utils2.isTestCaseCall)(node, context.getScope()) || 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.getScope());
|
|
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.getScope())) {
|
|
120
120
|
callStack.pop();
|
|
121
121
|
}
|
|
122
122
|
},
|
|
@@ -29,8 +29,9 @@ var _default = (0, _utils2.createRule)({
|
|
|
29
29
|
create(context) {
|
|
30
30
|
return {
|
|
31
31
|
CallExpression(node) {
|
|
32
|
+
const scope = context.getScope();
|
|
32
33
|
const nodeName = (0, _utils2.getNodeName)(node.callee);
|
|
33
|
-
if (!nodeName || !(0, _utils2.isDescribeCall)(node) && !(0, _utils2.isTestCaseCall)(node)) return;
|
|
34
|
+
if (!nodeName || !(0, _utils2.isDescribeCall)(node, scope) && !(0, _utils2.isTestCaseCall)(node, scope)) return;
|
|
34
35
|
const preferredNodeName = getPreferredNodeName(nodeName);
|
|
35
36
|
if (!preferredNodeName) return;
|
|
36
37
|
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;
|
|
@@ -38,7 +38,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
38
38
|
create(context) {
|
|
39
39
|
return {
|
|
40
40
|
CallExpression(node) {
|
|
41
|
-
if (!(0, _utils2.isTestCaseCall)(node)) return;
|
|
41
|
+
if (!(0, _utils2.isTestCaseCall)(node, context.getScope())) return;
|
|
42
42
|
const body = getBody(node.arguments);
|
|
43
43
|
const returnStmt = body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement);
|
|
44
44
|
if (!returnStmt) return;
|
|
@@ -50,7 +50,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
50
50
|
|
|
51
51
|
FunctionDeclaration(node) {
|
|
52
52
|
const declaredVariables = context.getDeclaredVariables(node);
|
|
53
|
-
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables);
|
|
53
|
+
const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables, context.getScope());
|
|
54
54
|
if (testCallExpressions.length === 0) return;
|
|
55
55
|
const returnStmt = node.body.body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement);
|
|
56
56
|
if (!returnStmt) return;
|
|
@@ -116,7 +116,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
116
116
|
'ForOfStatement:exit': exitForLoop,
|
|
117
117
|
|
|
118
118
|
CallExpression(node) {
|
|
119
|
-
if ((0, _utils2.isTestCaseCall)(node)) {
|
|
119
|
+
if ((0, _utils2.isTestCaseCall)(node, context.getScope())) {
|
|
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.isTestCaseCall)(node)) {
|
|
136
|
+
if (!(0, _utils2.isTestCaseCall)(node, context.getScope())) {
|
|
137
137
|
return;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
inTestCaseCall = false;
|
|
141
|
+
|
|
140
142
|
if (node.arguments.length < 2) {
|
|
141
143
|
return;
|
|
142
144
|
}
|
|
@@ -27,11 +27,13 @@ var _default = (0, _utils.createRule)({
|
|
|
27
27
|
const hooksContext = [false];
|
|
28
28
|
return {
|
|
29
29
|
CallExpression(node) {
|
|
30
|
-
|
|
30
|
+
const scope = context.getScope();
|
|
31
|
+
|
|
32
|
+
if (!(0, _utils.isHookCall)(node, scope) && (0, _utils.isTestCaseCall)(node, scope)) {
|
|
31
33
|
hooksContext[hooksContext.length - 1] = true;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
if (hooksContext[hooksContext.length - 1] && (0, _utils.
|
|
36
|
+
if (hooksContext[hooksContext.length - 1] && (0, _utils.isHookCall)(node, scope)) {
|
|
35
37
|
context.report({
|
|
36
38
|
messageId: 'noHookOnTop',
|
|
37
39
|
node
|
|
@@ -9,8 +9,8 @@ var _utils = require("./utils");
|
|
|
9
9
|
|
|
10
10
|
const hasStringAsFirstArgument = node => node.arguments[0] && (0, _utils.isStringNode)(node.arguments[0]);
|
|
11
11
|
|
|
12
|
-
const findNodeNameAndArgument = node => {
|
|
13
|
-
if (!((0, _utils.isTestCaseCall)(node) || (0, _utils.isDescribeCall)(node))) {
|
|
12
|
+
const findNodeNameAndArgument = (node, scope) => {
|
|
13
|
+
if (!((0, _utils.isTestCaseCall)(node, scope) || (0, _utils.isDescribeCall)(node, scope))) {
|
|
14
14
|
return null;
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -92,7 +92,9 @@ var _default = (0, _utils.createRule)({
|
|
|
92
92
|
let numberOfDescribeBlocks = 0;
|
|
93
93
|
return {
|
|
94
94
|
CallExpression(node) {
|
|
95
|
-
|
|
95
|
+
const scope = context.getScope();
|
|
96
|
+
|
|
97
|
+
if ((0, _utils.isDescribeCall)(node, scope)) {
|
|
96
98
|
numberOfDescribeBlocks++;
|
|
97
99
|
|
|
98
100
|
if (ignoreTopLevelDescribe && numberOfDescribeBlocks === 1) {
|
|
@@ -100,7 +102,7 @@ var _default = (0, _utils.createRule)({
|
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
|
|
103
|
-
const results = findNodeNameAndArgument(node);
|
|
105
|
+
const results = findNodeNameAndArgument(node, scope);
|
|
104
106
|
|
|
105
107
|
if (!results) {
|
|
106
108
|
return;
|
|
@@ -137,7 +139,7 @@ var _default = (0, _utils.createRule)({
|
|
|
137
139
|
},
|
|
138
140
|
|
|
139
141
|
'CallExpression:exit'(node) {
|
|
140
|
-
if ((0, _utils.isDescribeCall)(node)) {
|
|
142
|
+
if ((0, _utils.isDescribeCall)(node, context.getScope())) {
|
|
141
143
|
numberOfDescribeBlocks--;
|
|
142
144
|
}
|
|
143
145
|
}
|
|
@@ -106,7 +106,9 @@ var _default = (0, _utils.createRule)({
|
|
|
106
106
|
'ArrowFunctionExpression:exit': exitExpression,
|
|
107
107
|
|
|
108
108
|
'CallExpression:exit'(node) {
|
|
109
|
-
|
|
109
|
+
const scope = context.getScope();
|
|
110
|
+
|
|
111
|
+
if ((0, _utils.isDescribeCall)(node, scope) || (0, _utils.isTestCaseCall)(node, scope)) {
|
|
110
112
|
var _depths$pop;
|
|
111
113
|
|
|
112
114
|
/* istanbul ignore next */
|
|
@@ -115,7 +117,9 @@ var _default = (0, _utils.createRule)({
|
|
|
115
117
|
},
|
|
116
118
|
|
|
117
119
|
CallExpression(node) {
|
|
118
|
-
|
|
120
|
+
const scope = context.getScope();
|
|
121
|
+
|
|
122
|
+
if ((0, _utils.isDescribeCall)(node, scope) || (0, _utils.isTestCaseCall)(node, scope)) {
|
|
119
123
|
depths.push(expressionDepth);
|
|
120
124
|
expressionDepth = 0;
|
|
121
125
|
}
|
package/lib/rules/prefer-todo.js
CHANGED
|
@@ -22,7 +22,7 @@ function createTodoFixer(node, fixer) {
|
|
|
22
22
|
return fixer.replaceText(node.callee, `${testName}.todo`);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const isTargetedTestCase = node => (0, _utils2.isTestCaseCall)(node) && [_utils2.TestCaseName.it, _utils2.TestCaseName.test, 'it.skip', 'test.skip'].includes((0, _utils2.getNodeName)(node));
|
|
25
|
+
const isTargetedTestCase = (node, scope) => (0, _utils2.isTestCaseCall)(node, scope) && [_utils2.TestCaseName.it, _utils2.TestCaseName.test, 'it.skip', 'test.skip'].includes((0, _utils2.getNodeName)(node));
|
|
26
26
|
|
|
27
27
|
var _default = (0, _utils2.createRule)({
|
|
28
28
|
name: __filename,
|
|
@@ -47,7 +47,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
47
47
|
CallExpression(node) {
|
|
48
48
|
const [title, callback] = node.arguments;
|
|
49
49
|
|
|
50
|
-
if (!title || !isTargetedTestCase(node) || !(0, _utils2.isStringNode)(title)) {
|
|
50
|
+
if (!title || !isTargetedTestCase(node, context.getScope()) || !(0, _utils2.isStringNode)(title)) {
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -9,10 +9,10 @@ var _utils = require("@typescript-eslint/utils");
|
|
|
9
9
|
|
|
10
10
|
var _utils2 = require("./utils");
|
|
11
11
|
|
|
12
|
-
const isJestFnCall = node => {
|
|
12
|
+
const isJestFnCall = (node, scope) => {
|
|
13
13
|
var _getNodeName;
|
|
14
14
|
|
|
15
|
-
if ((0, _utils2.isDescribeCall)(node) || (0, _utils2.isTestCaseCall)(node) || (0, _utils2.
|
|
15
|
+
if ((0, _utils2.isDescribeCall)(node, scope) || (0, _utils2.isTestCaseCall)(node, scope) || (0, _utils2.isHookCall)(node, scope)) {
|
|
16
16
|
return true;
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -23,13 +23,13 @@ const isNullOrUndefined = node => {
|
|
|
23
23
|
return node.type === _utils.AST_NODE_TYPES.Literal && node.value === null || (0, _utils2.isIdentifier)(node, 'undefined');
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
const shouldBeInHook = (node, allowedFunctionCalls = []) => {
|
|
26
|
+
const shouldBeInHook = (node, scope, allowedFunctionCalls = []) => {
|
|
27
27
|
switch (node.type) {
|
|
28
28
|
case _utils.AST_NODE_TYPES.ExpressionStatement:
|
|
29
|
-
return shouldBeInHook(node.expression, allowedFunctionCalls);
|
|
29
|
+
return shouldBeInHook(node.expression, scope, allowedFunctionCalls);
|
|
30
30
|
|
|
31
31
|
case _utils.AST_NODE_TYPES.CallExpression:
|
|
32
|
-
return !(isJestFnCall(node) || allowedFunctionCalls.includes((0, _utils2.getNodeName)(node)));
|
|
32
|
+
return !(isJestFnCall(node, scope) || allowedFunctionCalls.includes((0, _utils2.getNodeName)(node)));
|
|
33
33
|
|
|
34
34
|
case _utils.AST_NODE_TYPES.VariableDeclaration:
|
|
35
35
|
{
|
|
@@ -85,7 +85,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
85
85
|
|
|
86
86
|
const checkBlockBody = body => {
|
|
87
87
|
for (const statement of body) {
|
|
88
|
-
if (shouldBeInHook(statement, allowedFunctionCalls)) {
|
|
88
|
+
if (shouldBeInHook(statement, context.getScope(), allowedFunctionCalls)) {
|
|
89
89
|
context.report({
|
|
90
90
|
node: statement,
|
|
91
91
|
messageId: 'useHook'
|
|
@@ -100,7 +100,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
100
100
|
},
|
|
101
101
|
|
|
102
102
|
CallExpression(node) {
|
|
103
|
-
if (!(0, _utils2.isDescribeCall)(node) || node.arguments.length < 2) {
|
|
103
|
+
if (!(0, _utils2.isDescribeCall)(node, context.getScope()) || node.arguments.length < 2) {
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -46,7 +46,9 @@ var _default = (0, _utils.createRule)({
|
|
|
46
46
|
let numberOfDescribeBlocks = 0;
|
|
47
47
|
return {
|
|
48
48
|
CallExpression(node) {
|
|
49
|
-
|
|
49
|
+
const scope = context.getScope();
|
|
50
|
+
|
|
51
|
+
if ((0, _utils.isDescribeCall)(node, scope)) {
|
|
50
52
|
numberOfDescribeBlocks++;
|
|
51
53
|
|
|
52
54
|
if (numberOfDescribeBlocks === 1) {
|
|
@@ -68,7 +70,7 @@ var _default = (0, _utils.createRule)({
|
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
if (numberOfDescribeBlocks === 0) {
|
|
71
|
-
if ((0, _utils.isTestCaseCall)(node)) {
|
|
73
|
+
if ((0, _utils.isTestCaseCall)(node, scope)) {
|
|
72
74
|
context.report({
|
|
73
75
|
node,
|
|
74
76
|
messageId: 'unexpectedTestCase'
|
|
@@ -76,7 +78,7 @@ var _default = (0, _utils.createRule)({
|
|
|
76
78
|
return;
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
if ((0, _utils.
|
|
81
|
+
if ((0, _utils.isHookCall)(node, scope)) {
|
|
80
82
|
context.report({
|
|
81
83
|
node,
|
|
82
84
|
messageId: 'unexpectedHook'
|
|
@@ -87,7 +89,7 @@ var _default = (0, _utils.createRule)({
|
|
|
87
89
|
},
|
|
88
90
|
|
|
89
91
|
'CallExpression:exit'(node) {
|
|
90
|
-
if ((0, _utils.isDescribeCall)(node)) {
|
|
92
|
+
if ((0, _utils.isDescribeCall)(node, context.getScope())) {
|
|
91
93
|
numberOfDescribeBlocks--;
|
|
92
94
|
}
|
|
93
95
|
}
|
package/lib/rules/utils.js
CHANGED
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.getAccessorValue = exports.followTypeAssertionChain = exports.createRule = exports.TestCaseProperty = exports.TestCaseName = exports.ModifierName = exports.HookName = exports.EqualityMatcher = exports.DescribeProperty = exports.DescribeAlias = void 0;
|
|
7
7
|
exports.getNodeName = getNodeName;
|
|
8
|
-
exports.scopeHasLocalReference = exports.parseExpectCall = exports.isTestCaseCall = exports.isSupportedAccessor = exports.isStringNode = exports.isParsedEqualityMatcherCall = exports.isIdentifier = exports.
|
|
8
|
+
exports.scopeHasLocalReference = exports.parseExpectCall = exports.isTestCaseCall = exports.isSupportedAccessor = exports.isStringNode = exports.isParsedEqualityMatcherCall = exports.isIdentifier = exports.isHookCall = exports.isFunction = exports.isExpectMember = exports.isExpectCall = exports.isDescribeCall = exports.hasOnlyOneArgument = exports.getTestCallExpressionsFromDeclaredVariables = exports.getStringValue = void 0;
|
|
9
9
|
|
|
10
10
|
var _path = require("path");
|
|
11
11
|
|
|
@@ -384,108 +384,220 @@ const isFunction = node => node.type === _utils.AST_NODE_TYPES.FunctionExpressio
|
|
|
384
384
|
|
|
385
385
|
exports.isFunction = isFunction;
|
|
386
386
|
|
|
387
|
-
const
|
|
387
|
+
const isHookCall = (node, scope) => {
|
|
388
|
+
let name = findFirstCallPropertyName(node, []);
|
|
388
389
|
|
|
389
|
-
|
|
390
|
+
if (!name) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
name = resolveToJestFn(scope, name);
|
|
395
|
+
return name !== null && HookName.hasOwnProperty(name);
|
|
396
|
+
};
|
|
390
397
|
|
|
391
|
-
|
|
398
|
+
exports.isHookCall = isHookCall;
|
|
399
|
+
|
|
400
|
+
const getTestCallExpressionsFromDeclaredVariables = (declaredVariables, scope) => {
|
|
392
401
|
return declaredVariables.reduce((acc, {
|
|
393
402
|
references
|
|
394
403
|
}) => acc.concat(references.map(({
|
|
395
404
|
identifier
|
|
396
|
-
}) => identifier.parent).filter(node => !!node && node.type === _utils.AST_NODE_TYPES.CallExpression && isTestCaseCall(node))), []);
|
|
405
|
+
}) => identifier.parent).filter(node => !!node && node.type === _utils.AST_NODE_TYPES.CallExpression && isTestCaseCall(node, scope))), []);
|
|
397
406
|
};
|
|
398
|
-
|
|
399
|
-
exports.getTestCallExpressionsFromDeclaredVariables = getTestCallExpressionsFromDeclaredVariables;
|
|
400
|
-
|
|
401
|
-
const isTestCaseName = node => node.type === _utils.AST_NODE_TYPES.Identifier && TestCaseName.hasOwnProperty(node.name);
|
|
402
|
-
|
|
403
|
-
const isTestCaseProperty = node => isSupportedAccessor(node) && TestCaseProperty.hasOwnProperty(getAccessorValue(node));
|
|
404
407
|
/**
|
|
405
408
|
* Checks if the given `node` is a *call* to a test case function that would
|
|
406
409
|
* result in tests being run by `jest`.
|
|
407
410
|
*
|
|
408
411
|
* Note that `.each()` does not count as a call in this context, as it will not
|
|
409
412
|
* result in `jest` running any tests.
|
|
410
|
-
*
|
|
411
|
-
* @param {TSESTree.CallExpression} node
|
|
412
|
-
*
|
|
413
|
-
* @return {node is JestFunctionCallExpression<TestCaseName>}
|
|
414
413
|
*/
|
|
415
414
|
|
|
416
415
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
416
|
+
exports.getTestCallExpressionsFromDeclaredVariables = getTestCallExpressionsFromDeclaredVariables;
|
|
417
|
+
|
|
418
|
+
const isTestCaseCall = (node, scope) => {
|
|
419
|
+
let name = findFirstCallPropertyName(node, Object.keys(TestCaseProperty));
|
|
420
|
+
|
|
421
|
+
if (!name) {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
name = resolveToJestFn(scope, name);
|
|
426
|
+
return name !== null && TestCaseName.hasOwnProperty(name);
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
exports.isTestCaseCall = isTestCaseCall;
|
|
430
|
+
|
|
431
|
+
const findFirstCallPropertyName = (node, properties) => {
|
|
432
|
+
if (isIdentifier(node.callee)) {
|
|
433
|
+
return node.callee.name;
|
|
420
434
|
}
|
|
421
435
|
|
|
422
436
|
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;
|
|
423
437
|
|
|
424
|
-
if (callee.type === _utils.AST_NODE_TYPES.MemberExpression &&
|
|
438
|
+
if (callee.type === _utils.AST_NODE_TYPES.MemberExpression && isSupportedAccessor(callee.property) && properties.includes(getAccessorValue(callee.property))) {
|
|
425
439
|
// if we're an `each()`, ensure we're the outer CallExpression (i.e `.each()()`)
|
|
426
440
|
if (getAccessorValue(callee.property) === 'each' && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression && node.callee.type !== _utils.AST_NODE_TYPES.CallExpression) {
|
|
427
|
-
return
|
|
441
|
+
return null;
|
|
428
442
|
}
|
|
429
443
|
|
|
430
|
-
|
|
444
|
+
const nod = callee.object.type === _utils.AST_NODE_TYPES.MemberExpression ? callee.object.object : callee.object;
|
|
445
|
+
|
|
446
|
+
if (isSupportedAccessor(nod)) {
|
|
447
|
+
return getAccessorValue(nod);
|
|
448
|
+
}
|
|
431
449
|
}
|
|
432
450
|
|
|
433
|
-
return
|
|
451
|
+
return null;
|
|
434
452
|
};
|
|
435
|
-
|
|
436
|
-
exports.isTestCaseCall = isTestCaseCall;
|
|
437
|
-
|
|
438
|
-
const isDescribeAlias = node => node.type === _utils.AST_NODE_TYPES.Identifier && DescribeAlias.hasOwnProperty(node.name);
|
|
439
|
-
|
|
440
|
-
const isDescribeProperty = node => isSupportedAccessor(node) && DescribeProperty.hasOwnProperty(getAccessorValue(node));
|
|
441
453
|
/**
|
|
442
454
|
* Checks if the given `node` is a *call* to a `describe` function that would
|
|
443
455
|
* result in a `describe` block being created by `jest`.
|
|
444
456
|
*
|
|
445
457
|
* Note that `.each()` does not count as a call in this context, as it will not
|
|
446
458
|
* result in `jest` creating any `describe` blocks.
|
|
447
|
-
*
|
|
448
|
-
* @param {TSESTree.CallExpression} node
|
|
449
|
-
*
|
|
450
|
-
* @return {node is JestFunctionCallExpression<TestCaseName>}
|
|
451
459
|
*/
|
|
452
460
|
|
|
453
461
|
|
|
454
|
-
const isDescribeCall = node => {
|
|
455
|
-
|
|
456
|
-
|
|
462
|
+
const isDescribeCall = (node, scope) => {
|
|
463
|
+
let name = findFirstCallPropertyName(node, Object.keys(DescribeProperty));
|
|
464
|
+
|
|
465
|
+
if (!name) {
|
|
466
|
+
return false;
|
|
457
467
|
}
|
|
458
468
|
|
|
459
|
-
|
|
469
|
+
name = resolveToJestFn(scope, name);
|
|
470
|
+
return name !== null && DescribeAlias.hasOwnProperty(name);
|
|
471
|
+
};
|
|
460
472
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
473
|
+
exports.isDescribeCall = isDescribeCall;
|
|
474
|
+
|
|
475
|
+
const describeImportDefAsImport = def => {
|
|
476
|
+
if (def.parent.type === _utils.AST_NODE_TYPES.TSImportEqualsDeclaration) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (def.node.type !== _utils.AST_NODE_TYPES.ImportSpecifier) {
|
|
481
|
+
return null;
|
|
482
|
+
} // we only care about value imports
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
if (def.parent.importKind === 'type') {
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return {
|
|
490
|
+
source: def.parent.source.value,
|
|
491
|
+
imported: def.node.imported.name,
|
|
492
|
+
local: def.node.local.name
|
|
493
|
+
};
|
|
494
|
+
};
|
|
495
|
+
/**
|
|
496
|
+
* Attempts to find the node that represents the import source for the
|
|
497
|
+
* given expression node, if it looks like it's an import.
|
|
498
|
+
*
|
|
499
|
+
* If no such node can be found (e.g. because the expression doesn't look
|
|
500
|
+
* like an import), then `null` is returned instead.
|
|
501
|
+
*/
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
const findImportSourceNode = node => {
|
|
505
|
+
if (node.type === _utils.AST_NODE_TYPES.AwaitExpression) {
|
|
506
|
+
if (node.argument.type === _utils.AST_NODE_TYPES.ImportExpression) {
|
|
507
|
+
return node.argument.source;
|
|
465
508
|
}
|
|
466
509
|
|
|
467
|
-
return
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (node.type === _utils.AST_NODE_TYPES.CallExpression && isIdentifier(node.callee, 'require')) {
|
|
514
|
+
var _node$arguments$;
|
|
515
|
+
|
|
516
|
+
return (_node$arguments$ = node.arguments[0]) !== null && _node$arguments$ !== void 0 ? _node$arguments$ : null;
|
|
468
517
|
}
|
|
469
518
|
|
|
470
|
-
return
|
|
519
|
+
return null;
|
|
471
520
|
};
|
|
472
521
|
|
|
473
|
-
|
|
522
|
+
const describeVariableDefAsImport = def => {
|
|
523
|
+
var _def$name$parent;
|
|
524
|
+
|
|
525
|
+
// make sure that we've actually being assigned a value
|
|
526
|
+
if (!def.node.init) {
|
|
527
|
+
return null;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const sourceNode = findImportSourceNode(def.node.init);
|
|
531
|
+
|
|
532
|
+
if (!sourceNode || !isStringNode(sourceNode)) {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (((_def$name$parent = def.name.parent) === null || _def$name$parent === void 0 ? void 0 : _def$name$parent.type) !== _utils.AST_NODE_TYPES.Property) {
|
|
537
|
+
return null;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (!isSupportedAccessor(def.name.parent.key)) {
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return {
|
|
545
|
+
source: getStringValue(sourceNode),
|
|
546
|
+
imported: getAccessorValue(def.name.parent.key),
|
|
547
|
+
local: def.name.name
|
|
548
|
+
};
|
|
549
|
+
};
|
|
550
|
+
/**
|
|
551
|
+
* Attempts to describe a definition as an import if possible.
|
|
552
|
+
*
|
|
553
|
+
* If the definition is an import binding, it's described as you'd expect.
|
|
554
|
+
* If the definition is a variable, then we try and determine if it's either
|
|
555
|
+
* a dynamic `import()` or otherwise a call to `require()`.
|
|
556
|
+
*
|
|
557
|
+
* If it's neither of these, `null` is returned to indicate that the definition
|
|
558
|
+
* is not describable as an import of any kind.
|
|
559
|
+
*/
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
const describePossibleImportDef = def => {
|
|
563
|
+
if (def.type === 'Variable') {
|
|
564
|
+
return describeVariableDefAsImport(def);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (def.type === 'ImportBinding') {
|
|
568
|
+
return describeImportDefAsImport(def);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
return null;
|
|
572
|
+
};
|
|
474
573
|
|
|
475
574
|
const collectReferences = scope => {
|
|
476
575
|
const locals = new Set();
|
|
576
|
+
const imports = new Map();
|
|
477
577
|
const unresolved = new Set();
|
|
478
578
|
let currentScope = scope;
|
|
479
579
|
|
|
480
580
|
while (currentScope !== null) {
|
|
481
581
|
for (const ref of currentScope.variables) {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
}
|
|
582
|
+
if (ref.defs.length === 0) {
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
/* istanbul ignore if */
|
|
485
586
|
|
|
486
|
-
|
|
487
|
-
|
|
587
|
+
|
|
588
|
+
if (ref.defs.length > 1) {
|
|
589
|
+
throw new Error(`Reference unexpected had more than one definition - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
|
|
488
590
|
}
|
|
591
|
+
|
|
592
|
+
const [def] = ref.defs;
|
|
593
|
+
const importDetails = describePossibleImportDef(def);
|
|
594
|
+
|
|
595
|
+
if (importDetails) {
|
|
596
|
+
imports.set(importDetails.local, importDetails);
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
locals.add(ref.name);
|
|
489
601
|
}
|
|
490
602
|
|
|
491
603
|
for (const ref of currentScope.through) {
|
|
@@ -497,6 +609,7 @@ const collectReferences = scope => {
|
|
|
497
609
|
|
|
498
610
|
return {
|
|
499
611
|
locals,
|
|
612
|
+
imports,
|
|
500
613
|
unresolved
|
|
501
614
|
};
|
|
502
615
|
};
|
|
@@ -504,10 +617,34 @@ const collectReferences = scope => {
|
|
|
504
617
|
const scopeHasLocalReference = (scope, referenceName) => {
|
|
505
618
|
const references = collectReferences(scope);
|
|
506
619
|
return (// referenceName was found as a local variable or function declaration.
|
|
507
|
-
references.locals.has(referenceName) || // referenceName was
|
|
620
|
+
references.locals.has(referenceName) || // referenceName was found as an imported identifier
|
|
621
|
+
references.imports.has(referenceName) || // referenceName was not found as an unresolved reference,
|
|
508
622
|
// meaning it is likely not an implicit global reference.
|
|
509
623
|
!references.unresolved.has(referenceName)
|
|
510
624
|
);
|
|
511
625
|
};
|
|
512
626
|
|
|
513
|
-
exports.scopeHasLocalReference = scopeHasLocalReference;
|
|
627
|
+
exports.scopeHasLocalReference = scopeHasLocalReference;
|
|
628
|
+
|
|
629
|
+
const resolveToJestFn = (scope, identifier) => {
|
|
630
|
+
const references = collectReferences(scope);
|
|
631
|
+
const maybeImport = references.imports.get(identifier);
|
|
632
|
+
|
|
633
|
+
if (maybeImport) {
|
|
634
|
+
// the identifier is imported from @jest/globals,
|
|
635
|
+
// so return the original import name
|
|
636
|
+
if (maybeImport.source === '@jest/globals') {
|
|
637
|
+
return maybeImport.imported;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
return null;
|
|
641
|
+
} // the identifier was found as a local variable or function declaration
|
|
642
|
+
// meaning it's not a function from jest
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
if (references.locals.has(identifier)) {
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
return identifier;
|
|
650
|
+
};
|
|
@@ -52,8 +52,8 @@ const findTopMostCallExpression = node => {
|
|
|
52
52
|
return topMostCallExpression;
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
const isTestCaseCallWithCallbackArg = node => {
|
|
56
|
-
if (!(0, _utils2.isTestCaseCall)(node)) {
|
|
55
|
+
const isTestCaseCallWithCallbackArg = (node, scope) => {
|
|
56
|
+
if (!(0, _utils2.isTestCaseCall)(node, scope)) {
|
|
57
57
|
return false;
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -254,7 +254,7 @@ const findFirstBlockBodyUp = node => {
|
|
|
254
254
|
throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
|
|
255
255
|
};
|
|
256
256
|
|
|
257
|
-
const isDirectlyWithinTestCaseCall = node => {
|
|
257
|
+
const isDirectlyWithinTestCaseCall = (node, scope) => {
|
|
258
258
|
let parent = node;
|
|
259
259
|
|
|
260
260
|
while (parent) {
|
|
@@ -262,7 +262,7 @@ const isDirectlyWithinTestCaseCall = node => {
|
|
|
262
262
|
var _parent;
|
|
263
263
|
|
|
264
264
|
parent = parent.parent;
|
|
265
|
-
return !!(((_parent = parent) === null || _parent === void 0 ? void 0 : _parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTestCaseCall)(parent));
|
|
265
|
+
return !!(((_parent = parent) === null || _parent === void 0 ? void 0 : _parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTestCaseCall)(parent, scope));
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
parent = parent.parent;
|
|
@@ -312,7 +312,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
312
312
|
CallExpression(node) {
|
|
313
313
|
// there are too many ways that the done argument could be used with
|
|
314
314
|
// promises that contain expect that would make the promise safe for us
|
|
315
|
-
if (isTestCaseCallWithCallbackArg(node)) {
|
|
315
|
+
if (isTestCaseCallWithCallbackArg(node, context.getScope())) {
|
|
316
316
|
inTestCaseWithDoneCallback = true;
|
|
317
317
|
return;
|
|
318
318
|
} // if this call expression is a promise chain, add it to the stack with
|
|
@@ -336,7 +336,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
336
336
|
// make promises containing expects safe in a test for us to be able to
|
|
337
337
|
// accurately check, so we just bail out completely if it's present
|
|
338
338
|
if (inTestCaseWithDoneCallback) {
|
|
339
|
-
if ((0, _utils2.isTestCaseCall)(node)) {
|
|
339
|
+
if ((0, _utils2.isTestCaseCall)(node, context.getScope())) {
|
|
340
340
|
inTestCaseWithDoneCallback = false;
|
|
341
341
|
}
|
|
342
342
|
|
|
@@ -363,7 +363,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
363
363
|
// because we're most likely in the body of a function being defined
|
|
364
364
|
// within the test, which we can't track
|
|
365
365
|
|
|
366
|
-
if (!parent || !isDirectlyWithinTestCaseCall(parent)) {
|
|
366
|
+
if (!parent || !isDirectlyWithinTestCaseCall(parent, context.getScope())) {
|
|
367
367
|
return;
|
|
368
368
|
}
|
|
369
369
|
|
package/lib/rules/valid-title.js
CHANGED
|
@@ -130,7 +130,9 @@ var _default = (0, _utils2.createRule)({
|
|
|
130
130
|
CallExpression(node) {
|
|
131
131
|
var _mustNotMatchPatterns, _mustMatchPatterns$je;
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
const scope = context.getScope();
|
|
134
|
+
|
|
135
|
+
if (!(0, _utils2.isDescribeCall)(node, scope) && !(0, _utils2.isTestCaseCall)(node, scope)) {
|
|
134
136
|
return;
|
|
135
137
|
}
|
|
136
138
|
|
|
@@ -145,7 +147,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
145
147
|
return;
|
|
146
148
|
}
|
|
147
149
|
|
|
148
|
-
if (argument.type !== _utils.AST_NODE_TYPES.TemplateLiteral && !(ignoreTypeOfDescribeName && (0, _utils2.isDescribeCall)(node))) {
|
|
150
|
+
if (argument.type !== _utils.AST_NODE_TYPES.TemplateLiteral && !(ignoreTypeOfDescribeName && (0, _utils2.isDescribeCall)(node, scope))) {
|
|
149
151
|
context.report({
|
|
150
152
|
messageId: 'titleMustBeString',
|
|
151
153
|
loc: argument.loc
|
|
@@ -161,7 +163,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
161
163
|
context.report({
|
|
162
164
|
messageId: 'emptyTitle',
|
|
163
165
|
data: {
|
|
164
|
-
jestFunctionName: (0, _utils2.isDescribeCall)(node) ? _utils2.DescribeAlias.describe : _utils2.TestCaseName.test
|
|
166
|
+
jestFunctionName: (0, _utils2.isDescribeCall)(node, scope) ? _utils2.DescribeAlias.describe : _utils2.TestCaseName.test
|
|
165
167
|
},
|
|
166
168
|
node
|
|
167
169
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-jest",
|
|
3
|
-
"version": "26.1
|
|
3
|
+
"version": "26.2.1",
|
|
4
4
|
"description": "ESLint rules for Jest",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"eslint",
|
|
@@ -60,9 +60,6 @@
|
|
|
60
60
|
"projects": [
|
|
61
61
|
{
|
|
62
62
|
"displayName": "test",
|
|
63
|
-
"moduleNameMapper": {
|
|
64
|
-
"eslint/use-at-your-own-risk": "eslint/lib/unsupported-api.js"
|
|
65
|
-
},
|
|
66
63
|
"testPathIgnorePatterns": [
|
|
67
64
|
"<rootDir>/lib/.*",
|
|
68
65
|
"<rootDir>/src/rules/__tests__/fixtures/*",
|
|
@@ -100,7 +97,7 @@
|
|
|
100
97
|
"@types/prettier": "^2.0.0",
|
|
101
98
|
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
|
102
99
|
"@typescript-eslint/parser": "^5.0.0",
|
|
103
|
-
"babel-jest": "^
|
|
100
|
+
"babel-jest": "^28.0.0",
|
|
104
101
|
"babel-plugin-replace-ts-export-assignment": "^0.0.2",
|
|
105
102
|
"dedent": "^0.7.0",
|
|
106
103
|
"eslint": "^6.0.0 || ^7.0.0 || ^8.0.0",
|
|
@@ -111,11 +108,11 @@
|
|
|
111
108
|
"eslint-plugin-import": "^2.25.1",
|
|
112
109
|
"eslint-plugin-node": "^11.0.0",
|
|
113
110
|
"eslint-plugin-prettier": "^3.4.1",
|
|
114
|
-
"eslint-remote-tester": "^2.1.
|
|
111
|
+
"eslint-remote-tester": "^2.1.3",
|
|
115
112
|
"eslint-remote-tester-repositories": "^0.0.5",
|
|
116
113
|
"husky": "^7.0.2",
|
|
117
114
|
"is-ci": "^3.0.0",
|
|
118
|
-
"jest": "^
|
|
115
|
+
"jest": "^28.0.0",
|
|
119
116
|
"jest-runner-eslint": "^1.0.0",
|
|
120
117
|
"lint-staged": "^12.0.0",
|
|
121
118
|
"pinst": "^3.0.0",
|
|
@@ -163,5 +160,5 @@
|
|
|
163
160
|
"@typescript-eslint/experimental-utils": "^5.0.0",
|
|
164
161
|
"fsevents/node-gyp": "^7.0.0"
|
|
165
162
|
},
|
|
166
|
-
"packageManager": "yarn@3.2.
|
|
163
|
+
"packageManager": "yarn@3.2.1"
|
|
167
164
|
}
|