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.
Files changed (114) hide show
  1. package/README.md +82 -78
  2. package/docs/rules/consistent-test-it.md +9 -4
  3. package/docs/rules/expect-expect.md +5 -0
  4. package/docs/rules/max-expects.md +3 -1
  5. package/docs/rules/max-nested-describe.md +3 -1
  6. package/docs/rules/no-alias-methods.md +13 -2
  7. package/docs/rules/no-commented-out-tests.md +6 -1
  8. package/docs/rules/no-conditional-expect.md +7 -2
  9. package/docs/rules/no-conditional-in-test.md +3 -1
  10. package/docs/rules/no-deprecated-functions.md +14 -7
  11. package/docs/rules/no-disabled-tests.md +6 -1
  12. package/docs/rules/no-done-callback.md +9 -1
  13. package/docs/rules/no-duplicate-hooks.md +3 -1
  14. package/docs/rules/no-export.md +6 -1
  15. package/docs/rules/no-focused-tests.md +10 -1
  16. package/docs/rules/no-hooks.md +3 -1
  17. package/docs/rules/no-identical-title.md +6 -1
  18. package/docs/rules/no-if.md +4 -4
  19. package/docs/rules/no-interpolation-in-snapshots.md +6 -1
  20. package/docs/rules/no-jasmine-globals.md +10 -2
  21. package/docs/rules/no-large-snapshots.md +4 -2
  22. package/docs/rules/no-mocks-import.md +6 -1
  23. package/docs/rules/no-restricted-jest-methods.md +51 -0
  24. package/docs/rules/no-restricted-matchers.md +19 -4
  25. package/docs/rules/no-standalone-expect.md +6 -1
  26. package/docs/rules/no-test-prefixes.md +9 -1
  27. package/docs/rules/no-test-return-statement.md +2 -0
  28. package/docs/rules/prefer-called-with.md +2 -0
  29. package/docs/rules/prefer-comparison-matcher.md +5 -0
  30. package/docs/rules/prefer-each.md +56 -0
  31. package/docs/rules/prefer-equality-matcher.md +5 -0
  32. package/docs/rules/prefer-expect-assertions.md +5 -2
  33. package/docs/rules/prefer-expect-resolves.md +8 -1
  34. package/docs/rules/prefer-hooks-in-order.md +3 -1
  35. package/docs/rules/prefer-hooks-on-top.md +3 -1
  36. package/docs/rules/prefer-lowercase-title.md +5 -0
  37. package/docs/rules/prefer-mock-promise-shorthand.md +6 -1
  38. package/docs/rules/prefer-snapshot-hint.md +2 -0
  39. package/docs/rules/prefer-spy-on.md +5 -2
  40. package/docs/rules/prefer-strict-equal.md +5 -2
  41. package/docs/rules/prefer-to-be.md +8 -0
  42. package/docs/rules/prefer-to-contain.md +8 -2
  43. package/docs/rules/prefer-to-have-length.md +8 -2
  44. package/docs/rules/prefer-todo.md +5 -2
  45. package/docs/rules/require-hook.md +2 -0
  46. package/docs/rules/require-to-throw-message.md +2 -2
  47. package/docs/rules/require-top-level-describe.md +5 -1
  48. package/docs/rules/unbound-method.md +7 -2
  49. package/docs/rules/valid-describe-callback.md +6 -1
  50. package/docs/rules/valid-expect-in-promise.md +6 -1
  51. package/docs/rules/valid-expect.md +5 -2
  52. package/docs/rules/valid-title.md +9 -1
  53. package/lib/index.js +14 -25
  54. package/lib/processors/snapshot-processor.js +3 -5
  55. package/lib/rules/consistent-test-it.js +1 -19
  56. package/lib/rules/expect-expect.js +1 -18
  57. package/lib/rules/max-expects.js +0 -16
  58. package/lib/rules/max-nested-describe.js +0 -13
  59. package/lib/rules/no-alias-methods.js +1 -10
  60. package/lib/rules/no-commented-out-tests.js +0 -10
  61. package/lib/rules/no-conditional-expect.js +2 -23
  62. package/lib/rules/no-conditional-in-test.js +0 -9
  63. package/lib/rules/no-deprecated-functions.js +2 -18
  64. package/lib/rules/no-disabled-tests.js +3 -19
  65. package/lib/rules/no-done-callback.js +5 -35
  66. package/lib/rules/no-duplicate-hooks.js +0 -12
  67. package/lib/rules/no-export.js +0 -12
  68. package/lib/rules/no-focused-tests.js +1 -17
  69. package/lib/rules/no-hooks.js +0 -7
  70. package/lib/rules/no-identical-title.js +0 -19
  71. package/lib/rules/no-if.js +0 -24
  72. package/lib/rules/no-interpolation-in-snapshots.js +0 -9
  73. package/lib/rules/no-jasmine-globals.js +1 -23
  74. package/lib/rules/no-large-snapshots.js +4 -24
  75. package/lib/rules/no-mocks-import.js +0 -12
  76. package/lib/rules/no-restricted-jest-methods.js +56 -0
  77. package/lib/rules/no-restricted-matchers.js +13 -28
  78. package/lib/rules/no-standalone-expect.js +7 -33
  79. package/lib/rules/no-test-prefixes.js +1 -13
  80. package/lib/rules/no-test-return-statement.js +0 -12
  81. package/lib/rules/prefer-called-with.js +0 -10
  82. package/lib/rules/prefer-comparison-matcher.js +8 -33
  83. package/lib/rules/prefer-each.js +80 -0
  84. package/lib/rules/prefer-equality-matcher.js +12 -25
  85. package/lib/rules/prefer-expect-assertions.js +8 -54
  86. package/lib/rules/prefer-expect-resolves.js +0 -12
  87. package/lib/rules/prefer-hooks-in-order.js +2 -16
  88. package/lib/rules/prefer-hooks-on-top.js +0 -9
  89. package/lib/rules/prefer-lowercase-title.js +0 -23
  90. package/lib/rules/prefer-mock-promise-shorthand.js +5 -26
  91. package/lib/rules/prefer-snapshot-hint.js +8 -34
  92. package/lib/rules/prefer-spy-on.js +0 -17
  93. package/lib/rules/prefer-strict-equal.js +1 -11
  94. package/lib/rules/prefer-to-be.js +5 -30
  95. package/lib/rules/prefer-to-contain.js +11 -21
  96. package/lib/rules/prefer-to-have-length.js +4 -16
  97. package/lib/rules/prefer-todo.js +2 -18
  98. package/lib/rules/require-hook.js +1 -25
  99. package/lib/rules/require-to-throw-message.js +0 -9
  100. package/lib/rules/require-top-level-describe.js +1 -18
  101. package/lib/rules/unbound-method.js +3 -30
  102. package/lib/rules/utils/accessors.js +6 -18
  103. package/lib/rules/utils/detectJestVersion.js +2 -7
  104. package/lib/rules/utils/followTypeAssertionChain.js +0 -4
  105. package/lib/rules/utils/index.js +0 -10
  106. package/lib/rules/utils/misc.js +2 -46
  107. package/lib/rules/utils/parseJestFnCall.js +51 -154
  108. package/lib/rules/valid-describe-callback.js +0 -17
  109. package/lib/rules/valid-expect-in-promise.js +28 -95
  110. package/lib/rules/valid-expect.js +5 -48
  111. package/lib/rules/valid-title.js +5 -40
  112. package/package.json +20 -16
  113. package/docs/rules/no-jest-import.md +0 -20
  114. package/lib/rules/no-jest-import.js +0 -48
@@ -4,17 +4,14 @@ 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
  var _default = (0, _utils2.createRule)({
13
10
  name: __filename,
14
11
  meta: {
15
12
  docs: {
16
13
  category: 'Best Practices',
17
- description: 'Use `.only` and `.skip` over `f` and `x`',
14
+ description: 'Require using `.only` and `.skip` over `f` and `x`',
18
15
  recommended: 'error'
19
16
  },
20
17
  messages: {
@@ -25,20 +22,16 @@ var _default = (0, _utils2.createRule)({
25
22
  type: 'suggestion'
26
23
  },
27
24
  defaultOptions: [],
28
-
29
25
  create(context) {
30
26
  return {
31
27
  CallExpression(node) {
32
28
  const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
33
-
34
29
  if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'describe' && (jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'test') {
35
30
  return;
36
31
  }
37
-
38
32
  if (jestFnCall.name[0] !== 'f' && jestFnCall.name[0] !== 'x') {
39
33
  return;
40
34
  }
41
-
42
35
  const preferredNodeName = [jestFnCall.name.slice(1), jestFnCall.name[0] === 'f' ? 'only' : 'skip', ...jestFnCall.members.map(s => (0, _utils2.getAccessorValue)(s))].join('.');
43
36
  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;
44
37
  context.report({
@@ -47,17 +40,12 @@ var _default = (0, _utils2.createRule)({
47
40
  data: {
48
41
  preferredNodeName
49
42
  },
50
-
51
43
  fix(fixer) {
52
44
  return [fixer.replaceText(funcNode, preferredNodeName)];
53
45
  }
54
-
55
46
  });
56
47
  }
57
-
58
48
  };
59
49
  }
60
-
61
50
  });
62
-
63
51
  exports.default = _default;
@@ -4,21 +4,15 @@ 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 getBody = args => {
13
10
  const [, secondArg] = args;
14
-
15
11
  if (secondArg && (0, _utils2.isFunction)(secondArg) && secondArg.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
16
12
  return secondArg.body.body;
17
13
  }
18
-
19
14
  return [];
20
15
  };
21
-
22
16
  var _default = (0, _utils2.createRule)({
23
17
  name: __filename,
24
18
  meta: {
@@ -34,14 +28,12 @@ var _default = (0, _utils2.createRule)({
34
28
  type: 'suggestion'
35
29
  },
36
30
  defaultOptions: [],
37
-
38
31
  create(context) {
39
32
  return {
40
33
  CallExpression(node) {
41
34
  if (!(0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
42
35
  return;
43
36
  }
44
-
45
37
  const body = getBody(node.arguments);
46
38
  const returnStmt = body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement);
47
39
  if (!returnStmt) return;
@@ -50,7 +42,6 @@ var _default = (0, _utils2.createRule)({
50
42
  node: returnStmt
51
43
  });
52
44
  },
53
-
54
45
  FunctionDeclaration(node) {
55
46
  const declaredVariables = context.getDeclaredVariables(node);
56
47
  const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables, context);
@@ -62,10 +53,7 @@ var _default = (0, _utils2.createRule)({
62
53
  node: returnStmt
63
54
  });
64
55
  }
65
-
66
56
  };
67
57
  }
68
-
69
58
  });
70
-
71
59
  exports.default = _default;
@@ -4,9 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
-
8
7
  var _utils = require("./utils");
9
-
10
8
  var _default = (0, _utils.createRule)({
11
9
  name: __filename,
12
10
  meta: {
@@ -22,25 +20,20 @@ var _default = (0, _utils.createRule)({
22
20
  schema: []
23
21
  },
24
22
  defaultOptions: [],
25
-
26
23
  create(context) {
27
24
  return {
28
25
  CallExpression(node) {
29
26
  const jestFnCall = (0, _utils.parseJestFnCall)(node, context);
30
-
31
27
  if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect') {
32
28
  return;
33
29
  }
34
-
35
30
  if (jestFnCall.modifiers.some(nod => (0, _utils.getAccessorValue)(nod) === 'not')) {
36
31
  return;
37
32
  }
38
-
39
33
  const {
40
34
  matcher
41
35
  } = jestFnCall;
42
36
  const matcherName = (0, _utils.getAccessorValue)(matcher);
43
-
44
37
  if (['toBeCalled', 'toHaveBeenCalled'].includes(matcherName)) {
45
38
  context.report({
46
39
  data: {
@@ -51,10 +44,7 @@ var _default = (0, _utils.createRule)({
51
44
  });
52
45
  }
53
46
  }
54
-
55
47
  };
56
48
  }
57
-
58
49
  });
59
-
60
50
  exports.default = _default;
@@ -4,57 +4,41 @@ 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 isString = node => {
13
10
  return (0, _utils2.isStringNode)(node) || node.type === _utils.AST_NODE_TYPES.TemplateLiteral;
14
11
  };
15
-
16
12
  const isComparingToString = expression => {
17
13
  return isString(expression.left) || isString(expression.right);
18
14
  };
19
-
20
15
  const invertOperator = operator => {
21
16
  switch (operator) {
22
17
  case '>':
23
18
  return '<=';
24
-
25
19
  case '<':
26
20
  return '>=';
27
-
28
21
  case '>=':
29
22
  return '<';
30
-
31
23
  case '<=':
32
24
  return '>';
33
25
  }
34
-
35
26
  return null;
36
27
  };
37
-
38
28
  const determineMatcher = (operator, negated) => {
39
29
  const op = negated ? invertOperator(operator) : operator;
40
-
41
30
  switch (op) {
42
31
  case '>':
43
32
  return 'toBeGreaterThan';
44
-
45
33
  case '<':
46
34
  return 'toBeLessThan';
47
-
48
35
  case '>=':
49
36
  return 'toBeGreaterThanOrEqual';
50
-
51
37
  case '<=':
52
38
  return 'toBeLessThanOrEqual';
53
39
  }
54
-
55
40
  return null;
56
41
  };
57
-
58
42
  var _default = (0, _utils2.createRule)({
59
43
  name: __filename,
60
44
  meta: {
@@ -71,24 +55,19 @@ var _default = (0, _utils2.createRule)({
71
55
  schema: []
72
56
  },
73
57
  defaultOptions: [],
74
-
75
58
  create(context) {
76
59
  return {
77
60
  CallExpression(node) {
78
61
  const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
79
-
80
62
  if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect' || jestFnCall.args.length === 0) {
81
63
  return;
82
64
  }
83
-
84
65
  const {
85
66
  parent: expect
86
67
  } = jestFnCall.head.node;
87
-
88
68
  if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) {
89
69
  return;
90
70
  }
91
-
92
71
  const {
93
72
  arguments: [comparison],
94
73
  range: [, expectCallEnd]
@@ -97,30 +76,29 @@ var _default = (0, _utils2.createRule)({
97
76
  matcher
98
77
  } = jestFnCall;
99
78
  const matcherArg = (0, _utils2.getFirstMatcherArg)(jestFnCall);
100
-
101
79
  if ((comparison === null || comparison === void 0 ? void 0 : comparison.type) !== _utils.AST_NODE_TYPES.BinaryExpression || isComparingToString(comparison) || !_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || !(0, _utils2.isBooleanLiteral)(matcherArg)) {
102
80
  return;
103
81
  }
104
-
105
82
  const [modifier] = jestFnCall.modifiers;
106
83
  const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not');
107
84
  const preferredMatcher = determineMatcher(comparison.operator, matcherArg.value === hasNot);
108
-
109
85
  if (!preferredMatcher) {
110
86
  return;
111
87
  }
112
-
113
88
  context.report({
114
89
  fix(fixer) {
115
- const sourceCode = context.getSourceCode(); // preserve the existing modifier if it's not a negation
90
+ const sourceCode = context.getSourceCode();
116
91
 
92
+ // preserve the existing modifier if it's not a negation
117
93
  const modifierText = modifier && (0, _utils2.getAccessorValue)(modifier) !== 'not' ? `.${(0, _utils2.getAccessorValue)(modifier)}` : '';
118
- return [// replace the comparison argument with the left-hand side of the comparison
119
- fixer.replaceText(comparison, sourceCode.getText(comparison.left)), // replace the current matcher & modifier with the preferred matcher
120
- fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${preferredMatcher}`), // replace the matcher argument with the right-hand side of the comparison
94
+ return [
95
+ // replace the comparison argument with the left-hand side of the comparison
96
+ fixer.replaceText(comparison, sourceCode.getText(comparison.left)),
97
+ // replace the current matcher & modifier with the preferred matcher
98
+ fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${preferredMatcher}`),
99
+ // replace the matcher argument with the right-hand side of the comparison
121
100
  fixer.replaceText(matcherArg, sourceCode.getText(comparison.right))];
122
101
  },
123
-
124
102
  messageId: 'useToBeComparison',
125
103
  data: {
126
104
  preferredMatcher
@@ -128,10 +106,7 @@ var _default = (0, _utils2.createRule)({
128
106
  node: matcher
129
107
  });
130
108
  }
131
-
132
109
  };
133
110
  }
134
-
135
111
  });
136
-
137
112
  exports.default = _default;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _utils = require("./utils");
8
+ var _default = (0, _utils.createRule)({
9
+ name: __filename,
10
+ meta: {
11
+ docs: {
12
+ category: 'Best Practices',
13
+ description: 'Prefer using `.each` rather than manual loops',
14
+ recommended: false
15
+ },
16
+ messages: {
17
+ preferEach: 'prefer using `{{ fn }}.each` rather than a manual loop'
18
+ },
19
+ type: 'suggestion',
20
+ schema: []
21
+ },
22
+ defaultOptions: [],
23
+ create(context) {
24
+ const jestFnCalls = [];
25
+ let inTestCaseCall = false;
26
+ const recommendFn = () => {
27
+ if (jestFnCalls.length === 1 && jestFnCalls[0] === 'test') {
28
+ return 'it';
29
+ }
30
+ return 'describe';
31
+ };
32
+ const enterForLoop = () => {
33
+ if (jestFnCalls.length === 0 || inTestCaseCall) {
34
+ return;
35
+ }
36
+ jestFnCalls.length = 0;
37
+ };
38
+ const exitForLoop = node => {
39
+ if (jestFnCalls.length === 0 || inTestCaseCall) {
40
+ return;
41
+ }
42
+ context.report({
43
+ node,
44
+ messageId: 'preferEach',
45
+ data: {
46
+ fn: recommendFn()
47
+ }
48
+ });
49
+ jestFnCalls.length = 0;
50
+ };
51
+ return {
52
+ ForStatement: enterForLoop,
53
+ 'ForStatement:exit': exitForLoop,
54
+ ForInStatement: enterForLoop,
55
+ 'ForInStatement:exit': exitForLoop,
56
+ ForOfStatement: enterForLoop,
57
+ 'ForOfStatement:exit': exitForLoop,
58
+ CallExpression(node) {
59
+ const {
60
+ type: jestFnCallType
61
+ } = (0, _utils.parseJestFnCall)(node, context) ?? {};
62
+ if (jestFnCallType === 'hook' || jestFnCallType === 'describe' || jestFnCallType === 'test') {
63
+ jestFnCalls.push(jestFnCallType);
64
+ }
65
+ if (jestFnCallType === 'test') {
66
+ inTestCaseCall = true;
67
+ }
68
+ },
69
+ 'CallExpression:exit'(node) {
70
+ const {
71
+ type: jestFnCallType
72
+ } = (0, _utils.parseJestFnCall)(node, context) ?? {};
73
+ if (jestFnCallType === 'test') {
74
+ inTestCaseCall = false;
75
+ }
76
+ }
77
+ };
78
+ }
79
+ });
80
+ exports.default = _default;
@@ -4,19 +4,15 @@ 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
  var _default = (0, _utils2.createRule)({
13
10
  name: __filename,
14
11
  meta: {
15
12
  docs: {
16
13
  category: 'Best Practices',
17
14
  description: 'Suggest using the built-in equality matchers',
18
- recommended: false,
19
- suggestion: true
15
+ recommended: false
20
16
  },
21
17
  messages: {
22
18
  useEqualityMatcher: 'Prefer using one of the equality matchers instead',
@@ -27,24 +23,19 @@ var _default = (0, _utils2.createRule)({
27
23
  schema: []
28
24
  },
29
25
  defaultOptions: [],
30
-
31
26
  create(context) {
32
27
  return {
33
28
  CallExpression(node) {
34
29
  const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
35
-
36
30
  if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) !== 'expect' || jestFnCall.args.length === 0) {
37
31
  return;
38
32
  }
39
-
40
33
  const {
41
34
  parent: expect
42
35
  } = jestFnCall.head.node;
43
-
44
36
  if ((expect === null || expect === void 0 ? void 0 : expect.type) !== _utils.AST_NODE_TYPES.CallExpression) {
45
37
  return;
46
38
  }
47
-
48
39
  const {
49
40
  arguments: [comparison],
50
41
  range: [, expectCallEnd]
@@ -53,33 +44,32 @@ var _default = (0, _utils2.createRule)({
53
44
  matcher
54
45
  } = jestFnCall;
55
46
  const matcherArg = (0, _utils2.getFirstMatcherArg)(jestFnCall);
56
-
57
47
  if ((comparison === null || comparison === void 0 ? void 0 : comparison.type) !== _utils.AST_NODE_TYPES.BinaryExpression || comparison.operator !== '===' && comparison.operator !== '!==' || !_utils2.EqualityMatcher.hasOwnProperty((0, _utils2.getAccessorValue)(matcher)) || !(0, _utils2.isBooleanLiteral)(matcherArg)) {
58
48
  return;
59
49
  }
60
-
61
50
  const matcherValue = matcherArg.value;
62
51
  const [modifier] = jestFnCall.modifiers;
63
- const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not'); // we need to negate the expectation if the current expected
64
- // value is itself negated by the "not" modifier
52
+ const hasNot = jestFnCall.modifiers.some(nod => (0, _utils2.getAccessorValue)(nod) === 'not');
65
53
 
54
+ // we need to negate the expectation if the current expected
55
+ // value is itself negated by the "not" modifier
66
56
  const addNotModifier = (comparison.operator === '!==' ? !matcherValue : matcherValue) === hasNot;
67
-
68
57
  const buildFixer = equalityMatcher => fixer => {
69
- const sourceCode = context.getSourceCode(); // preserve the existing modifier if it's not a negation
58
+ const sourceCode = context.getSourceCode();
70
59
 
60
+ // preserve the existing modifier if it's not a negation
71
61
  let modifierText = modifier && (0, _utils2.getAccessorValue)(modifier) !== 'not' ? `.${(0, _utils2.getAccessorValue)(modifier)}` : '';
72
-
73
62
  if (addNotModifier) {
74
63
  modifierText += `.${_utils2.ModifierName.not}`;
75
64
  }
76
-
77
- return [// replace the comparison argument with the left-hand side of the comparison
78
- fixer.replaceText(comparison, sourceCode.getText(comparison.left)), // replace the current matcher & modifier with the preferred matcher
79
- fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${equalityMatcher}`), // replace the matcher argument with the right-hand side of the comparison
65
+ return [
66
+ // replace the comparison argument with the left-hand side of the comparison
67
+ fixer.replaceText(comparison, sourceCode.getText(comparison.left)),
68
+ // replace the current matcher & modifier with the preferred matcher
69
+ fixer.replaceTextRange([expectCallEnd, matcher.parent.range[1]], `${modifierText}.${equalityMatcher}`),
70
+ // replace the matcher argument with the right-hand side of the comparison
80
71
  fixer.replaceText(matcherArg, sourceCode.getText(comparison.right))];
81
72
  };
82
-
83
73
  context.report({
84
74
  messageId: 'useEqualityMatcher',
85
75
  suggest: ['toBe', 'toEqual', 'toStrictEqual'].map(equalityMatcher => ({
@@ -92,10 +82,7 @@ var _default = (0, _utils2.createRule)({
92
82
  node: matcher
93
83
  });
94
84
  }
95
-
96
85
  };
97
86
  }
98
-
99
87
  });
100
-
101
88
  exports.default = _default;
@@ -4,46 +4,38 @@ 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 isFirstStatement = node => {
13
10
  let parent = node;
14
-
15
11
  while (parent) {
16
- var _parent$parent;
17
-
12
+ var _parent$parent, _parent$parent2;
18
13
  if (((_parent$parent = parent.parent) === null || _parent$parent === void 0 ? void 0 : _parent$parent.type) === _utils.AST_NODE_TYPES.BlockStatement) {
19
14
  return parent.parent.body[0] === parent;
20
15
  }
21
16
 
17
+ // if we've hit an arrow function, then it must have a single expression
18
+ // as its body, as otherwise we would have hit the block statement already
19
+ if (((_parent$parent2 = parent.parent) === null || _parent$parent2 === void 0 ? void 0 : _parent$parent2.type) === _utils.AST_NODE_TYPES.ArrowFunctionExpression) {
20
+ return true;
21
+ }
22
22
  parent = parent.parent;
23
23
  }
24
- /* istanbul ignore next */
25
-
26
24
 
25
+ /* istanbul ignore next */
27
26
  throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
28
27
  };
29
-
30
28
  const suggestRemovingExtraArguments = (args, extraArgsStartAt) => ({
31
29
  messageId: 'suggestRemovingExtraArguments',
32
30
  fix: fixer => fixer.removeRange([args[extraArgsStartAt].range[0] - Math.sign(extraArgsStartAt), args[args.length - 1].range[1]])
33
31
  });
34
-
35
- // const suggestions: Array<[MessageIds, string]> = [
36
- // ['suggestAddingHasAssertions', 'expect.hasAssertions();'],
37
- // ['suggestAddingAssertions', 'expect.assertions();'],
38
- // ];
39
32
  var _default = (0, _utils2.createRule)({
40
33
  name: __filename,
41
34
  meta: {
42
35
  docs: {
43
36
  category: 'Best Practices',
44
37
  description: 'Suggest using `expect.assertions()` OR `expect.hasAssertions()`',
45
- recommended: false,
46
- suggestion: true
38
+ recommended: false
47
39
  },
48
40
  messages: {
49
41
  hasAssertionsTakesNoArguments: '`expect.hasAssertions` expects no arguments',
@@ -77,7 +69,6 @@ var _default = (0, _utils2.createRule)({
77
69
  onlyFunctionsWithExpectInLoop: false,
78
70
  onlyFunctionsWithExpectInCallback: false
79
71
  }],
80
-
81
72
  create(context, [options]) {
82
73
  let expressionDepth = 0;
83
74
  let hasExpectInCallback = false;
@@ -85,33 +76,27 @@ var _default = (0, _utils2.createRule)({
85
76
  let hasExpectAssertionsAsFirstStatement = false;
86
77
  let inTestCaseCall = false;
87
78
  let inForLoop = false;
88
-
89
79
  const shouldCheckFunction = testFunction => {
90
80
  if (!options.onlyFunctionsWithAsyncKeyword && !options.onlyFunctionsWithExpectInLoop && !options.onlyFunctionsWithExpectInCallback) {
91
81
  return true;
92
82
  }
93
-
94
83
  if (options.onlyFunctionsWithAsyncKeyword) {
95
84
  if (testFunction.async) {
96
85
  return true;
97
86
  }
98
87
  }
99
-
100
88
  if (options.onlyFunctionsWithExpectInLoop) {
101
89
  if (hasExpectInLoop) {
102
90
  return true;
103
91
  }
104
92
  }
105
-
106
93
  if (options.onlyFunctionsWithExpectInCallback) {
107
94
  if (hasExpectInCallback) {
108
95
  return true;
109
96
  }
110
97
  }
111
-
112
98
  return false;
113
99
  };
114
-
115
100
  const checkExpectHasAssertions = expectFnCall => {
116
101
  if ((0, _utils2.getAccessorValue)(expectFnCall.members[0]) === 'hasAssertions') {
117
102
  if (expectFnCall.args.length) {
@@ -121,21 +106,17 @@ var _default = (0, _utils2.createRule)({
121
106
  suggest: [suggestRemovingExtraArguments(expectFnCall.args, 0)]
122
107
  });
123
108
  }
124
-
125
109
  return;
126
110
  }
127
-
128
111
  if (expectFnCall.args.length !== 1) {
129
112
  let {
130
113
  loc
131
114
  } = expectFnCall.matcher;
132
115
  const suggest = [];
133
-
134
116
  if (expectFnCall.args.length) {
135
117
  loc = expectFnCall.args[1].loc;
136
118
  suggest.push(suggestRemovingExtraArguments(expectFnCall.args, 1));
137
119
  }
138
-
139
120
  context.report({
140
121
  messageId: 'assertionsRequiresOneArgument',
141
122
  suggest,
@@ -143,27 +124,19 @@ var _default = (0, _utils2.createRule)({
143
124
  });
144
125
  return;
145
126
  }
146
-
147
127
  const [arg] = expectFnCall.args;
148
-
149
128
  if (arg.type === _utils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value)) {
150
129
  return;
151
130
  }
152
-
153
131
  context.report({
154
132
  messageId: 'assertionsRequiresNumberArgument',
155
133
  node: arg
156
134
  });
157
135
  };
158
-
159
136
  const enterExpression = () => inTestCaseCall && expressionDepth++;
160
-
161
137
  const exitExpression = () => inTestCaseCall && expressionDepth--;
162
-
163
138
  const enterForLoop = () => inForLoop = true;
164
-
165
139
  const exitForLoop = () => inForLoop = false;
166
-
167
140
  return {
168
141
  FunctionExpression: enterExpression,
169
142
  'FunctionExpression:exit': exitExpression,
@@ -175,64 +148,48 @@ var _default = (0, _utils2.createRule)({
175
148
  'ForInStatement:exit': exitForLoop,
176
149
  ForOfStatement: enterForLoop,
177
150
  'ForOfStatement:exit': exitForLoop,
178
-
179
151
  CallExpression(node) {
180
152
  const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
181
-
182
153
  if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'test') {
183
154
  inTestCaseCall = true;
184
155
  return;
185
156
  }
186
-
187
157
  if ((jestFnCall === null || jestFnCall === void 0 ? void 0 : jestFnCall.type) === 'expect' && inTestCaseCall) {
188
158
  var _jestFnCall$head$node;
189
-
190
159
  if (expressionDepth === 1 && isFirstStatement(node) && ((_jestFnCall$head$node = jestFnCall.head.node.parent) === null || _jestFnCall$head$node === void 0 ? void 0 : _jestFnCall$head$node.type) === _utils.AST_NODE_TYPES.MemberExpression && jestFnCall.members.length === 1 && ['assertions', 'hasAssertions'].includes((0, _utils2.getAccessorValue)(jestFnCall.members[0]))) {
191
160
  checkExpectHasAssertions(jestFnCall);
192
161
  hasExpectAssertionsAsFirstStatement = true;
193
162
  }
194
-
195
163
  if (inForLoop) {
196
164
  hasExpectInLoop = true;
197
165
  }
198
-
199
166
  if (expressionDepth > 1) {
200
167
  hasExpectInCallback = true;
201
168
  }
202
169
  }
203
170
  },
204
-
205
171
  'CallExpression:exit'(node) {
206
172
  if (!(0, _utils2.isTypeOfJestFnCall)(node, context, ['test'])) {
207
173
  return;
208
174
  }
209
-
210
175
  inTestCaseCall = false;
211
-
212
176
  if (node.arguments.length < 2) {
213
177
  return;
214
178
  }
215
-
216
179
  const [, testFn] = node.arguments;
217
-
218
180
  if (!(0, _utils2.isFunction)(testFn) || !shouldCheckFunction(testFn)) {
219
181
  return;
220
182
  }
221
-
222
183
  hasExpectInLoop = false;
223
184
  hasExpectInCallback = false;
224
-
225
185
  if (hasExpectAssertionsAsFirstStatement) {
226
186
  hasExpectAssertionsAsFirstStatement = false;
227
187
  return;
228
188
  }
229
-
230
189
  const suggestions = [];
231
-
232
190
  if (testFn.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
233
191
  suggestions.push(['suggestAddingHasAssertions', 'expect.hasAssertions();'], ['suggestAddingAssertions', 'expect.assertions();']);
234
192
  }
235
-
236
193
  context.report({
237
194
  messageId: 'haveExpectAssertions',
238
195
  node,
@@ -242,10 +199,7 @@ var _default = (0, _utils2.createRule)({
242
199
  }))
243
200
  });
244
201
  }
245
-
246
202
  };
247
203
  }
248
-
249
204
  });
250
-
251
205
  exports.default = _default;