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.
Files changed (59) hide show
  1. package/README.md +50 -2
  2. package/docs/rules/no-conditional-expect.md +1 -1
  3. package/docs/rules/no-deprecated-functions.md +1 -2
  4. package/docs/rules/no-identical-title.md +1 -1
  5. package/docs/rules/no-jasmine-globals.md +2 -2
  6. package/docs/rules/no-jest-import.md +1 -1
  7. package/docs/rules/no-large-snapshots.md +2 -2
  8. package/docs/rules/no-standalone-expect.md +1 -1
  9. package/docs/rules/prefer-comparison-matcher.md +1 -1
  10. package/docs/rules/prefer-equality-matcher.md +1 -1
  11. package/docs/rules/prefer-expect-assertions.md +1 -1
  12. package/docs/rules/prefer-hooks-in-order.md +133 -0
  13. package/docs/rules/prefer-hooks-on-top.md +1 -1
  14. package/docs/rules/prefer-lowercase-title.md +2 -2
  15. package/docs/rules/valid-expect.md +2 -2
  16. package/lib/rules/consistent-test-it.js +9 -8
  17. package/lib/rules/expect-expect.js +4 -4
  18. package/lib/rules/max-nested-describe.js +2 -2
  19. package/lib/rules/no-alias-methods.js +1 -1
  20. package/lib/rules/no-conditional-expect.js +3 -3
  21. package/lib/rules/no-conditional-in-test.js +2 -2
  22. package/lib/rules/no-deprecated-functions.js +1 -3
  23. package/lib/rules/no-disabled-tests.js +36 -61
  24. package/lib/rules/no-done-callback.js +6 -4
  25. package/lib/rules/no-duplicate-hooks.js +23 -23
  26. package/lib/rules/no-export.js +1 -1
  27. package/lib/rules/no-focused-tests.js +40 -43
  28. package/lib/rules/no-hooks.js +4 -2
  29. package/lib/rules/no-identical-title.js +10 -7
  30. package/lib/rules/no-if.js +6 -4
  31. package/lib/rules/no-restricted-matchers.js +39 -43
  32. package/lib/rules/no-standalone-expect.js +5 -5
  33. package/lib/rules/no-test-prefixes.js +12 -20
  34. package/lib/rules/no-test-return-statement.js +5 -2
  35. package/lib/rules/prefer-called-with.js +14 -13
  36. package/lib/rules/prefer-comparison-matcher.js +9 -4
  37. package/lib/rules/prefer-equality-matcher.js +15 -5
  38. package/lib/rules/prefer-expect-assertions.js +4 -2
  39. package/lib/rules/prefer-hooks-in-order.js +84 -0
  40. package/lib/rules/prefer-hooks-on-top.js +2 -2
  41. package/lib/rules/prefer-lowercase-title.js +12 -22
  42. package/lib/rules/prefer-snapshot-hint.js +34 -3
  43. package/lib/rules/prefer-strict-equal.js +1 -1
  44. package/lib/rules/prefer-to-be.js +1 -1
  45. package/lib/rules/prefer-todo.js +22 -7
  46. package/lib/rules/require-hook.js +7 -7
  47. package/lib/rules/require-top-level-describe.js +10 -4
  48. package/lib/rules/utils/accessors.js +135 -0
  49. package/lib/rules/{detectJestVersion.js → utils/detectJestVersion.js} +0 -0
  50. package/lib/rules/utils/followTypeAssertionChain.js +14 -0
  51. package/lib/rules/utils/index.js +83 -0
  52. package/lib/rules/utils/misc.js +120 -0
  53. package/lib/rules/utils/parseExpectCall.js +145 -0
  54. package/lib/rules/utils/parseJestFnCall.js +323 -0
  55. package/lib/rules/valid-describe-callback.js +4 -2
  56. package/lib/rules/valid-expect-in-promise.js +13 -15
  57. package/lib/rules/valid-title.js +8 -6
  58. package/package.json +9 -12
  59. package/lib/rules/utils.js +0 -513
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createRule = exports.TestCaseName = exports.HookName = exports.DescribeAlias = void 0;
7
+ exports.getNodeName = getNodeName;
8
+ exports.replaceAccessorFixer = exports.isFunction = exports.hasOnlyOneArgument = exports.getTestCallExpressionsFromDeclaredVariables = void 0;
9
+
10
+ var _path = require("path");
11
+
12
+ var _utils = require("@typescript-eslint/utils");
13
+
14
+ var _package = require("../../../package.json");
15
+
16
+ var _accessors = require("./accessors");
17
+
18
+ var _parseJestFnCall = require("./parseJestFnCall");
19
+
20
+ const REPO_URL = 'https://github.com/jest-community/eslint-plugin-jest';
21
+
22
+ const createRule = _utils.ESLintUtils.RuleCreator(name => {
23
+ const ruleName = (0, _path.parse)(name).name;
24
+ return `${REPO_URL}/blob/v${_package.version}/docs/rules/${ruleName}.md`;
25
+ });
26
+ /**
27
+ * Represents a `MemberExpression` with a "known" `property`.
28
+ */
29
+
30
+
31
+ exports.createRule = createRule;
32
+
33
+ /**
34
+ * Guards that the given `call` has only one `argument`.
35
+ *
36
+ * @param {CallExpression} call
37
+ *
38
+ * @return {call is CallExpressionWithSingleArgument}
39
+ */
40
+ const hasOnlyOneArgument = call => call.arguments.length === 1;
41
+
42
+ exports.hasOnlyOneArgument = hasOnlyOneArgument;
43
+ let DescribeAlias;
44
+ exports.DescribeAlias = DescribeAlias;
45
+
46
+ (function (DescribeAlias) {
47
+ DescribeAlias["describe"] = "describe";
48
+ DescribeAlias["fdescribe"] = "fdescribe";
49
+ DescribeAlias["xdescribe"] = "xdescribe";
50
+ })(DescribeAlias || (exports.DescribeAlias = DescribeAlias = {}));
51
+
52
+ let TestCaseName;
53
+ exports.TestCaseName = TestCaseName;
54
+
55
+ (function (TestCaseName) {
56
+ TestCaseName["fit"] = "fit";
57
+ TestCaseName["it"] = "it";
58
+ TestCaseName["test"] = "test";
59
+ TestCaseName["xit"] = "xit";
60
+ TestCaseName["xtest"] = "xtest";
61
+ })(TestCaseName || (exports.TestCaseName = TestCaseName = {}));
62
+
63
+ let HookName;
64
+ exports.HookName = HookName;
65
+
66
+ (function (HookName) {
67
+ HookName["beforeAll"] = "beforeAll";
68
+ HookName["beforeEach"] = "beforeEach";
69
+ HookName["afterAll"] = "afterAll";
70
+ HookName["afterEach"] = "afterEach";
71
+ })(HookName || (exports.HookName = HookName = {}));
72
+
73
+ const joinNames = (a, b) => a && b ? `${a}.${b}` : null;
74
+
75
+ function getNodeName(node) {
76
+ if ((0, _accessors.isSupportedAccessor)(node)) {
77
+ return (0, _accessors.getAccessorValue)(node);
78
+ }
79
+
80
+ switch (node.type) {
81
+ case _utils.AST_NODE_TYPES.TaggedTemplateExpression:
82
+ return getNodeName(node.tag);
83
+
84
+ case _utils.AST_NODE_TYPES.MemberExpression:
85
+ return joinNames(getNodeName(node.object), getNodeName(node.property));
86
+
87
+ case _utils.AST_NODE_TYPES.NewExpression:
88
+ case _utils.AST_NODE_TYPES.CallExpression:
89
+ return getNodeName(node.callee);
90
+ }
91
+
92
+ return null;
93
+ }
94
+
95
+ const isFunction = node => node.type === _utils.AST_NODE_TYPES.FunctionExpression || node.type === _utils.AST_NODE_TYPES.ArrowFunctionExpression;
96
+
97
+ exports.isFunction = isFunction;
98
+
99
+ const getTestCallExpressionsFromDeclaredVariables = (declaredVariables, context) => {
100
+ return declaredVariables.reduce((acc, {
101
+ references
102
+ }) => acc.concat(references.map(({
103
+ identifier
104
+ }) => identifier.parent).filter(node => (node === null || node === void 0 ? void 0 : node.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _parseJestFnCall.isTypeOfJestFnCall)(node, context, ['test']))), []);
105
+ };
106
+ /**
107
+ * Replaces an accessor node with the given `text`, surrounding it in quotes if required.
108
+ *
109
+ * This ensures that fixes produce valid code when replacing both dot-based and
110
+ * bracket-based property accessors.
111
+ */
112
+
113
+
114
+ exports.getTestCallExpressionsFromDeclaredVariables = getTestCallExpressionsFromDeclaredVariables;
115
+
116
+ const replaceAccessorFixer = (fixer, node, text) => {
117
+ return fixer.replaceText(node, node.type === _utils.AST_NODE_TYPES.Identifier ? text : `'${text}'`);
118
+ };
119
+
120
+ exports.replaceAccessorFixer = replaceAccessorFixer;
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.parseExpectCall = exports.isParsedEqualityMatcherCall = exports.isExpectMember = exports.isExpectCall = exports.ModifierName = exports.EqualityMatcher = void 0;
7
+
8
+ var _utils = require("@typescript-eslint/utils");
9
+
10
+ var _utils2 = require("../utils");
11
+
12
+ /**
13
+ * Checks if the given `node` is a valid `ExpectCall`.
14
+ *
15
+ * In order to be an `ExpectCall`, the `node` must:
16
+ * * be a `CallExpression`,
17
+ * * have an accessor named 'expect',
18
+ * * have a `parent`.
19
+ *
20
+ * @param {Node} node
21
+ *
22
+ * @return {node is ExpectCall}
23
+ */
24
+ const isExpectCall = node => node.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isSupportedAccessor)(node.callee, 'expect') && node.parent !== undefined;
25
+
26
+ exports.isExpectCall = isExpectCall;
27
+
28
+ const isExpectMember = (node, name) => node.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.property, name);
29
+ /**
30
+ * Represents all the jest matchers.
31
+ */
32
+
33
+
34
+ exports.isExpectMember = isExpectMember;
35
+ let ModifierName;
36
+ exports.ModifierName = ModifierName;
37
+
38
+ (function (ModifierName) {
39
+ ModifierName["not"] = "not";
40
+ ModifierName["rejects"] = "rejects";
41
+ ModifierName["resolves"] = "resolves";
42
+ })(ModifierName || (exports.ModifierName = ModifierName = {}));
43
+
44
+ let EqualityMatcher;
45
+ exports.EqualityMatcher = EqualityMatcher;
46
+
47
+ (function (EqualityMatcher) {
48
+ EqualityMatcher["toBe"] = "toBe";
49
+ EqualityMatcher["toEqual"] = "toEqual";
50
+ EqualityMatcher["toStrictEqual"] = "toStrictEqual";
51
+ })(EqualityMatcher || (exports.EqualityMatcher = EqualityMatcher = {}));
52
+
53
+ const isParsedEqualityMatcherCall = (matcher, name) => (name ? matcher.name === name : EqualityMatcher.hasOwnProperty(matcher.name)) && matcher.arguments !== null && matcher.arguments.length === 1;
54
+ /**
55
+ * Represents a parsed expect matcher, such as `toBe`, `toContain`, and so on.
56
+ */
57
+
58
+
59
+ exports.isParsedEqualityMatcherCall = isParsedEqualityMatcherCall;
60
+
61
+ const parseExpectMember = expectMember => ({
62
+ name: (0, _utils2.getAccessorValue)(expectMember.property),
63
+ node: expectMember
64
+ });
65
+
66
+ const reparseAsMatcher = parsedMember => ({ ...parsedMember,
67
+
68
+ /**
69
+ * The arguments being passed to this `Matcher`, if any.
70
+ *
71
+ * If this matcher isn't called, this will be `null`.
72
+ */
73
+ arguments: parsedMember.node.parent.type === _utils.AST_NODE_TYPES.CallExpression ? parsedMember.node.parent.arguments : null
74
+ });
75
+ /**
76
+ * Re-parses the given `parsedMember` as a `ParsedExpectModifier`.
77
+ *
78
+ * If the given `parsedMember` does not have a `name` of a valid `Modifier`,
79
+ * an exception will be thrown.
80
+ *
81
+ * @param {ParsedExpectMember<ModifierName>} parsedMember
82
+ *
83
+ * @return {ParsedExpectModifier}
84
+ */
85
+
86
+
87
+ const reparseMemberAsModifier = parsedMember => {
88
+ if (isSpecificMember(parsedMember, ModifierName.not)) {
89
+ return parsedMember;
90
+ }
91
+ /* istanbul ignore if */
92
+
93
+
94
+ if (!isSpecificMember(parsedMember, ModifierName.resolves) && !isSpecificMember(parsedMember, ModifierName.rejects)) {
95
+ // ts doesn't think that the ModifierName.not check is the direct inverse as the above two checks
96
+ // todo: impossible at runtime, but can't be typed w/o negation support
97
+ throw new Error(`modifier name must be either "${ModifierName.resolves}" or "${ModifierName.rejects}" (got "${parsedMember.name}")`);
98
+ }
99
+
100
+ const negation = isExpectMember(parsedMember.node.parent, ModifierName.not) ? parsedMember.node.parent : undefined;
101
+ return { ...parsedMember,
102
+ negation
103
+ };
104
+ };
105
+
106
+ const isSpecificMember = (member, specific) => member.name === specific;
107
+ /**
108
+ * Checks if the given `ParsedExpectMember` should be re-parsed as an `ParsedExpectModifier`.
109
+ *
110
+ * @param {ParsedExpectMember} member
111
+ *
112
+ * @return {member is ParsedExpectMember<ModifierName>}
113
+ */
114
+
115
+
116
+ const shouldBeParsedExpectModifier = member => ModifierName.hasOwnProperty(member.name);
117
+
118
+ const parseExpectCall = expect => {
119
+ const expectation = {
120
+ expect
121
+ };
122
+
123
+ if (!isExpectMember(expect.parent)) {
124
+ return expectation;
125
+ }
126
+
127
+ const parsedMember = parseExpectMember(expect.parent);
128
+
129
+ if (!shouldBeParsedExpectModifier(parsedMember)) {
130
+ expectation.matcher = reparseAsMatcher(parsedMember);
131
+ return expectation;
132
+ }
133
+
134
+ const modifier = expectation.modifier = reparseMemberAsModifier(parsedMember);
135
+ const memberNode = modifier.negation || modifier.node;
136
+
137
+ if (!isExpectMember(memberNode.parent)) {
138
+ return expectation;
139
+ }
140
+
141
+ expectation.matcher = reparseAsMatcher(parseExpectMember(memberNode.parent));
142
+ return expectation;
143
+ };
144
+
145
+ exports.parseExpectCall = parseExpectCall;
@@ -0,0 +1,323 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getNodeChain = getNodeChain;
7
+ exports.scopeHasLocalReference = exports.parseJestFnCall = exports.isTypeOfJestFnCall = void 0;
8
+
9
+ var _utils = require("@typescript-eslint/utils");
10
+
11
+ var _utils2 = require("../utils");
12
+
13
+ const isTypeOfJestFnCall = (node, context, types) => {
14
+ const jestFnCall = parseJestFnCall(node, context);
15
+ return jestFnCall !== null && types.includes(jestFnCall.type);
16
+ };
17
+
18
+ exports.isTypeOfJestFnCall = isTypeOfJestFnCall;
19
+
20
+ const joinChains = (a, b) => a && b ? [...a, ...b] : null;
21
+
22
+ function getNodeChain(node) {
23
+ if ((0, _utils2.isSupportedAccessor)(node)) {
24
+ return [node];
25
+ }
26
+
27
+ switch (node.type) {
28
+ case _utils.AST_NODE_TYPES.TaggedTemplateExpression:
29
+ return getNodeChain(node.tag);
30
+
31
+ case _utils.AST_NODE_TYPES.MemberExpression:
32
+ return joinChains(getNodeChain(node.object), getNodeChain(node.property));
33
+
34
+ case _utils.AST_NODE_TYPES.CallExpression:
35
+ return getNodeChain(node.callee);
36
+ }
37
+
38
+ return null;
39
+ }
40
+
41
+ const determineJestFnType = name => {
42
+ // if (name === 'expect') {
43
+ // return 'expect';
44
+ // }
45
+ if (name === 'jest') {
46
+ return 'jest';
47
+ }
48
+
49
+ if (_utils2.DescribeAlias.hasOwnProperty(name)) {
50
+ return 'describe';
51
+ }
52
+
53
+ if (_utils2.TestCaseName.hasOwnProperty(name)) {
54
+ return 'test';
55
+ }
56
+ /* istanbul ignore else */
57
+
58
+
59
+ if (_utils2.HookName.hasOwnProperty(name)) {
60
+ return 'hook';
61
+ }
62
+ /* istanbul ignore next */
63
+
64
+
65
+ return 'unknown';
66
+ };
67
+
68
+ 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'];
69
+
70
+ const resolvePossibleAliasedGlobal = (global, context) => {
71
+ var _context$settings$jes, _context$settings$jes2;
72
+
73
+ 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 : {};
74
+ const alias = Object.entries(globalAliases).find(([, aliases]) => aliases.includes(global));
75
+
76
+ if (alias) {
77
+ return alias[0];
78
+ }
79
+
80
+ return null;
81
+ };
82
+
83
+ const parseJestFnCall = (node, context) => {
84
+ var _node$parent, _node$parent2, _resolved$original;
85
+
86
+ // ensure that we're at the "top" of the function call chain otherwise when
87
+ // parsing e.g. x().y.z(), we'll incorrectly find & parse "x()" even though
88
+ // the full chain is not a valid jest function call chain
89
+ if (((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) === _utils.AST_NODE_TYPES.CallExpression || ((_node$parent2 = node.parent) === null || _node$parent2 === void 0 ? void 0 : _node$parent2.type) === _utils.AST_NODE_TYPES.MemberExpression) {
90
+ return null;
91
+ }
92
+
93
+ const chain = getNodeChain(node);
94
+
95
+ if (!(chain !== null && chain !== void 0 && chain.length)) {
96
+ return null;
97
+ } // check that every link in the chain except the last is a member expression
98
+
99
+
100
+ if (chain.slice(0, chain.length - 1).some(nod => {
101
+ var _nod$parent;
102
+
103
+ return ((_nod$parent = nod.parent) === null || _nod$parent === void 0 ? void 0 : _nod$parent.type) !== _utils.AST_NODE_TYPES.MemberExpression;
104
+ })) {
105
+ return null;
106
+ }
107
+
108
+ const [first, ...rest] = chain;
109
+ const lastLink = (0, _utils2.getAccessorValue)(chain[chain.length - 1]); // if we're an `each()`, ensure we're the outer CallExpression (i.e `.each()()`)
110
+
111
+ if (lastLink === 'each') {
112
+ if (node.callee.type !== _utils.AST_NODE_TYPES.CallExpression && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression) {
113
+ return null;
114
+ }
115
+ }
116
+
117
+ if (node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression && lastLink !== 'each') {
118
+ return null;
119
+ }
120
+
121
+ const resolved = resolveToJestFn(context, (0, _utils2.getAccessorValue)(first)); // we're not a jest function
122
+
123
+ if (!resolved) {
124
+ return null;
125
+ }
126
+
127
+ const name = (_resolved$original = resolved.original) !== null && _resolved$original !== void 0 ? _resolved$original : resolved.local;
128
+ const links = [name, ...rest.map(link => (0, _utils2.getAccessorValue)(link))];
129
+
130
+ if (name !== 'jest' && !ValidJestFnCallChains.includes(links.join('.'))) {
131
+ return null;
132
+ }
133
+
134
+ return {
135
+ name,
136
+ type: determineJestFnType(name),
137
+ head: { ...resolved,
138
+ node: first
139
+ },
140
+ members: rest
141
+ };
142
+ };
143
+
144
+ exports.parseJestFnCall = parseJestFnCall;
145
+
146
+ const describeImportDefAsImport = def => {
147
+ if (def.parent.type === _utils.AST_NODE_TYPES.TSImportEqualsDeclaration) {
148
+ return null;
149
+ }
150
+
151
+ if (def.node.type !== _utils.AST_NODE_TYPES.ImportSpecifier) {
152
+ return null;
153
+ } // we only care about value imports
154
+
155
+
156
+ if (def.parent.importKind === 'type') {
157
+ return null;
158
+ }
159
+
160
+ return {
161
+ source: def.parent.source.value,
162
+ imported: def.node.imported.name,
163
+ local: def.node.local.name
164
+ };
165
+ };
166
+ /**
167
+ * Attempts to find the node that represents the import source for the
168
+ * given expression node, if it looks like it's an import.
169
+ *
170
+ * If no such node can be found (e.g. because the expression doesn't look
171
+ * like an import), then `null` is returned instead.
172
+ */
173
+
174
+
175
+ const findImportSourceNode = node => {
176
+ if (node.type === _utils.AST_NODE_TYPES.AwaitExpression) {
177
+ if (node.argument.type === _utils.AST_NODE_TYPES.ImportExpression) {
178
+ return node.argument.source;
179
+ }
180
+
181
+ return null;
182
+ }
183
+
184
+ if (node.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isIdentifier)(node.callee, 'require')) {
185
+ var _node$arguments$;
186
+
187
+ return (_node$arguments$ = node.arguments[0]) !== null && _node$arguments$ !== void 0 ? _node$arguments$ : null;
188
+ }
189
+
190
+ return null;
191
+ };
192
+
193
+ const describeVariableDefAsImport = def => {
194
+ var _def$name$parent;
195
+
196
+ // make sure that we've actually being assigned a value
197
+ if (!def.node.init) {
198
+ return null;
199
+ }
200
+
201
+ const sourceNode = findImportSourceNode(def.node.init);
202
+
203
+ if (!sourceNode || !(0, _utils2.isStringNode)(sourceNode)) {
204
+ return null;
205
+ }
206
+
207
+ if (((_def$name$parent = def.name.parent) === null || _def$name$parent === void 0 ? void 0 : _def$name$parent.type) !== _utils.AST_NODE_TYPES.Property) {
208
+ return null;
209
+ }
210
+
211
+ if (!(0, _utils2.isSupportedAccessor)(def.name.parent.key)) {
212
+ return null;
213
+ }
214
+
215
+ return {
216
+ source: (0, _utils2.getStringValue)(sourceNode),
217
+ imported: (0, _utils2.getAccessorValue)(def.name.parent.key),
218
+ local: def.name.name
219
+ };
220
+ };
221
+ /**
222
+ * Attempts to describe a definition as an import if possible.
223
+ *
224
+ * If the definition is an import binding, it's described as you'd expect.
225
+ * If the definition is a variable, then we try and determine if it's either
226
+ * a dynamic `import()` or otherwise a call to `require()`.
227
+ *
228
+ * If it's neither of these, `null` is returned to indicate that the definition
229
+ * is not describable as an import of any kind.
230
+ */
231
+
232
+
233
+ const describePossibleImportDef = def => {
234
+ if (def.type === 'Variable') {
235
+ return describeVariableDefAsImport(def);
236
+ }
237
+
238
+ if (def.type === 'ImportBinding') {
239
+ return describeImportDefAsImport(def);
240
+ }
241
+
242
+ return null;
243
+ };
244
+
245
+ const collectReferences = scope => {
246
+ const locals = new Set();
247
+ const imports = new Map();
248
+ const unresolved = new Set();
249
+ let currentScope = scope;
250
+
251
+ while (currentScope !== null) {
252
+ for (const ref of currentScope.variables) {
253
+ if (ref.defs.length === 0) {
254
+ continue;
255
+ }
256
+
257
+ const def = ref.defs[ref.defs.length - 1];
258
+ const importDetails = describePossibleImportDef(def);
259
+
260
+ if (importDetails) {
261
+ imports.set(importDetails.local, importDetails);
262
+ continue;
263
+ }
264
+
265
+ locals.add(ref.name);
266
+ }
267
+
268
+ for (const ref of currentScope.through) {
269
+ unresolved.add(ref.identifier.name);
270
+ }
271
+
272
+ currentScope = currentScope.upper;
273
+ }
274
+
275
+ return {
276
+ locals,
277
+ imports,
278
+ unresolved
279
+ };
280
+ };
281
+
282
+ const resolveToJestFn = (context, identifier) => {
283
+ const references = collectReferences(context.getScope());
284
+ const maybeImport = references.imports.get(identifier);
285
+
286
+ if (maybeImport) {
287
+ // the identifier is imported from @jest/globals,
288
+ // so return the original import name
289
+ if (maybeImport.source === '@jest/globals') {
290
+ return {
291
+ original: maybeImport.imported,
292
+ local: maybeImport.local,
293
+ type: 'import'
294
+ };
295
+ }
296
+
297
+ return null;
298
+ } // the identifier was found as a local variable or function declaration
299
+ // meaning it's not a function from jest
300
+
301
+
302
+ if (references.locals.has(identifier)) {
303
+ return null;
304
+ }
305
+
306
+ return {
307
+ original: resolvePossibleAliasedGlobal(identifier, context),
308
+ local: identifier,
309
+ type: 'global'
310
+ };
311
+ };
312
+
313
+ const scopeHasLocalReference = (scope, referenceName) => {
314
+ const references = collectReferences(scope);
315
+ return (// referenceName was found as a local variable or function declaration.
316
+ references.locals.has(referenceName) || // referenceName was found as an imported identifier
317
+ references.imports.has(referenceName) || // referenceName was not found as an unresolved reference,
318
+ // meaning it is likely not an implicit global reference.
319
+ !references.unresolved.has(referenceName)
320
+ );
321
+ };
322
+
323
+ exports.scopeHasLocalReference = scopeHasLocalReference;
@@ -41,7 +41,9 @@ var _default = (0, _utils2.createRule)({
41
41
  create(context) {
42
42
  return {
43
43
  CallExpression(node) {
44
- if (!(0, _utils2.isDescribeCall)(node)) {
44
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
45
+
46
+ if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe') {
45
47
  return;
46
48
  }
47
49
 
@@ -77,7 +79,7 @@ var _default = (0, _utils2.createRule)({
77
79
  });
78
80
  }
79
81
 
80
- if (!(0, _utils2.getNodeName)(node).endsWith('each') && callback.params.length) {
82
+ if (jestFnCall.members.every(s => (0, _utils2.getAccessorValue)(s) !== 'each') && callback.params.length) {
81
83
  context.report({
82
84
  messageId: 'unexpectedDescribeArgument',
83
85
  loc: paramsLocation(callback.params)
@@ -52,12 +52,14 @@ 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, context) => {
56
+ const jestCallFn = (0, _utils2.parseJestFnCall)(node, context);
57
+
58
+ if ((jestCallFn === null || jestCallFn === void 0 ? void 0 : jestCallFn.type) !== 'test') {
57
59
  return false;
58
60
  }
59
61
 
60
- const isJestEach = (0, _utils2.getNodeName)(node).endsWith('.each');
62
+ const isJestEach = jestCallFn.members.some(s => (0, _utils2.getAccessorValue)(s) === 'each');
61
63
 
62
64
  if (isJestEach && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression) {
63
65
  // isJestEach but not a TaggedTemplateExpression, so this must be
@@ -67,13 +69,9 @@ const isTestCaseCallWithCallbackArg = node => {
67
69
  return true;
68
70
  }
69
71
 
70
- if (isJestEach || node.arguments.length >= 2) {
71
- const [, callback] = node.arguments;
72
- const callbackArgIndex = Number(isJestEach);
73
- return callback && (0, _utils2.isFunction)(callback) && callback.params.length === 1 + callbackArgIndex;
74
- }
75
-
76
- return false;
72
+ const [, callback] = node.arguments;
73
+ const callbackArgIndex = Number(isJestEach);
74
+ return callback && (0, _utils2.isFunction)(callback) && callback.params.length === 1 + callbackArgIndex;
77
75
  };
78
76
 
79
77
  const isPromiseMethodThatUsesValue = (node, identifier) => {
@@ -254,7 +252,7 @@ const findFirstBlockBodyUp = node => {
254
252
  throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
255
253
  };
256
254
 
257
- const isDirectlyWithinTestCaseCall = node => {
255
+ const isDirectlyWithinTestCaseCall = (node, context) => {
258
256
  let parent = node;
259
257
 
260
258
  while (parent) {
@@ -262,7 +260,7 @@ const isDirectlyWithinTestCaseCall = node => {
262
260
  var _parent;
263
261
 
264
262
  parent = parent.parent;
265
- return !!(((_parent = parent) === null || _parent === void 0 ? void 0 : _parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTestCaseCall)(parent));
263
+ return ((_parent = parent) === null || _parent === void 0 ? void 0 : _parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTypeOfJestFnCall)(parent, context, ['test']);
266
264
  }
267
265
 
268
266
  parent = parent.parent;
@@ -312,7 +310,7 @@ var _default = (0, _utils2.createRule)({
312
310
  CallExpression(node) {
313
311
  // there are too many ways that the done argument could be used with
314
312
  // promises that contain expect that would make the promise safe for us
315
- if (isTestCaseCallWithCallbackArg(node)) {
313
+ if (isTestCaseCallWithCallbackArg(node, context)) {
316
314
  inTestCaseWithDoneCallback = true;
317
315
  return;
318
316
  } // if this call expression is a promise chain, add it to the stack with
@@ -336,7 +334,7 @@ var _default = (0, _utils2.createRule)({
336
334
  // make promises containing expects safe in a test for us to be able to
337
335
  // accurately check, so we just bail out completely if it's present
338
336
  if (inTestCaseWithDoneCallback) {
339
- if ((0, _utils2.isTestCaseCall)(node)) {
337
+ if ((0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
340
338
  inTestCaseWithDoneCallback = false;
341
339
  }
342
340
 
@@ -363,7 +361,7 @@ var _default = (0, _utils2.createRule)({
363
361
  // because we're most likely in the body of a function being defined
364
362
  // within the test, which we can't track
365
363
 
366
- if (!parent || !isDirectlyWithinTestCaseCall(parent)) {
364
+ if (!parent || !isDirectlyWithinTestCaseCall(parent, context)) {
367
365
  return;
368
366
  }
369
367