eslint-plugin-jest 24.4.2 → 26.1.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.
Files changed (77) hide show
  1. package/README.md +75 -50
  2. package/docs/rules/expect-expect.md +42 -1
  3. package/docs/rules/max-nested-describe.md +4 -5
  4. package/docs/rules/no-conditional-expect.md +57 -3
  5. package/docs/rules/no-conditional-in-test.md +79 -0
  6. package/docs/rules/no-deprecated-functions.md +5 -0
  7. package/docs/rules/no-done-callback.md +3 -3
  8. package/docs/rules/no-if.md +5 -0
  9. package/docs/rules/no-standalone-expect.md +3 -3
  10. package/docs/rules/no-test-return-statement.md +1 -2
  11. package/docs/rules/prefer-comparison-matcher.md +55 -0
  12. package/docs/rules/prefer-equality-matcher.md +29 -0
  13. package/docs/rules/prefer-expect-assertions.md +126 -0
  14. package/docs/rules/prefer-expect-resolves.md +53 -0
  15. package/docs/rules/prefer-hooks-on-top.md +72 -48
  16. package/docs/rules/{lowercase-name.md → prefer-lowercase-title.md} +7 -7
  17. package/docs/rules/prefer-snapshot-hint.md +188 -0
  18. package/docs/rules/prefer-to-be.md +53 -0
  19. package/docs/rules/require-hook.md +187 -0
  20. package/docs/rules/require-top-level-describe.md +28 -0
  21. package/docs/rules/{valid-describe.md → valid-describe-callback.md} +1 -1
  22. package/docs/rules/valid-expect-in-promise.md +55 -14
  23. package/docs/rules/valid-expect.md +13 -0
  24. package/docs/rules/valid-title.md +30 -2
  25. package/lib/index.js +2 -3
  26. package/lib/processors/snapshot-processor.js +1 -1
  27. package/lib/rules/consistent-test-it.js +20 -20
  28. package/lib/rules/detectJestVersion.js +29 -0
  29. package/lib/rules/expect-expect.js +25 -11
  30. package/lib/rules/max-nested-describe.js +5 -5
  31. package/lib/rules/no-conditional-expect.js +9 -9
  32. package/lib/rules/no-conditional-in-test.js +60 -0
  33. package/lib/rules/no-deprecated-functions.js +14 -32
  34. package/lib/rules/no-done-callback.js +10 -10
  35. package/lib/rules/no-export.js +6 -6
  36. package/lib/rules/no-focused-tests.js +11 -11
  37. package/lib/rules/no-identical-title.js +3 -3
  38. package/lib/rules/no-if.js +13 -11
  39. package/lib/rules/no-interpolation-in-snapshots.js +6 -6
  40. package/lib/rules/no-jasmine-globals.js +10 -10
  41. package/lib/rules/no-large-snapshots.js +11 -11
  42. package/lib/rules/no-standalone-expect.js +14 -14
  43. package/lib/rules/no-test-prefixes.js +6 -6
  44. package/lib/rules/no-test-return-statement.js +8 -8
  45. package/lib/rules/prefer-comparison-matcher.js +139 -0
  46. package/lib/rules/prefer-equality-matcher.js +98 -0
  47. package/lib/rules/prefer-expect-assertions.js +93 -11
  48. package/lib/rules/prefer-expect-resolves.js +48 -0
  49. package/lib/rules/prefer-hooks-on-top.js +1 -1
  50. package/lib/rules/{lowercase-name.js → prefer-lowercase-title.js} +20 -1
  51. package/lib/rules/prefer-snapshot-hint.js +112 -0
  52. package/lib/rules/prefer-spy-on.js +9 -9
  53. package/lib/rules/prefer-to-be.js +136 -0
  54. package/lib/rules/prefer-to-contain.js +19 -67
  55. package/lib/rules/prefer-to-have-length.js +9 -14
  56. package/lib/rules/prefer-todo.js +9 -9
  57. package/lib/rules/require-hook.js +121 -0
  58. package/lib/rules/require-top-level-describe.js +40 -6
  59. package/lib/rules/utils.js +34 -30
  60. package/lib/rules/{valid-describe.js → valid-describe-callback.js} +9 -9
  61. package/lib/rules/valid-expect-in-promise.js +336 -67
  62. package/lib/rules/valid-expect.js +36 -19
  63. package/lib/rules/valid-title.js +61 -61
  64. package/package.json +40 -27
  65. package/CHANGELOG.md +0 -513
  66. package/docs/rules/no-expect-resolves.md +0 -47
  67. package/docs/rules/no-truthy-falsy.md +0 -53
  68. package/docs/rules/no-try-expect.md +0 -63
  69. package/docs/rules/prefer-inline-snapshots.md +0 -51
  70. package/docs/rules/prefer-to-be-null.md +0 -33
  71. package/docs/rules/prefer-to-be-undefined.md +0 -33
  72. package/lib/rules/no-expect-resolves.js +0 -40
  73. package/lib/rules/no-truthy-falsy.js +0 -58
  74. package/lib/rules/no-try-expect.js +0 -89
  75. package/lib/rules/prefer-inline-snapshots.js +0 -69
  76. package/lib/rules/prefer-to-be-null.js +0 -67
  77. package/lib/rules/prefer-to-be-undefined.js +0 -67
@@ -5,9 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _experimentalUtils = require("@typescript-eslint/experimental-utils");
8
+ var _utils = require("@typescript-eslint/utils");
9
9
 
10
- var _utils = require("./utils");
10
+ var _utils2 = require("./utils");
11
11
 
12
12
  const getBlockType = statement => {
13
13
  const func = statement.parent;
@@ -18,19 +18,19 @@ const getBlockType = statement => {
18
18
  } // functionDeclaration: function func() {}
19
19
 
20
20
 
21
- if (func.type === _experimentalUtils.AST_NODE_TYPES.FunctionDeclaration) {
21
+ if (func.type === _utils.AST_NODE_TYPES.FunctionDeclaration) {
22
22
  return 'function';
23
23
  }
24
24
 
25
- if ((0, _utils.isFunction)(func) && func.parent) {
25
+ if ((0, _utils2.isFunction)(func) && func.parent) {
26
26
  const expr = func.parent; // arrow function or function expr
27
27
 
28
- if (expr.type === _experimentalUtils.AST_NODE_TYPES.VariableDeclarator) {
28
+ if (expr.type === _utils.AST_NODE_TYPES.VariableDeclarator) {
29
29
  return 'function';
30
30
  } // if it's not a variable, it will be callExpr, we only care about describe
31
31
 
32
32
 
33
- if (expr.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && (0, _utils.isDescribeCall)(expr)) {
33
+ if (expr.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isDescribeCall)(expr)) {
34
34
  return 'describe';
35
35
  }
36
36
  }
@@ -38,7 +38,7 @@ const getBlockType = statement => {
38
38
  return null;
39
39
  };
40
40
 
41
- var _default = (0, _utils.createRule)({
41
+ var _default = (0, _utils2.createRule)({
42
42
  name: __filename,
43
43
  meta: {
44
44
  docs: {
@@ -71,16 +71,16 @@ var _default = (0, _utils.createRule)({
71
71
  }]) {
72
72
  const callStack = [];
73
73
 
74
- const isCustomTestBlockFunction = node => additionalTestBlockFunctions.includes((0, _utils.getNodeName)(node) || '');
74
+ const isCustomTestBlockFunction = node => additionalTestBlockFunctions.includes((0, _utils2.getNodeName)(node) || '');
75
75
 
76
- const isTestBlock = node => (0, _utils.isTestCaseCall)(node) || isCustomTestBlockFunction(node);
76
+ const isTestBlock = node => (0, _utils2.isTestCaseCall)(node) || isCustomTestBlockFunction(node);
77
77
 
78
78
  return {
79
79
  CallExpression(node) {
80
- if ((0, _utils.isExpectCall)(node)) {
80
+ if ((0, _utils2.isExpectCall)(node)) {
81
81
  const parent = callStack[callStack.length - 1];
82
82
 
83
- if (!parent || parent === _utils.DescribeAlias.describe) {
83
+ if (!parent || parent === _utils2.DescribeAlias.describe) {
84
84
  context.report({
85
85
  node,
86
86
  messageId: 'unexpectedExpect'
@@ -94,7 +94,7 @@ var _default = (0, _utils.createRule)({
94
94
  callStack.push('test');
95
95
  }
96
96
 
97
- if (node.callee.type === _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression) {
97
+ if (node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression) {
98
98
  callStack.push('template');
99
99
  }
100
100
  },
@@ -102,7 +102,7 @@ var _default = (0, _utils.createRule)({
102
102
  'CallExpression:exit'(node) {
103
103
  const top = callStack[callStack.length - 1];
104
104
 
105
- if (top === 'test' && isTestBlock(node) && node.callee.type !== _experimentalUtils.AST_NODE_TYPES.MemberExpression || top === 'template' && node.callee.type === _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression) {
105
+ if (top === 'test' && isTestBlock(node) && node.callee.type !== _utils.AST_NODE_TYPES.MemberExpression || top === 'template' && node.callee.type === _utils.AST_NODE_TYPES.TaggedTemplateExpression) {
106
106
  callStack.pop();
107
107
  }
108
108
  },
@@ -124,7 +124,7 @@ var _default = (0, _utils.createRule)({
124
124
  ArrowFunctionExpression(node) {
125
125
  var _node$parent;
126
126
 
127
- if (((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) !== _experimentalUtils.AST_NODE_TYPES.CallExpression) {
127
+ if (((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) !== _utils.AST_NODE_TYPES.CallExpression) {
128
128
  callStack.push('arrow');
129
129
  }
130
130
  },
@@ -5,11 +5,11 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _experimentalUtils = require("@typescript-eslint/experimental-utils");
8
+ var _utils = require("@typescript-eslint/utils");
9
9
 
10
- var _utils = require("./utils");
10
+ var _utils2 = require("./utils");
11
11
 
12
- var _default = (0, _utils.createRule)({
12
+ var _default = (0, _utils2.createRule)({
13
13
  name: __filename,
14
14
  meta: {
15
15
  docs: {
@@ -29,11 +29,11 @@ var _default = (0, _utils.createRule)({
29
29
  create(context) {
30
30
  return {
31
31
  CallExpression(node) {
32
- const nodeName = (0, _utils.getNodeName)(node.callee);
33
- if (!nodeName || !(0, _utils.isDescribeCall)(node) && !(0, _utils.isTestCaseCall)(node)) return;
32
+ const nodeName = (0, _utils2.getNodeName)(node.callee);
33
+ if (!nodeName || !(0, _utils2.isDescribeCall)(node) && !(0, _utils2.isTestCaseCall)(node)) return;
34
34
  const preferredNodeName = getPreferredNodeName(nodeName);
35
35
  if (!preferredNodeName) return;
36
- const funcNode = node.callee.type === _experimentalUtils.AST_NODE_TYPES.TaggedTemplateExpression ? node.callee.tag : node.callee.type === _experimentalUtils.AST_NODE_TYPES.CallExpression ? node.callee.callee : node.callee;
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;
37
37
  context.report({
38
38
  messageId: 'usePreferredName',
39
39
  node: node.callee,
@@ -5,21 +5,21 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _experimentalUtils = require("@typescript-eslint/experimental-utils");
8
+ var _utils = require("@typescript-eslint/utils");
9
9
 
10
- var _utils = require("./utils");
10
+ var _utils2 = require("./utils");
11
11
 
12
12
  const getBody = args => {
13
13
  const [, secondArg] = args;
14
14
 
15
- if (secondArg && (0, _utils.isFunction)(secondArg) && secondArg.body.type === _experimentalUtils.AST_NODE_TYPES.BlockStatement) {
15
+ if (secondArg && (0, _utils2.isFunction)(secondArg) && secondArg.body.type === _utils.AST_NODE_TYPES.BlockStatement) {
16
16
  return secondArg.body.body;
17
17
  }
18
18
 
19
19
  return [];
20
20
  };
21
21
 
22
- var _default = (0, _utils.createRule)({
22
+ var _default = (0, _utils2.createRule)({
23
23
  name: __filename,
24
24
  meta: {
25
25
  docs: {
@@ -38,9 +38,9 @@ var _default = (0, _utils.createRule)({
38
38
  create(context) {
39
39
  return {
40
40
  CallExpression(node) {
41
- if (!(0, _utils.isTestCaseCall)(node)) return;
41
+ if (!(0, _utils2.isTestCaseCall)(node)) return;
42
42
  const body = getBody(node.arguments);
43
- const returnStmt = body.find(t => t.type === _experimentalUtils.AST_NODE_TYPES.ReturnStatement);
43
+ const returnStmt = body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement);
44
44
  if (!returnStmt) return;
45
45
  context.report({
46
46
  messageId: 'noReturnValue',
@@ -50,9 +50,9 @@ var _default = (0, _utils.createRule)({
50
50
 
51
51
  FunctionDeclaration(node) {
52
52
  const declaredVariables = context.getDeclaredVariables(node);
53
- const testCallExpressions = (0, _utils.getTestCallExpressionsFromDeclaredVariables)(declaredVariables);
53
+ const testCallExpressions = (0, _utils2.getTestCallExpressionsFromDeclaredVariables)(declaredVariables);
54
54
  if (testCallExpressions.length === 0) return;
55
- const returnStmt = node.body.body.find(t => t.type === _experimentalUtils.AST_NODE_TYPES.ReturnStatement);
55
+ const returnStmt = node.body.body.find(t => t.type === _utils.AST_NODE_TYPES.ReturnStatement);
56
56
  if (!returnStmt) return;
57
57
  context.report({
58
58
  messageId: 'noReturnValue',
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _utils = require("@typescript-eslint/utils");
9
+
10
+ var _utils2 = require("./utils");
11
+
12
+ const isBooleanLiteral = node => node.type === _utils.AST_NODE_TYPES.Literal && typeof node.value === 'boolean';
13
+
14
+ /**
15
+ * Checks if the given `ParsedExpectMatcher` is a call to one of the equality matchers,
16
+ * with a boolean literal as the sole argument.
17
+ *
18
+ * @example javascript
19
+ * toBe(true);
20
+ * toEqual(false);
21
+ *
22
+ * @param {ParsedExpectMatcher} matcher
23
+ *
24
+ * @return {matcher is ParsedBooleanEqualityMatcher}
25
+ */
26
+ const isBooleanEqualityMatcher = matcher => (0, _utils2.isParsedEqualityMatcherCall)(matcher) && isBooleanLiteral((0, _utils2.followTypeAssertionChain)(matcher.arguments[0]));
27
+
28
+ const isString = node => {
29
+ return (0, _utils2.isStringNode)(node) || node.type === _utils.AST_NODE_TYPES.TemplateLiteral;
30
+ };
31
+
32
+ const isComparingToString = expression => {
33
+ return isString(expression.left) || isString(expression.right);
34
+ };
35
+
36
+ const invertOperator = operator => {
37
+ switch (operator) {
38
+ case '>':
39
+ return '<=';
40
+
41
+ case '<':
42
+ return '>=';
43
+
44
+ case '>=':
45
+ return '<';
46
+
47
+ case '<=':
48
+ return '>';
49
+ }
50
+
51
+ return null;
52
+ };
53
+
54
+ const determineMatcher = (operator, negated) => {
55
+ const op = negated ? invertOperator(operator) : operator;
56
+
57
+ switch (op) {
58
+ case '>':
59
+ return 'toBeGreaterThan';
60
+
61
+ case '<':
62
+ return 'toBeLessThan';
63
+
64
+ case '>=':
65
+ return 'toBeGreaterThanOrEqual';
66
+
67
+ case '<=':
68
+ return 'toBeLessThanOrEqual';
69
+ }
70
+
71
+ return null;
72
+ };
73
+
74
+ var _default = (0, _utils2.createRule)({
75
+ name: __filename,
76
+ meta: {
77
+ docs: {
78
+ category: 'Best Practices',
79
+ description: 'Suggest using the built-in comparison matchers',
80
+ recommended: false
81
+ },
82
+ messages: {
83
+ useToBeComparison: 'Prefer using `{{ preferredMatcher }}` instead'
84
+ },
85
+ fixable: 'code',
86
+ type: 'suggestion',
87
+ schema: []
88
+ },
89
+ defaultOptions: [],
90
+
91
+ create(context) {
92
+ return {
93
+ CallExpression(node) {
94
+ if (!(0, _utils2.isExpectCall)(node)) {
95
+ return;
96
+ }
97
+
98
+ const {
99
+ expect: {
100
+ arguments: [comparison],
101
+ range: [, expectCallEnd]
102
+ },
103
+ matcher,
104
+ modifier
105
+ } = (0, _utils2.parseExpectCall)(node);
106
+
107
+ if (!matcher || (comparison === null || comparison === void 0 ? void 0 : comparison.type) !== _utils.AST_NODE_TYPES.BinaryExpression || isComparingToString(comparison) || !isBooleanEqualityMatcher(matcher)) {
108
+ return;
109
+ }
110
+
111
+ const preferredMatcher = determineMatcher(comparison.operator, (0, _utils2.followTypeAssertionChain)(matcher.arguments[0]).value === !!modifier);
112
+
113
+ if (!preferredMatcher) {
114
+ return;
115
+ }
116
+
117
+ context.report({
118
+ fix(fixer) {
119
+ const sourceCode = context.getSourceCode();
120
+ return [// replace the comparison argument with the left-hand side of the comparison
121
+ fixer.replaceText(comparison, sourceCode.getText(comparison.left)), // replace the current matcher & modifier with the preferred matcher
122
+ fixer.replaceTextRange([expectCallEnd, matcher.node.range[1]], `.${preferredMatcher}`), // replace the matcher argument with the right-hand side of the comparison
123
+ fixer.replaceText(matcher.arguments[0], sourceCode.getText(comparison.right))];
124
+ },
125
+
126
+ messageId: 'useToBeComparison',
127
+ data: {
128
+ preferredMatcher
129
+ },
130
+ node: (modifier || matcher).node.property
131
+ });
132
+ }
133
+
134
+ };
135
+ }
136
+
137
+ });
138
+
139
+ exports.default = _default;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _utils = require("@typescript-eslint/utils");
9
+
10
+ var _utils2 = require("./utils");
11
+
12
+ const isBooleanLiteral = node => node.type === _utils.AST_NODE_TYPES.Literal && typeof node.value === 'boolean';
13
+
14
+ /**
15
+ * Checks if the given `ParsedExpectMatcher` is a call to one of the equality matchers,
16
+ * with a boolean literal as the sole argument.
17
+ *
18
+ * @example javascript
19
+ * toBe(true);
20
+ * toEqual(false);
21
+ *
22
+ * @param {ParsedExpectMatcher} matcher
23
+ *
24
+ * @return {matcher is ParsedBooleanEqualityMatcher}
25
+ */
26
+ const isBooleanEqualityMatcher = matcher => (0, _utils2.isParsedEqualityMatcherCall)(matcher) && isBooleanLiteral((0, _utils2.followTypeAssertionChain)(matcher.arguments[0]));
27
+
28
+ var _default = (0, _utils2.createRule)({
29
+ name: __filename,
30
+ meta: {
31
+ docs: {
32
+ category: 'Best Practices',
33
+ description: 'Suggest using the built-in equality matchers',
34
+ recommended: false,
35
+ suggestion: true
36
+ },
37
+ messages: {
38
+ useEqualityMatcher: 'Prefer using one of the equality matchers instead',
39
+ suggestEqualityMatcher: 'Use `{{ equalityMatcher }}`'
40
+ },
41
+ hasSuggestions: true,
42
+ type: 'suggestion',
43
+ schema: []
44
+ },
45
+ defaultOptions: [],
46
+
47
+ create(context) {
48
+ return {
49
+ CallExpression(node) {
50
+ if (!(0, _utils2.isExpectCall)(node)) {
51
+ return;
52
+ }
53
+
54
+ const {
55
+ expect: {
56
+ arguments: [comparison],
57
+ range: [, expectCallEnd]
58
+ },
59
+ matcher,
60
+ modifier
61
+ } = (0, _utils2.parseExpectCall)(node);
62
+
63
+ if (!matcher || (comparison === null || comparison === void 0 ? void 0 : comparison.type) !== _utils.AST_NODE_TYPES.BinaryExpression || comparison.operator !== '===' && comparison.operator !== '!==' || !isBooleanEqualityMatcher(matcher)) {
64
+ return;
65
+ }
66
+
67
+ const matcherValue = (0, _utils2.followTypeAssertionChain)(matcher.arguments[0]).value; // we need to negate the expectation if the current expected
68
+ // value is itself negated by the "not" modifier
69
+
70
+ const addNotModifier = (comparison.operator === '!==' ? !matcherValue : matcherValue) === !!modifier;
71
+
72
+ const buildFixer = equalityMatcher => fixer => {
73
+ const sourceCode = context.getSourceCode();
74
+ return [// replace the comparison argument with the left-hand side of the comparison
75
+ fixer.replaceText(comparison, sourceCode.getText(comparison.left)), // replace the current matcher & modifier with the preferred matcher
76
+ fixer.replaceTextRange([expectCallEnd, matcher.node.range[1]], addNotModifier ? `.${_utils2.ModifierName.not}.${equalityMatcher}` : `.${equalityMatcher}`), // replace the matcher argument with the right-hand side of the comparison
77
+ fixer.replaceText(matcher.arguments[0], sourceCode.getText(comparison.right))];
78
+ };
79
+
80
+ context.report({
81
+ messageId: 'useEqualityMatcher',
82
+ suggest: ['toBe', 'toEqual', 'toStrictEqual'].map(equalityMatcher => ({
83
+ messageId: 'suggestEqualityMatcher',
84
+ data: {
85
+ equalityMatcher
86
+ },
87
+ fix: buildFixer(equalityMatcher)
88
+ })),
89
+ node: (modifier || matcher).node.property
90
+ });
91
+ }
92
+
93
+ };
94
+ }
95
+
96
+ });
97
+
98
+ exports.default = _default;
@@ -5,13 +5,13 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _experimentalUtils = require("@typescript-eslint/experimental-utils");
8
+ var _utils = require("@typescript-eslint/utils");
9
9
 
10
- var _utils = require("./utils");
10
+ var _utils2 = require("./utils");
11
11
 
12
- const isExpectAssertionsOrHasAssertionsCall = expression => expression.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && expression.callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(expression.callee.object, 'expect') && (0, _utils.isSupportedAccessor)(expression.callee.property) && ['assertions', 'hasAssertions'].includes((0, _utils.getAccessorValue)(expression.callee.property));
12
+ const isExpectAssertionsOrHasAssertionsCall = expression => expression.type === _utils.AST_NODE_TYPES.CallExpression && expression.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(expression.callee.object, 'expect') && (0, _utils2.isSupportedAccessor)(expression.callee.property) && ['assertions', 'hasAssertions'].includes((0, _utils2.getAccessorValue)(expression.callee.property));
13
13
 
14
- const isFirstLineExprStmt = functionBody => functionBody[0] && functionBody[0].type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement;
14
+ const isFirstLineExprStmt = functionBody => functionBody[0] && functionBody[0].type === _utils.AST_NODE_TYPES.ExpressionStatement;
15
15
 
16
16
  const suggestRemovingExtraArguments = (args, extraArgsStartAt) => ({
17
17
  messageId: 'suggestRemovingExtraArguments',
@@ -20,7 +20,7 @@ const suggestRemovingExtraArguments = (args, extraArgsStartAt) => ({
20
20
 
21
21
  const suggestions = [['suggestAddingHasAssertions', 'expect.hasAssertions();'], ['suggestAddingAssertions', 'expect.assertions();']];
22
22
 
23
- var _default = (0, _utils.createRule)({
23
+ var _default = (0, _utils2.createRule)({
24
24
  name: __filename,
25
25
  meta: {
26
26
  docs: {
@@ -45,19 +45,95 @@ var _default = (0, _utils.createRule)({
45
45
  properties: {
46
46
  onlyFunctionsWithAsyncKeyword: {
47
47
  type: 'boolean'
48
+ },
49
+ onlyFunctionsWithExpectInLoop: {
50
+ type: 'boolean'
51
+ },
52
+ onlyFunctionsWithExpectInCallback: {
53
+ type: 'boolean'
48
54
  }
49
55
  },
50
56
  additionalProperties: false
51
57
  }]
52
58
  },
53
59
  defaultOptions: [{
54
- onlyFunctionsWithAsyncKeyword: false
60
+ onlyFunctionsWithAsyncKeyword: false,
61
+ onlyFunctionsWithExpectInLoop: false,
62
+ onlyFunctionsWithExpectInCallback: false
55
63
  }],
56
64
 
57
65
  create(context, [options]) {
66
+ let expressionDepth = 0;
67
+ let hasExpectInCallback = false;
68
+ let hasExpectInLoop = false;
69
+ let inTestCaseCall = false;
70
+ let inForLoop = false;
71
+
72
+ const shouldCheckFunction = testFunction => {
73
+ if (!options.onlyFunctionsWithAsyncKeyword && !options.onlyFunctionsWithExpectInLoop && !options.onlyFunctionsWithExpectInCallback) {
74
+ return true;
75
+ }
76
+
77
+ if (options.onlyFunctionsWithAsyncKeyword) {
78
+ if (testFunction.async) {
79
+ return true;
80
+ }
81
+ }
82
+
83
+ if (options.onlyFunctionsWithExpectInLoop) {
84
+ if (hasExpectInLoop) {
85
+ return true;
86
+ }
87
+ }
88
+
89
+ if (options.onlyFunctionsWithExpectInCallback) {
90
+ if (hasExpectInCallback) {
91
+ return true;
92
+ }
93
+ }
94
+
95
+ return false;
96
+ };
97
+
98
+ const enterExpression = () => inTestCaseCall && expressionDepth++;
99
+
100
+ const exitExpression = () => inTestCaseCall && expressionDepth--;
101
+
102
+ const enterForLoop = () => inForLoop = true;
103
+
104
+ const exitForLoop = () => inForLoop = false;
105
+
58
106
  return {
107
+ FunctionExpression: enterExpression,
108
+ 'FunctionExpression:exit': exitExpression,
109
+ ArrowFunctionExpression: enterExpression,
110
+ 'ArrowFunctionExpression:exit': exitExpression,
111
+ ForStatement: enterForLoop,
112
+ 'ForStatement:exit': exitForLoop,
113
+ ForInStatement: enterForLoop,
114
+ 'ForInStatement:exit': exitForLoop,
115
+ ForOfStatement: enterForLoop,
116
+ 'ForOfStatement:exit': exitForLoop,
117
+
59
118
  CallExpression(node) {
60
- if (!(0, _utils.isTestCaseCall)(node)) {
119
+ if ((0, _utils2.isTestCaseCall)(node)) {
120
+ inTestCaseCall = true;
121
+ return;
122
+ }
123
+
124
+ if ((0, _utils2.isExpectCall)(node) && inTestCaseCall) {
125
+ if (inForLoop) {
126
+ hasExpectInLoop = true;
127
+ }
128
+
129
+ if (expressionDepth > 1) {
130
+ hasExpectInCallback = true;
131
+ }
132
+ }
133
+ },
134
+
135
+ 'CallExpression:exit'(node) {
136
+ if (!(0, _utils2.isTestCaseCall)(node)) {
61
137
  return;
62
138
  }
63
139
 
@@ -67,10 +143,16 @@ var _default = (0, _utils.createRule)({
67
143
 
68
144
  const [, testFn] = node.arguments;
69
145
 
70
- if (!(0, _utils.isFunction)(testFn) || testFn.body.type !== _experimentalUtils.AST_NODE_TYPES.BlockStatement || options.onlyFunctionsWithAsyncKeyword && !testFn.async) {
146
+ if (!(0, _utils2.isFunction)(testFn) || testFn.body.type !== _utils.AST_NODE_TYPES.BlockStatement) {
147
+ return;
148
+ }
149
+
150
+ if (!shouldCheckFunction(testFn)) {
71
151
  return;
72
152
  }
73
153
 
154
+ hasExpectInLoop = false;
155
+ hasExpectInCallback = false;
74
156
  const testFuncBody = testFn.body.body;
75
157
 
76
158
  if (!isFirstLineExprStmt(testFuncBody)) {
@@ -99,7 +181,7 @@ var _default = (0, _utils.createRule)({
99
181
  return;
100
182
  }
101
183
 
102
- if ((0, _utils.isSupportedAccessor)(testFuncFirstLine.callee.property, 'hasAssertions')) {
184
+ if ((0, _utils2.isSupportedAccessor)(testFuncFirstLine.callee.property, 'hasAssertions')) {
103
185
  if (testFuncFirstLine.arguments.length) {
104
186
  context.report({
105
187
  messageId: 'hasAssertionsTakesNoArguments',
@@ -111,7 +193,7 @@ var _default = (0, _utils.createRule)({
111
193
  return;
112
194
  }
113
195
 
114
- if (!(0, _utils.hasOnlyOneArgument)(testFuncFirstLine)) {
196
+ if (!(0, _utils2.hasOnlyOneArgument)(testFuncFirstLine)) {
115
197
  let {
116
198
  loc
117
199
  } = testFuncFirstLine.callee.property;
@@ -132,7 +214,7 @@ var _default = (0, _utils.createRule)({
132
214
 
133
215
  const [arg] = testFuncFirstLine.arguments;
134
216
 
135
- if (arg.type === _experimentalUtils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value)) {
217
+ if (arg.type === _utils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value)) {
136
218
  return;
137
219
  }
138
220
 
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _utils = require("@typescript-eslint/utils");
9
+
10
+ var _utils2 = require("./utils");
11
+
12
+ var _default = (0, _utils2.createRule)({
13
+ name: __filename,
14
+ meta: {
15
+ docs: {
16
+ category: 'Best Practices',
17
+ description: 'Prefer `await expect(...).resolves` over `expect(await ...)` syntax',
18
+ recommended: false
19
+ },
20
+ fixable: 'code',
21
+ messages: {
22
+ expectResolves: 'Use `await expect(...).resolves instead.'
23
+ },
24
+ schema: [],
25
+ type: 'suggestion'
26
+ },
27
+ defaultOptions: [],
28
+ create: context => ({
29
+ CallExpression(node) {
30
+ const [awaitNode] = node.arguments;
31
+
32
+ if ((0, _utils2.isExpectCall)(node) && (awaitNode === null || awaitNode === void 0 ? void 0 : awaitNode.type) === _utils.AST_NODE_TYPES.AwaitExpression) {
33
+ context.report({
34
+ node: node.arguments[0],
35
+ messageId: 'expectResolves',
36
+
37
+ fix(fixer) {
38
+ return [fixer.insertTextBefore(node, 'await '), fixer.removeRange([awaitNode.range[0], awaitNode.argument.range[0]]), fixer.insertTextAfter(node, '.resolves')];
39
+ }
40
+
41
+ });
42
+ }
43
+ }
44
+
45
+ })
46
+ });
47
+
48
+ exports.default = _default;
@@ -16,7 +16,7 @@ var _default = (0, _utils.createRule)({
16
16
  recommended: false
17
17
  },
18
18
  messages: {
19
- noHookOnTop: 'Move all hooks before test cases'
19
+ noHookOnTop: 'Hooks should come before test cases'
20
20
  },
21
21
  schema: [],
22
22
  type: 'suggestion'
@@ -21,6 +21,24 @@ const findNodeNameAndArgument = node => {
21
21
  return [(0, _utils.getNodeName)(node).split('.')[0], node.arguments[0]];
22
22
  };
23
23
 
24
+ const populateIgnores = ignore => {
25
+ const ignores = [];
26
+
27
+ if (ignore.includes(_utils.DescribeAlias.describe)) {
28
+ ignores.push(...Object.keys(_utils.DescribeAlias));
29
+ }
30
+
31
+ if (ignore.includes(_utils.TestCaseName.test)) {
32
+ ignores.push(...Object.keys(_utils.TestCaseName).filter(k => k.endsWith(_utils.TestCaseName.test)));
33
+ }
34
+
35
+ if (ignore.includes(_utils.TestCaseName.it)) {
36
+ ignores.push(...Object.keys(_utils.TestCaseName).filter(k => k.endsWith(_utils.TestCaseName.it)));
37
+ }
38
+
39
+ return ignores;
40
+ };
41
+
24
42
  var _default = (0, _utils.createRule)({
25
43
  name: __filename,
26
44
  meta: {
@@ -70,6 +88,7 @@ var _default = (0, _utils.createRule)({
70
88
  allowedPrefixes = [],
71
89
  ignoreTopLevelDescribe
72
90
  }]) {
91
+ const ignores = populateIgnores(ignore);
73
92
  let numberOfDescribeBlocks = 0;
74
93
  return {
75
94
  CallExpression(node) {
@@ -96,7 +115,7 @@ var _default = (0, _utils.createRule)({
96
115
 
97
116
  const firstCharacter = description.charAt(0);
98
117
 
99
- if (!firstCharacter || firstCharacter === firstCharacter.toLowerCase() || ignore.includes(name)) {
118
+ if (!firstCharacter || firstCharacter === firstCharacter.toLowerCase() || ignores.includes(name)) {
100
119
  return;
101
120
  }
102
121