eslint-plugin-jest 26.2.1 → 26.4.0

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.
@@ -3,9 +3,33 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ var _exportNames = {
7
+ createRule: true,
8
+ followTypeAssertionChain: true,
9
+ isStringNode: true,
10
+ getStringValue: true,
11
+ hasOnlyOneArgument: true,
12
+ isIdentifier: true,
13
+ isSupportedAccessor: true,
14
+ getAccessorValue: true,
15
+ isExpectCall: true,
16
+ isExpectMember: true,
17
+ ModifierName: true,
18
+ EqualityMatcher: true,
19
+ isParsedEqualityMatcherCall: true,
20
+ parseExpectCall: true,
21
+ DescribeAlias: true,
22
+ TestCaseName: true,
23
+ HookName: true,
24
+ DescribeProperty: true,
25
+ TestCaseProperty: true,
26
+ getNodeName: true,
27
+ isFunction: true,
28
+ getTestCallExpressionsFromDeclaredVariables: true
29
+ };
6
30
  exports.getAccessorValue = exports.followTypeAssertionChain = exports.createRule = exports.TestCaseProperty = exports.TestCaseName = exports.ModifierName = exports.HookName = exports.EqualityMatcher = exports.DescribeProperty = exports.DescribeAlias = void 0;
7
31
  exports.getNodeName = getNodeName;
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;
32
+ exports.parseExpectCall = exports.isSupportedAccessor = exports.isStringNode = exports.isParsedEqualityMatcherCall = exports.isIdentifier = exports.isFunction = exports.isExpectMember = exports.isExpectCall = exports.hasOnlyOneArgument = exports.getTestCallExpressionsFromDeclaredVariables = exports.getStringValue = void 0;
9
33
 
10
34
  var _path = require("path");
11
35
 
@@ -13,6 +37,19 @@ var _utils = require("@typescript-eslint/utils");
13
37
 
14
38
  var _package = require("../../package.json");
15
39
 
40
+ var _parseJestFnCall = require("./utils/parseJestFnCall");
41
+
42
+ Object.keys(_parseJestFnCall).forEach(function (key) {
43
+ if (key === "default" || key === "__esModule") return;
44
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
45
+ if (key in exports && exports[key] === _parseJestFnCall[key]) return;
46
+ Object.defineProperty(exports, key, {
47
+ enumerable: true,
48
+ get: function () {
49
+ return _parseJestFnCall[key];
50
+ }
51
+ });
52
+ });
16
53
  const REPO_URL = 'https://github.com/jest-community/eslint-plugin-jest';
17
54
 
18
55
  const createRule = _utils.ESLintUtils.RuleCreator(name => {
@@ -384,267 +421,12 @@ const isFunction = node => node.type === _utils.AST_NODE_TYPES.FunctionExpressio
384
421
 
385
422
  exports.isFunction = isFunction;
386
423
 
387
- const isHookCall = (node, scope) => {
388
- let name = findFirstCallPropertyName(node, []);
389
-
390
- if (!name) {
391
- return false;
392
- }
393
-
394
- name = resolveToJestFn(scope, name);
395
- return name !== null && HookName.hasOwnProperty(name);
396
- };
397
-
398
- exports.isHookCall = isHookCall;
399
-
400
424
  const getTestCallExpressionsFromDeclaredVariables = (declaredVariables, scope) => {
401
425
  return declaredVariables.reduce((acc, {
402
426
  references
403
427
  }) => acc.concat(references.map(({
404
428
  identifier
405
- }) => identifier.parent).filter(node => !!node && node.type === _utils.AST_NODE_TYPES.CallExpression && isTestCaseCall(node, scope))), []);
406
- };
407
- /**
408
- * Checks if the given `node` is a *call* to a test case function that would
409
- * result in tests being run by `jest`.
410
- *
411
- * Note that `.each()` does not count as a call in this context, as it will not
412
- * result in `jest` running any tests.
413
- */
414
-
415
-
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;
434
- }
435
-
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;
437
-
438
- if (callee.type === _utils.AST_NODE_TYPES.MemberExpression && isSupportedAccessor(callee.property) && properties.includes(getAccessorValue(callee.property))) {
439
- // if we're an `each()`, ensure we're the outer CallExpression (i.e `.each()()`)
440
- if (getAccessorValue(callee.property) === 'each' && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression && node.callee.type !== _utils.AST_NODE_TYPES.CallExpression) {
441
- return null;
442
- }
443
-
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
- }
449
- }
450
-
451
- return null;
452
- };
453
- /**
454
- * Checks if the given `node` is a *call* to a `describe` function that would
455
- * result in a `describe` block being created by `jest`.
456
- *
457
- * Note that `.each()` does not count as a call in this context, as it will not
458
- * result in `jest` creating any `describe` blocks.
459
- */
460
-
461
-
462
- const isDescribeCall = (node, scope) => {
463
- let name = findFirstCallPropertyName(node, Object.keys(DescribeProperty));
464
-
465
- if (!name) {
466
- return false;
467
- }
468
-
469
- name = resolveToJestFn(scope, name);
470
- return name !== null && DescribeAlias.hasOwnProperty(name);
471
- };
472
-
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;
508
- }
509
-
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;
517
- }
518
-
519
- return null;
520
- };
521
-
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;
429
+ }) => identifier.parent).filter(node => !!node && node.type === _utils.AST_NODE_TYPES.CallExpression && (0, _parseJestFnCall.isTypeOfJestFnCall)(node, scope, ['test']))), []);
572
430
  };
573
431
 
574
- const collectReferences = scope => {
575
- const locals = new Set();
576
- const imports = new Map();
577
- const unresolved = new Set();
578
- let currentScope = scope;
579
-
580
- while (currentScope !== null) {
581
- for (const ref of currentScope.variables) {
582
- if (ref.defs.length === 0) {
583
- continue;
584
- }
585
- /* istanbul ignore if */
586
-
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`);
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);
601
- }
602
-
603
- for (const ref of currentScope.through) {
604
- unresolved.add(ref.identifier.name);
605
- }
606
-
607
- currentScope = currentScope.upper;
608
- }
609
-
610
- return {
611
- locals,
612
- imports,
613
- unresolved
614
- };
615
- };
616
-
617
- const scopeHasLocalReference = (scope, referenceName) => {
618
- const references = collectReferences(scope);
619
- return (// referenceName was found as a local variable or function declaration.
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,
622
- // meaning it is likely not an implicit global reference.
623
- !references.unresolved.has(referenceName)
624
- );
625
- };
626
-
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
- };
432
+ exports.getTestCallExpressionsFromDeclaredVariables = getTestCallExpressionsFromDeclaredVariables;
@@ -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, context.getScope())) {
44
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context.getScope());
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)
@@ -53,11 +53,13 @@ const findTopMostCallExpression = node => {
53
53
  };
54
54
 
55
55
  const isTestCaseCallWithCallbackArg = (node, scope) => {
56
- if (!(0, _utils2.isTestCaseCall)(node, scope)) {
56
+ const jestCallFn = (0, _utils2.parseJestFnCall)(node, scope);
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, scope) => {
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) => {
@@ -262,7 +260,7 @@ const isDirectlyWithinTestCaseCall = (node, scope) => {
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, scope));
263
+ return ((_parent = parent) === null || _parent === void 0 ? void 0 : _parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTypeOfJestFnCall)(parent, scope, ['test']);
266
264
  }
267
265
 
268
266
  parent = parent.parent;
@@ -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, context.getScope())) {
337
+ if ((0, _utils2.isTypeOfJestFnCall)(node, context.getScope(), ['test'])) {
340
338
  inTestCaseWithDoneCallback = false;
341
339
  }
342
340
 
@@ -131,8 +131,9 @@ var _default = (0, _utils2.createRule)({
131
131
  var _mustNotMatchPatterns, _mustMatchPatterns$je;
132
132
 
133
133
  const scope = context.getScope();
134
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, scope);
134
135
 
135
- if (!(0, _utils2.isDescribeCall)(node, scope) && !(0, _utils2.isTestCaseCall)(node, scope)) {
136
+ if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe' && (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'test') {
136
137
  return;
137
138
  }
138
139
 
@@ -147,7 +148,7 @@ var _default = (0, _utils2.createRule)({
147
148
  return;
148
149
  }
149
150
 
150
- if (argument.type !== _utils.AST_NODE_TYPES.TemplateLiteral && !(ignoreTypeOfDescribeName && (0, _utils2.isDescribeCall)(node, scope))) {
151
+ if (argument.type !== _utils.AST_NODE_TYPES.TemplateLiteral && !(ignoreTypeOfDescribeName && jestFnCall.type === 'describe')) {
151
152
  context.report({
152
153
  messageId: 'titleMustBeString',
153
154
  loc: argument.loc
@@ -163,7 +164,7 @@ var _default = (0, _utils2.createRule)({
163
164
  context.report({
164
165
  messageId: 'emptyTitle',
165
166
  data: {
166
- jestFunctionName: (0, _utils2.isDescribeCall)(node, scope) ? _utils2.DescribeAlias.describe : _utils2.TestCaseName.test
167
+ jestFunctionName: jestFnCall.type === 'describe' ? _utils2.DescribeAlias.describe : _utils2.TestCaseName.test
167
168
  },
168
169
  node
169
170
  });
@@ -193,10 +194,10 @@ var _default = (0, _utils2.createRule)({
193
194
  });
194
195
  }
195
196
 
196
- const nodeName = trimFXprefix((0, _utils2.getNodeName)(node));
197
+ const unprefixedName = trimFXprefix(jestFnCall.name);
197
198
  const [firstWord] = title.split(' ');
198
199
 
199
- if (firstWord.toLowerCase() === nodeName) {
200
+ if (firstWord.toLowerCase() === unprefixedName) {
200
201
  context.report({
201
202
  messageId: 'duplicatePrefix',
202
203
  node: argument,
@@ -204,7 +205,7 @@ var _default = (0, _utils2.createRule)({
204
205
  });
205
206
  }
206
207
 
207
- const [jestFunctionName] = nodeName.split('.');
208
+ const jestFunctionName = unprefixedName;
208
209
  const [mustNotMatchPattern, mustNotMatchMessage] = (_mustNotMatchPatterns = mustNotMatchPatterns[jestFunctionName]) !== null && _mustNotMatchPatterns !== void 0 ? _mustNotMatchPatterns : [];
209
210
 
210
211
  if (mustNotMatchPattern) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-jest",
3
- "version": "26.2.1",
3
+ "version": "26.4.0",
4
4
  "description": "ESLint rules for Jest",
5
5
  "keywords": [
6
6
  "eslint",