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,149 +4,113 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.getNodeChain = getNodeChain;
|
|
7
|
-
exports.
|
|
8
|
-
|
|
7
|
+
exports.resolveScope = exports.parseJestFnCallWithReason = exports.parseJestFnCall = exports.isTypeOfJestFnCall = void 0;
|
|
9
8
|
var _utils = require("@typescript-eslint/utils");
|
|
10
|
-
|
|
11
9
|
var _utils2 = require("../utils");
|
|
12
|
-
|
|
13
10
|
const isTypeOfJestFnCall = (node, context, types) => {
|
|
14
11
|
const jestFnCall = parseJestFnCall(node, context);
|
|
15
12
|
return jestFnCall !== null && types.includes(jestFnCall.type);
|
|
16
13
|
};
|
|
17
|
-
|
|
18
14
|
exports.isTypeOfJestFnCall = isTypeOfJestFnCall;
|
|
19
|
-
|
|
20
15
|
const joinChains = (a, b) => a && b ? [...a, ...b] : null;
|
|
21
|
-
|
|
22
16
|
function getNodeChain(node) {
|
|
23
17
|
if ((0, _utils2.isSupportedAccessor)(node)) {
|
|
24
18
|
return [node];
|
|
25
19
|
}
|
|
26
|
-
|
|
27
20
|
switch (node.type) {
|
|
28
21
|
case _utils.AST_NODE_TYPES.TaggedTemplateExpression:
|
|
29
22
|
return getNodeChain(node.tag);
|
|
30
|
-
|
|
31
23
|
case _utils.AST_NODE_TYPES.MemberExpression:
|
|
32
24
|
return joinChains(getNodeChain(node.object), getNodeChain(node.property));
|
|
33
|
-
|
|
34
25
|
case _utils.AST_NODE_TYPES.CallExpression:
|
|
35
26
|
return getNodeChain(node.callee);
|
|
36
27
|
}
|
|
37
|
-
|
|
38
28
|
return null;
|
|
39
29
|
}
|
|
40
|
-
|
|
41
30
|
const determineJestFnType = name => {
|
|
42
31
|
if (name === 'expect') {
|
|
43
32
|
return 'expect';
|
|
44
33
|
}
|
|
45
|
-
|
|
46
34
|
if (name === 'jest') {
|
|
47
35
|
return 'jest';
|
|
48
36
|
}
|
|
49
|
-
|
|
50
37
|
if (_utils2.DescribeAlias.hasOwnProperty(name)) {
|
|
51
38
|
return 'describe';
|
|
52
39
|
}
|
|
53
|
-
|
|
54
40
|
if (_utils2.TestCaseName.hasOwnProperty(name)) {
|
|
55
41
|
return 'test';
|
|
56
42
|
}
|
|
57
|
-
/* istanbul ignore else */
|
|
58
|
-
|
|
59
43
|
|
|
44
|
+
/* istanbul ignore else */
|
|
60
45
|
if (_utils2.HookName.hasOwnProperty(name)) {
|
|
61
46
|
return 'hook';
|
|
62
47
|
}
|
|
63
|
-
/* istanbul ignore next */
|
|
64
|
-
|
|
65
48
|
|
|
49
|
+
/* istanbul ignore next */
|
|
66
50
|
return 'unknown';
|
|
67
51
|
};
|
|
68
|
-
|
|
69
52
|
const ValidJestFnCallChains = ['afterAll', 'afterEach', 'beforeAll', 'beforeEach', 'describe', 'describe.each', 'describe.only', 'describe.only.each', 'describe.skip', 'describe.skip.each', 'fdescribe', 'fdescribe.each', 'xdescribe', 'xdescribe.each', 'it', 'it.concurrent', 'it.concurrent.each', 'it.concurrent.only.each', 'it.concurrent.skip.each', 'it.each', 'it.failing', 'it.only', 'it.only.each', 'it.only.failing', 'it.skip', 'it.skip.each', 'it.skip.failing', 'it.todo', 'fit', 'fit.each', 'fit.failing', 'xit', 'xit.each', 'xit.failing', 'test', 'test.concurrent', 'test.concurrent.each', 'test.concurrent.only.each', 'test.concurrent.skip.each', 'test.each', 'test.failing', 'test.only', 'test.only.each', 'test.only.failing', 'test.skip', 'test.skip.each', 'test.skip.failing', 'test.todo', 'xtest', 'xtest.each', 'xtest.failing'];
|
|
70
|
-
|
|
71
53
|
const resolvePossibleAliasedGlobal = (global, context) => {
|
|
72
|
-
var _context$settings$jes
|
|
73
|
-
|
|
74
|
-
const globalAliases = (_context$settings$jes = (_context$settings$jes2 = context.settings.jest) === null || _context$settings$jes2 === void 0 ? void 0 : _context$settings$jes2.globalAliases) !== null && _context$settings$jes !== void 0 ? _context$settings$jes : {};
|
|
54
|
+
var _context$settings$jes;
|
|
55
|
+
const globalAliases = ((_context$settings$jes = context.settings.jest) === null || _context$settings$jes === void 0 ? void 0 : _context$settings$jes.globalAliases) ?? {};
|
|
75
56
|
const alias = Object.entries(globalAliases).find(([, aliases]) => aliases.includes(global));
|
|
76
|
-
|
|
77
57
|
if (alias) {
|
|
78
58
|
return alias[0];
|
|
79
59
|
}
|
|
80
|
-
|
|
81
60
|
return null;
|
|
82
61
|
};
|
|
83
|
-
|
|
84
62
|
const parseJestFnCallCache = new WeakMap();
|
|
85
|
-
|
|
86
63
|
const parseJestFnCall = (node, context) => {
|
|
87
64
|
const jestFnCall = parseJestFnCallWithReason(node, context);
|
|
88
|
-
|
|
89
65
|
if (typeof jestFnCall === 'string') {
|
|
90
66
|
return null;
|
|
91
67
|
}
|
|
92
|
-
|
|
93
68
|
return jestFnCall;
|
|
94
69
|
};
|
|
95
|
-
|
|
96
70
|
exports.parseJestFnCall = parseJestFnCall;
|
|
97
|
-
|
|
98
71
|
const parseJestFnCallWithReason = (node, context) => {
|
|
99
72
|
let parsedJestFnCall = parseJestFnCallCache.get(node);
|
|
100
|
-
|
|
101
73
|
if (parsedJestFnCall) {
|
|
102
74
|
return parsedJestFnCall;
|
|
103
75
|
}
|
|
104
|
-
|
|
105
76
|
parsedJestFnCall = parseJestFnCallWithReasonInner(node, context);
|
|
106
77
|
parseJestFnCallCache.set(node, parsedJestFnCall);
|
|
107
78
|
return parsedJestFnCall;
|
|
108
79
|
};
|
|
109
|
-
|
|
110
80
|
exports.parseJestFnCallWithReason = parseJestFnCallWithReason;
|
|
111
|
-
|
|
112
81
|
const parseJestFnCallWithReasonInner = (node, context) => {
|
|
113
|
-
var
|
|
114
|
-
|
|
82
|
+
var _node$parent2, _node$parent3;
|
|
115
83
|
const chain = getNodeChain(node);
|
|
116
|
-
|
|
117
84
|
if (!(chain !== null && chain !== void 0 && chain.length)) {
|
|
118
85
|
return null;
|
|
119
86
|
}
|
|
120
|
-
|
|
121
87
|
const [first, ...rest] = chain;
|
|
122
|
-
const lastLink = (0, _utils2.getAccessorValue)(chain[chain.length - 1]);
|
|
88
|
+
const lastLink = (0, _utils2.getAccessorValue)(chain[chain.length - 1]);
|
|
123
89
|
|
|
90
|
+
// if we're an `each()`, ensure we're the outer CallExpression (i.e `.each()()`)
|
|
124
91
|
if (lastLink === 'each') {
|
|
125
92
|
if (node.callee.type !== _utils.AST_NODE_TYPES.CallExpression && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression) {
|
|
126
93
|
return null;
|
|
127
94
|
}
|
|
128
95
|
}
|
|
129
|
-
|
|
130
96
|
if (node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression && lastLink !== 'each') {
|
|
131
97
|
return null;
|
|
132
98
|
}
|
|
99
|
+
const resolved = resolveToJestFn(context, (0, _utils2.getAccessorValue)(first));
|
|
133
100
|
|
|
134
|
-
|
|
135
|
-
|
|
101
|
+
// we're not a jest function
|
|
136
102
|
if (!resolved) {
|
|
137
103
|
return null;
|
|
138
104
|
}
|
|
139
|
-
|
|
140
|
-
const name = (_resolved$original = resolved.original) !== null && _resolved$original !== void 0 ? _resolved$original : resolved.local;
|
|
105
|
+
const name = resolved.original ?? resolved.local;
|
|
141
106
|
const links = [name, ...rest.map(link => (0, _utils2.getAccessorValue)(link))];
|
|
142
|
-
|
|
143
107
|
if (name !== 'jest' && name !== 'expect' && !ValidJestFnCallChains.includes(links.join('.'))) {
|
|
144
108
|
return null;
|
|
145
109
|
}
|
|
146
|
-
|
|
147
110
|
const parsedJestFnCall = {
|
|
148
111
|
name,
|
|
149
|
-
head: {
|
|
112
|
+
head: {
|
|
113
|
+
...resolved,
|
|
150
114
|
node: first
|
|
151
115
|
},
|
|
152
116
|
// every member node must have a member expression as their parent
|
|
@@ -154,53 +118,46 @@ const parseJestFnCallWithReasonInner = (node, context) => {
|
|
|
154
118
|
members: rest
|
|
155
119
|
};
|
|
156
120
|
const type = determineJestFnType(name);
|
|
157
|
-
|
|
158
121
|
if (type === 'expect') {
|
|
159
|
-
const result = parseJestExpectCall(parsedJestFnCall);
|
|
160
|
-
// since all members in the chain are likely to get flagged for some reason
|
|
122
|
+
const result = parseJestExpectCall(parsedJestFnCall);
|
|
161
123
|
|
|
124
|
+
// if the `expect` call chain is not valid, only report on the topmost node
|
|
125
|
+
// since all members in the chain are likely to get flagged for some reason
|
|
162
126
|
if (typeof result === 'string' && (0, _utils2.findTopMostCallExpression)(node) !== node) {
|
|
163
127
|
return null;
|
|
164
128
|
}
|
|
165
|
-
|
|
166
129
|
if (result === 'matcher-not-found') {
|
|
167
130
|
var _node$parent;
|
|
168
|
-
|
|
169
131
|
if (((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) === _utils.AST_NODE_TYPES.MemberExpression) {
|
|
170
132
|
return 'matcher-not-called';
|
|
171
133
|
}
|
|
172
134
|
}
|
|
173
|
-
|
|
174
135
|
return result;
|
|
175
|
-
}
|
|
176
|
-
|
|
136
|
+
}
|
|
177
137
|
|
|
138
|
+
// check that every link in the chain except the last is a member expression
|
|
178
139
|
if (chain.slice(0, chain.length - 1).some(nod => {
|
|
179
140
|
var _nod$parent;
|
|
180
|
-
|
|
181
141
|
return ((_nod$parent = nod.parent) === null || _nod$parent === void 0 ? void 0 : _nod$parent.type) !== _utils.AST_NODE_TYPES.MemberExpression;
|
|
182
142
|
})) {
|
|
183
143
|
return null;
|
|
184
|
-
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ensure that we're at the "top" of the function call chain otherwise when
|
|
185
147
|
// parsing e.g. x().y.z(), we'll incorrectly find & parse "x()" even though
|
|
186
148
|
// the full chain is not a valid jest function call chain
|
|
187
|
-
|
|
188
|
-
|
|
189
149
|
if (((_node$parent2 = node.parent) === null || _node$parent2 === void 0 ? void 0 : _node$parent2.type) === _utils.AST_NODE_TYPES.CallExpression || ((_node$parent3 = node.parent) === null || _node$parent3 === void 0 ? void 0 : _node$parent3.type) === _utils.AST_NODE_TYPES.MemberExpression) {
|
|
190
150
|
return null;
|
|
191
151
|
}
|
|
192
|
-
|
|
193
|
-
|
|
152
|
+
return {
|
|
153
|
+
...parsedJestFnCall,
|
|
194
154
|
type
|
|
195
155
|
};
|
|
196
156
|
};
|
|
197
|
-
|
|
198
157
|
const findModifiersAndMatcher = members => {
|
|
199
158
|
const modifiers = [];
|
|
200
|
-
|
|
201
159
|
for (const member of members) {
|
|
202
160
|
var _member$parent, _member$parent$parent;
|
|
203
|
-
|
|
204
161
|
// check if the member is being called, which means it is the matcher
|
|
205
162
|
// (and also the end of the entire "expect" call chain)
|
|
206
163
|
if (((_member$parent = member.parent) === null || _member$parent === void 0 ? void 0 : _member$parent.type) === _utils.AST_NODE_TYPES.MemberExpression && ((_member$parent$parent = member.parent.parent) === null || _member$parent$parent === void 0 ? void 0 : _member$parent$parent.type) === _utils.AST_NODE_TYPES.CallExpression) {
|
|
@@ -209,11 +166,10 @@ const findModifiersAndMatcher = members => {
|
|
|
209
166
|
args: member.parent.parent.arguments,
|
|
210
167
|
modifiers
|
|
211
168
|
};
|
|
212
|
-
}
|
|
213
|
-
|
|
169
|
+
}
|
|
214
170
|
|
|
171
|
+
// otherwise, it should be a modifier
|
|
215
172
|
const name = (0, _utils2.getAccessorValue)(member);
|
|
216
|
-
|
|
217
173
|
if (modifiers.length === 0) {
|
|
218
174
|
// the first modifier can be any of the three modifiers
|
|
219
175
|
if (!_utils2.ModifierName.hasOwnProperty(name)) {
|
|
@@ -224,56 +180,51 @@ const findModifiersAndMatcher = members => {
|
|
|
224
180
|
if (name !== _utils2.ModifierName.not) {
|
|
225
181
|
return 'modifier-unknown';
|
|
226
182
|
}
|
|
183
|
+
const firstModifier = (0, _utils2.getAccessorValue)(modifiers[0]);
|
|
227
184
|
|
|
228
|
-
|
|
229
|
-
|
|
185
|
+
// and the first modifier has to be either "resolves" or "rejects"
|
|
230
186
|
if (firstModifier !== _utils2.ModifierName.resolves && firstModifier !== _utils2.ModifierName.rejects) {
|
|
231
187
|
return 'modifier-unknown';
|
|
232
188
|
}
|
|
233
189
|
} else {
|
|
234
190
|
return 'modifier-unknown';
|
|
235
191
|
}
|
|
236
|
-
|
|
237
192
|
modifiers.push(member);
|
|
238
|
-
}
|
|
239
|
-
|
|
193
|
+
}
|
|
240
194
|
|
|
195
|
+
// this will only really happen if there are no members
|
|
241
196
|
return 'matcher-not-found';
|
|
242
197
|
};
|
|
243
|
-
|
|
244
198
|
const parseJestExpectCall = typelessParsedJestFnCall => {
|
|
245
199
|
const modifiersAndMatcher = findModifiersAndMatcher(typelessParsedJestFnCall.members);
|
|
246
|
-
|
|
247
200
|
if (typeof modifiersAndMatcher === 'string') {
|
|
248
201
|
return modifiersAndMatcher;
|
|
249
202
|
}
|
|
250
|
-
|
|
251
|
-
|
|
203
|
+
return {
|
|
204
|
+
...typelessParsedJestFnCall,
|
|
252
205
|
type: 'expect',
|
|
253
206
|
...modifiersAndMatcher
|
|
254
207
|
};
|
|
255
208
|
};
|
|
256
|
-
|
|
257
209
|
const describeImportDefAsImport = def => {
|
|
258
210
|
if (def.parent.type === _utils.AST_NODE_TYPES.TSImportEqualsDeclaration) {
|
|
259
211
|
return null;
|
|
260
212
|
}
|
|
261
|
-
|
|
262
213
|
if (def.node.type !== _utils.AST_NODE_TYPES.ImportSpecifier) {
|
|
263
214
|
return null;
|
|
264
|
-
}
|
|
265
|
-
|
|
215
|
+
}
|
|
266
216
|
|
|
217
|
+
// we only care about value imports
|
|
267
218
|
if (def.parent.importKind === 'type') {
|
|
268
219
|
return null;
|
|
269
220
|
}
|
|
270
|
-
|
|
271
221
|
return {
|
|
272
222
|
source: def.parent.source.value,
|
|
273
223
|
imported: def.node.imported.name,
|
|
274
224
|
local: def.node.local.name
|
|
275
225
|
};
|
|
276
226
|
};
|
|
227
|
+
|
|
277
228
|
/**
|
|
278
229
|
* Attempts to find the node that represents the import source for the
|
|
279
230
|
* given expression node, if it looks like it's an import.
|
|
@@ -281,54 +232,41 @@ const describeImportDefAsImport = def => {
|
|
|
281
232
|
* If no such node can be found (e.g. because the expression doesn't look
|
|
282
233
|
* like an import), then `null` is returned instead.
|
|
283
234
|
*/
|
|
284
|
-
|
|
285
|
-
|
|
286
235
|
const findImportSourceNode = node => {
|
|
287
236
|
if (node.type === _utils.AST_NODE_TYPES.AwaitExpression) {
|
|
288
237
|
if (node.argument.type === _utils.AST_NODE_TYPES.ImportExpression) {
|
|
289
238
|
return node.argument.source;
|
|
290
239
|
}
|
|
291
|
-
|
|
292
240
|
return null;
|
|
293
241
|
}
|
|
294
|
-
|
|
295
242
|
if (node.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isIdentifier)(node.callee, 'require')) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
return (_node$arguments$ = node.arguments[0]) !== null && _node$arguments$ !== void 0 ? _node$arguments$ : null;
|
|
243
|
+
return node.arguments[0] ?? null;
|
|
299
244
|
}
|
|
300
|
-
|
|
301
245
|
return null;
|
|
302
246
|
};
|
|
303
|
-
|
|
304
247
|
const describeVariableDefAsImport = def => {
|
|
305
248
|
var _def$name$parent;
|
|
306
|
-
|
|
307
249
|
// make sure that we've actually being assigned a value
|
|
308
250
|
if (!def.node.init) {
|
|
309
251
|
return null;
|
|
310
252
|
}
|
|
311
|
-
|
|
312
253
|
const sourceNode = findImportSourceNode(def.node.init);
|
|
313
|
-
|
|
314
254
|
if (!sourceNode || !(0, _utils2.isStringNode)(sourceNode)) {
|
|
315
255
|
return null;
|
|
316
256
|
}
|
|
317
|
-
|
|
318
257
|
if (((_def$name$parent = def.name.parent) === null || _def$name$parent === void 0 ? void 0 : _def$name$parent.type) !== _utils.AST_NODE_TYPES.Property) {
|
|
319
258
|
return null;
|
|
320
259
|
}
|
|
321
|
-
|
|
322
260
|
if (!(0, _utils2.isSupportedAccessor)(def.name.parent.key)) {
|
|
323
261
|
return null;
|
|
324
262
|
}
|
|
325
|
-
|
|
326
263
|
return {
|
|
327
264
|
source: (0, _utils2.getStringValue)(sourceNode),
|
|
328
265
|
imported: (0, _utils2.getAccessorValue)(def.name.parent.key),
|
|
329
266
|
local: def.name.name
|
|
330
267
|
};
|
|
331
268
|
};
|
|
269
|
+
|
|
332
270
|
/**
|
|
333
271
|
* Attempts to describe a definition as an import if possible.
|
|
334
272
|
*
|
|
@@ -339,61 +277,40 @@ const describeVariableDefAsImport = def => {
|
|
|
339
277
|
* If it's neither of these, `null` is returned to indicate that the definition
|
|
340
278
|
* is not describable as an import of any kind.
|
|
341
279
|
*/
|
|
342
|
-
|
|
343
|
-
|
|
344
280
|
const describePossibleImportDef = def => {
|
|
345
281
|
if (def.type === 'Variable') {
|
|
346
282
|
return describeVariableDefAsImport(def);
|
|
347
283
|
}
|
|
348
|
-
|
|
349
284
|
if (def.type === 'ImportBinding') {
|
|
350
285
|
return describeImportDefAsImport(def);
|
|
351
286
|
}
|
|
352
|
-
|
|
353
287
|
return null;
|
|
354
288
|
};
|
|
355
|
-
|
|
356
|
-
const collectReferences = scope => {
|
|
357
|
-
const locals = new Set();
|
|
358
|
-
const imports = new Map();
|
|
359
|
-
const unresolved = new Set();
|
|
289
|
+
const resolveScope = (scope, identifier) => {
|
|
360
290
|
let currentScope = scope;
|
|
361
|
-
|
|
362
291
|
while (currentScope !== null) {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
|
|
292
|
+
const ref = currentScope.set.get(identifier);
|
|
293
|
+
if (ref && ref.defs.length > 0) {
|
|
368
294
|
const def = ref.defs[ref.defs.length - 1];
|
|
369
295
|
const importDetails = describePossibleImportDef(def);
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
imports.set(importDetails.local, importDetails);
|
|
373
|
-
continue;
|
|
296
|
+
if ((importDetails === null || importDetails === void 0 ? void 0 : importDetails.local) === identifier) {
|
|
297
|
+
return importDetails;
|
|
374
298
|
}
|
|
375
|
-
|
|
376
|
-
locals.add(ref.name);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
for (const ref of currentScope.through) {
|
|
380
|
-
unresolved.add(ref.identifier.name);
|
|
299
|
+
return 'local';
|
|
381
300
|
}
|
|
382
|
-
|
|
383
301
|
currentScope = currentScope.upper;
|
|
384
302
|
}
|
|
385
|
-
|
|
386
|
-
return {
|
|
387
|
-
locals,
|
|
388
|
-
imports,
|
|
389
|
-
unresolved
|
|
390
|
-
};
|
|
303
|
+
return null;
|
|
391
304
|
};
|
|
392
|
-
|
|
305
|
+
exports.resolveScope = resolveScope;
|
|
393
306
|
const resolveToJestFn = (context, identifier) => {
|
|
394
|
-
const
|
|
395
|
-
const maybeImport = references.imports.get(identifier);
|
|
307
|
+
const maybeImport = resolveScope(context.getScope(), identifier);
|
|
396
308
|
|
|
309
|
+
// the identifier was found as a local variable or function declaration
|
|
310
|
+
// meaning it's not a function from jest
|
|
311
|
+
if (maybeImport === 'local') {
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
397
314
|
if (maybeImport) {
|
|
398
315
|
// the identifier is imported from @jest/globals,
|
|
399
316
|
// so return the original import name
|
|
@@ -404,31 +321,11 @@ const resolveToJestFn = (context, identifier) => {
|
|
|
404
321
|
type: 'import'
|
|
405
322
|
};
|
|
406
323
|
}
|
|
407
|
-
|
|
408
|
-
return null;
|
|
409
|
-
} // the identifier was found as a local variable or function declaration
|
|
410
|
-
// meaning it's not a function from jest
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
if (references.locals.has(identifier)) {
|
|
414
324
|
return null;
|
|
415
325
|
}
|
|
416
|
-
|
|
417
326
|
return {
|
|
418
327
|
original: resolvePossibleAliasedGlobal(identifier, context),
|
|
419
328
|
local: identifier,
|
|
420
329
|
type: 'global'
|
|
421
330
|
};
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
const scopeHasLocalReference = (scope, referenceName) => {
|
|
425
|
-
const references = collectReferences(scope);
|
|
426
|
-
return (// referenceName was found as a local variable or function declaration.
|
|
427
|
-
references.locals.has(referenceName) || // referenceName was found as an imported identifier
|
|
428
|
-
references.imports.has(referenceName) || // referenceName was not found as an unresolved reference,
|
|
429
|
-
// meaning it is likely not an implicit global reference.
|
|
430
|
-
!references.unresolved.has(referenceName)
|
|
431
|
-
);
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
exports.scopeHasLocalReference = scopeHasLocalReference;
|
|
331
|
+
};
|
|
@@ -4,11 +4,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _utils = require("@typescript-eslint/utils");
|
|
9
|
-
|
|
10
8
|
var _utils2 = require("./utils");
|
|
11
|
-
|
|
12
9
|
const paramsLocation = params => {
|
|
13
10
|
const [first] = params;
|
|
14
11
|
const last = params[params.length - 1];
|
|
@@ -17,7 +14,6 @@ const paramsLocation = params => {
|
|
|
17
14
|
end: last.loc.end
|
|
18
15
|
};
|
|
19
16
|
};
|
|
20
|
-
|
|
21
17
|
var _default = (0, _utils2.createRule)({
|
|
22
18
|
name: __filename,
|
|
23
19
|
meta: {
|
|
@@ -37,25 +33,20 @@ var _default = (0, _utils2.createRule)({
|
|
|
37
33
|
schema: []
|
|
38
34
|
},
|
|
39
35
|
defaultOptions: [],
|
|
40
|
-
|
|
41
36
|
create(context) {
|
|
42
37
|
return {
|
|
43
38
|
CallExpression(node) {
|
|
44
39
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
45
|
-
|
|
46
40
|
if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe') {
|
|
47
41
|
return;
|
|
48
42
|
}
|
|
49
|
-
|
|
50
43
|
if (node.arguments.length < 1) {
|
|
51
44
|
return context.report({
|
|
52
45
|
messageId: 'nameAndCallback',
|
|
53
46
|
loc: node.loc
|
|
54
47
|
});
|
|
55
48
|
}
|
|
56
|
-
|
|
57
49
|
const [, callback] = node.arguments;
|
|
58
|
-
|
|
59
50
|
if (!callback) {
|
|
60
51
|
context.report({
|
|
61
52
|
messageId: 'nameAndCallback',
|
|
@@ -63,7 +54,6 @@ var _default = (0, _utils2.createRule)({
|
|
|
63
54
|
});
|
|
64
55
|
return;
|
|
65
56
|
}
|
|
66
|
-
|
|
67
57
|
if (!(0, _utils2.isFunction)(callback)) {
|
|
68
58
|
context.report({
|
|
69
59
|
messageId: 'secondArgumentMustBeFunction',
|
|
@@ -71,28 +61,24 @@ var _default = (0, _utils2.createRule)({
|
|
|
71
61
|
});
|
|
72
62
|
return;
|
|
73
63
|
}
|
|
74
|
-
|
|
75
64
|
if (callback.async) {
|
|
76
65
|
context.report({
|
|
77
66
|
messageId: 'noAsyncDescribeCallback',
|
|
78
67
|
node: callback
|
|
79
68
|
});
|
|
80
69
|
}
|
|
81
|
-
|
|
82
70
|
if (jestFnCall.members.every(s => (0, _utils2.getAccessorValue)(s) !== 'each') && callback.params.length) {
|
|
83
71
|
context.report({
|
|
84
72
|
messageId: 'unexpectedDescribeArgument',
|
|
85
73
|
loc: paramsLocation(callback.params)
|
|
86
74
|
});
|
|
87
75
|
}
|
|
88
|
-
|
|
89
76
|
if (callback.body.type === _utils.AST_NODE_TYPES.CallExpression) {
|
|
90
77
|
context.report({
|
|
91
78
|
messageId: 'unexpectedReturnInDescribe',
|
|
92
79
|
node: callback
|
|
93
80
|
});
|
|
94
81
|
}
|
|
95
|
-
|
|
96
82
|
if (callback.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
|
|
97
83
|
callback.body.body.forEach(node => {
|
|
98
84
|
if (node.type === _utils.AST_NODE_TYPES.ReturnStatement) {
|
|
@@ -104,10 +90,7 @@ var _default = (0, _utils2.createRule)({
|
|
|
104
90
|
});
|
|
105
91
|
}
|
|
106
92
|
}
|
|
107
|
-
|
|
108
93
|
};
|
|
109
94
|
}
|
|
110
|
-
|
|
111
95
|
});
|
|
112
|
-
|
|
113
96
|
exports.default = _default;
|