eslint-plugin-jest 22.15.0 → 22.17.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 (51) hide show
  1. package/README.md +42 -40
  2. package/docs/rules/prefer-to-be-null.md +7 -2
  3. package/docs/rules/prefer-to-be-undefined.md +7 -2
  4. package/docs/rules/prefer-to-contain.md +8 -10
  5. package/docs/rules/prefer-to-have-length.md +7 -3
  6. package/docs/rules/require-top-level-describe.md +52 -0
  7. package/lib/__tests__/rules.test.js +5 -4
  8. package/lib/index.js +2 -3
  9. package/lib/rules/consistent-test-it.js +7 -7
  10. package/lib/rules/expect-expect.js +3 -3
  11. package/lib/rules/lowercase-name.js +3 -3
  12. package/lib/rules/no-alias-methods.js +18 -14
  13. package/lib/rules/no-commented-out-tests.js +2 -2
  14. package/lib/rules/no-disabled-tests.js +4 -4
  15. package/lib/rules/no-duplicate-hooks.js +5 -5
  16. package/lib/rules/no-empty-title.js +8 -14
  17. package/lib/rules/no-expect-resolves.js +3 -3
  18. package/lib/rules/no-export.js +3 -3
  19. package/lib/rules/no-focused-tests.js +4 -4
  20. package/lib/rules/no-hooks.js +3 -3
  21. package/lib/rules/no-identical-title.js +9 -9
  22. package/lib/rules/no-if.js +5 -5
  23. package/lib/rules/no-jasmine-globals.js +4 -4
  24. package/lib/rules/no-jest-import.js +2 -2
  25. package/lib/rules/no-large-snapshots.js +25 -18
  26. package/lib/rules/no-mocks-import.js +18 -7
  27. package/lib/rules/no-standalone-expect.js +8 -8
  28. package/lib/rules/no-test-callback.js +5 -5
  29. package/lib/rules/no-test-prefixes.js +4 -4
  30. package/lib/rules/no-test-return-statement.js +4 -4
  31. package/lib/rules/no-truthy-falsy.js +31 -19
  32. package/lib/rules/no-try-expect.js +5 -5
  33. package/lib/rules/prefer-called-with.js +23 -11
  34. package/lib/rules/prefer-expect-assertions.js +45 -34
  35. package/lib/rules/prefer-inline-snapshots.js +2 -2
  36. package/lib/rules/prefer-spy-on.js +4 -4
  37. package/lib/rules/prefer-strict-equal.js +10 -12
  38. package/lib/rules/prefer-to-be-null.js +34 -16
  39. package/lib/rules/prefer-to-be-undefined.js +34 -16
  40. package/lib/rules/prefer-to-contain.js +112 -51
  41. package/lib/rules/prefer-to-have-length.js +47 -14
  42. package/lib/rules/prefer-todo.js +13 -17
  43. package/lib/rules/require-top-level-describe.js +66 -0
  44. package/lib/rules/require-tothrow-message.js +20 -15
  45. package/lib/rules/utils.js +486 -0
  46. package/lib/rules/valid-describe.js +36 -44
  47. package/lib/rules/valid-expect-in-promise.js +71 -66
  48. package/lib/rules/valid-expect.js +140 -173
  49. package/package.json +6 -5
  50. package/lib/rules/tsUtils.js +0 -250
  51. package/lib/rules/util.js +0 -100
@@ -5,7 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _util = require("./util");
8
+ var _experimentalUtils = require("@typescript-eslint/experimental-utils");
9
+
10
+ var _utils = require("./utils");
9
11
 
10
12
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
11
13
 
@@ -15,84 +17,143 @@ function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d =
15
17
 
16
18
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
17
19
 
18
- const isEqualityCheck = node => (0, _util.method)(node) && ((0, _util.method)(node).name === 'toBe' || (0, _util.method)(node).name === 'toEqual');
19
-
20
- const isArgumentValid = node => (0, _util.argument)(node).value === true || (0, _util.argument)(node).value === false;
21
-
22
- const hasOneArgument = node => node.arguments && node.arguments.length === 1;
23
-
24
- const isValidEqualityCheck = node => isEqualityCheck(node) && hasOneArgument(node.parent.parent) && isArgumentValid(node);
25
-
26
- const isEqualityNegation = node => (0, _util.method)(node).name === 'not' && isValidEqualityCheck(node.parent);
27
-
28
- const hasIncludesMethod = node => node.arguments[0] && node.arguments[0].callee && node.arguments[0].callee.property && node.arguments[0].callee.property.name === 'includes';
29
-
30
- const isValidIncludesMethod = node => hasIncludesMethod(node) && hasOneArgument(node.arguments[0]);
31
-
32
- const getNegationFixes = (node, sourceCode, fixer) => {
33
- const negationPropertyDot = sourceCode.getFirstTokenBetween(node.parent.object, node.parent.property, token => token.value === '.');
34
- const toContainFunc = isEqualityNegation(node) && (0, _util.argument)(node.parent).value ? 'not.toContain' : 'toContain'; //.includes function argument
35
-
36
- const _node$arguments$0$arg = _slicedToArray(node.arguments[0].arguments, 1),
37
- containArg = _node$arguments$0$arg[0];
20
+ const isBooleanLiteral = node => node.type === _experimentalUtils.AST_NODE_TYPES.Literal && typeof node.value === 'boolean';
21
+
22
+ /**
23
+ * Checks if the given `ParsedExpectMatcher` is a call to one of the equality matchers,
24
+ * with a boolean literal as the sole argument.
25
+ *
26
+ * @example javascript
27
+ * toBe(true);
28
+ * toEqual(false);
29
+ *
30
+ * @param {ParsedExpectMatcher} matcher
31
+ *
32
+ * @return {matcher is ParsedBooleanEqualityMatcher}
33
+ */
34
+ const isBooleanEqualityMatcher = matcher => (0, _utils.isParsedEqualityMatcherCall)(matcher) && isBooleanLiteral((0, _utils.followTypeAssertionChain)(matcher.arguments[0]));
35
+
36
+ /**
37
+ * Checks if the given `node` is a `CallExpression` representing the calling
38
+ * of an `includes`-like method that can be 'fixed' (using `toContain`).
39
+ *
40
+ * @param {CallExpression} node
41
+ *
42
+ * @return {node is FixableIncludesCallExpression}
43
+ *
44
+ * @todo support `['includes']()` syntax (remove last property.type check to begin)
45
+ * @todo break out into `isMethodCall<Name extends string>(node: TSESTree.Node, method: Name)` util-fn
46
+ */
47
+ const isFixableIncludesCallExpression = node => node.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && node.callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(node.callee.property, 'includes') && node.callee.property.type === _experimentalUtils.AST_NODE_TYPES.Identifier && (0, _utils.hasOnlyOneArgument)(node);
48
+
49
+ const buildToContainFuncExpectation = negated => negated ? `${_utils.ModifierName.not}.toContain` : 'toContain';
50
+ /**
51
+ * Finds the first `.` character token between the `object` & `property` of the given `member` expression.
52
+ *
53
+ * @param {TSESTree.MemberExpression} member
54
+ * @param {SourceCode} sourceCode
55
+ *
56
+ * @return {Token | null}
57
+ */
58
+
59
+
60
+ const findPropertyDotToken = (member, sourceCode) => sourceCode.getFirstTokenBetween(member.object, member.property, token => token.value === '.');
61
+
62
+ const getNegationFixes = (node, modifier, matcher, sourceCode, fixer, fileName) => {
63
+ const _node$arguments = _slicedToArray(node.arguments, 1),
64
+ containArg = _node$arguments[0];
65
+
66
+ const negationPropertyDot = findPropertyDotToken(modifier.node, sourceCode);
67
+ const toContainFunc = buildToContainFuncExpectation((0, _utils.followTypeAssertionChain)(matcher.arguments[0]).value);
68
+ /* istanbul ignore if */
69
+
70
+ if (negationPropertyDot === null) {
71
+ throw new Error(`Unexpected null when attempting to fix ${fileName} - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
72
+ }
38
73
 
39
- return [fixer.remove(negationPropertyDot), fixer.remove((0, _util.method)(node)), fixer.replaceText((0, _util.method)(node.parent), toContainFunc), fixer.replaceText((0, _util.argument)(node.parent), sourceCode.getText(containArg))];
74
+ return [fixer.remove(negationPropertyDot), fixer.remove(modifier.node.property), fixer.replaceText(matcher.node.property, toContainFunc), fixer.replaceText(matcher.arguments[0], sourceCode.getText(containArg))];
40
75
  };
41
76
 
42
- const getCommonFixes = (node, sourceCode, fixer) => {
43
- const _node$arguments$0$arg2 = _slicedToArray(node.arguments[0].arguments, 1),
44
- containArg = _node$arguments$0$arg2[0];
77
+ const getCommonFixes = (node, sourceCode, fileName) => {
78
+ const _node$arguments2 = _slicedToArray(node.arguments, 1),
79
+ containArg = _node$arguments2[0];
45
80
 
46
- const includesCaller = node.arguments[0].callee;
47
- const propertyDot = sourceCode.getFirstTokenBetween(includesCaller.object, includesCaller.property, token => token.value === '.');
81
+ const includesCallee = node.callee;
82
+ const propertyDot = findPropertyDotToken(includesCallee, sourceCode);
48
83
  const closingParenthesis = sourceCode.getTokenAfter(containArg);
49
84
  const openParenthesis = sourceCode.getTokenBefore(containArg);
50
- return [fixer.remove(containArg), fixer.remove(includesCaller.property), fixer.remove(propertyDot), fixer.remove(closingParenthesis), fixer.remove(openParenthesis)];
51
- };
85
+ /* istanbul ignore if */
86
+
87
+ if (propertyDot === null || closingParenthesis === null || openParenthesis === null) {
88
+ throw new Error(`Unexpected null when attempting to fix ${fileName} - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
89
+ }
90
+
91
+ return [containArg, includesCallee.property, propertyDot, closingParenthesis, openParenthesis];
92
+ }; // expect(array.includes(<value>)[not.]{toBe,toEqual}(<boolean>)
93
+
52
94
 
53
- var _default = {
95
+ var _default = (0, _utils.createRule)({
96
+ name: __filename,
54
97
  meta: {
55
98
  docs: {
56
- url: (0, _util.getDocsUrl)(__filename)
99
+ category: 'Best Practices',
100
+ description: 'Suggest using `toContain()`',
101
+ recommended: false
57
102
  },
58
103
  messages: {
59
104
  useToContain: 'Use toContain() instead'
60
105
  },
61
106
  fixable: 'code',
107
+ type: 'suggestion',
62
108
  schema: []
63
109
  },
110
+ defaultOptions: [],
64
111
 
65
112
  create(context) {
66
113
  return {
67
114
  CallExpression(node) {
68
- if (!((0, _util.expectResolvesCase)(node) || (0, _util.expectRejectsCase)(node)) && (0, _util.expectCaseWithParent)(node) && (isEqualityNegation(node) || isValidEqualityCheck(node)) && isValidIncludesMethod(node)) {
69
- context.report({
70
- fix(fixer) {
71
- const sourceCode = context.getSourceCode();
72
- let fixArr = getCommonFixes(node, sourceCode, fixer);
115
+ if (!(0, _utils.isExpectCall)(node)) {
116
+ return;
117
+ }
73
118
 
74
- if (isEqualityNegation(node)) {
75
- return getNegationFixes(node, sourceCode, fixer).concat(fixArr);
76
- }
119
+ const _parseExpectCall = (0, _utils.parseExpectCall)(node),
120
+ _parseExpectCall$expe = _slicedToArray(_parseExpectCall.expect.arguments, 1),
121
+ includesCall = _parseExpectCall$expe[0],
122
+ matcher = _parseExpectCall.matcher,
123
+ modifier = _parseExpectCall.modifier;
77
124
 
78
- const toContainFunc = (0, _util.argument)(node).value ? 'toContain' : 'not.toContain'; //.includes function argument
125
+ if (!matcher || modifier && modifier.name !== _utils.ModifierName.not || !isBooleanEqualityMatcher(matcher) || !isFixableIncludesCallExpression(includesCall)) {
126
+ return;
127
+ }
79
128
 
80
- const _node$arguments$0$arg3 = _slicedToArray(node.arguments[0].arguments, 1),
81
- containArg = _node$arguments$0$arg3[0];
129
+ context.report({
130
+ fix(fixer) {
131
+ const sourceCode = context.getSourceCode();
132
+ const fileName = context.getFilename();
133
+ const fixArr = getCommonFixes(includesCall, sourceCode, fileName).map(target => fixer.remove(target));
82
134
 
83
- fixArr.push(fixer.replaceText((0, _util.method)(node), toContainFunc));
84
- fixArr.push(fixer.replaceText((0, _util.argument)(node), sourceCode.getText(containArg)));
85
- return fixArr;
86
- },
135
+ if (modifier && modifier.name === _utils.ModifierName.not) {
136
+ return getNegationFixes(includesCall, modifier, matcher, sourceCode, fixer, fileName).concat(fixArr);
137
+ }
87
138
 
88
- messageId: 'useToContain',
89
- node: (0, _util.method)(node)
90
- });
91
- }
139
+ const toContainFunc = buildToContainFuncExpectation(!(0, _utils.followTypeAssertionChain)(matcher.arguments[0]).value);
140
+
141
+ const _includesCall$argumen = _slicedToArray(includesCall.arguments, 1),
142
+ containArg = _includesCall$argumen[0];
143
+
144
+ fixArr.push(fixer.replaceText(matcher.node.property, toContainFunc));
145
+ fixArr.push(fixer.replaceText(matcher.arguments[0], sourceCode.getText(containArg)));
146
+ return fixArr;
147
+ },
148
+
149
+ messageId: 'useToContain',
150
+ node: (modifier || matcher).node.property
151
+ });
92
152
  }
93
153
 
94
154
  };
95
155
  }
96
156
 
97
- };
157
+ });
158
+
98
159
  exports.default = _default;
@@ -5,38 +5,71 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _util = require("./util");
8
+ var _experimentalUtils = require("@typescript-eslint/experimental-utils");
9
9
 
10
- var _default = {
10
+ var _utils = require("./utils");
11
+
12
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
13
+
14
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
15
+
16
+ function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
17
+
18
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
19
+
20
+ var _default = (0, _utils.createRule)({
21
+ name: __filename,
11
22
  meta: {
12
23
  docs: {
13
- url: (0, _util.getDocsUrl)(__filename)
24
+ category: 'Best Practices',
25
+ description: 'Suggest using `toHaveLength()`',
26
+ recommended: false
14
27
  },
15
28
  messages: {
16
29
  useToHaveLength: 'Use toHaveLength() instead'
17
30
  },
18
31
  fixable: 'code',
32
+ type: 'suggestion',
19
33
  schema: []
20
34
  },
35
+ defaultOptions: [],
21
36
 
22
37
  create(context) {
23
38
  return {
24
39
  CallExpression(node) {
25
- if (!((0, _util.expectNotCase)(node) || (0, _util.expectResolvesCase)(node) || (0, _util.expectRejectsCase)(node)) && (0, _util.expectCaseWithParent)(node) && ((0, _util.method)(node).name === 'toBe' || (0, _util.method)(node).name === 'toEqual') && node.arguments[0].property && node.arguments[0].property.name === 'length') {
26
- const propertyDot = context.getSourceCode().getFirstTokenBetween(node.arguments[0].object, node.arguments[0].property, token => token.value === '.');
27
- context.report({
28
- fix(fixer) {
29
- return [fixer.remove(propertyDot), fixer.remove(node.arguments[0].property), fixer.replaceText((0, _util.method)(node), 'toHaveLength')];
30
- },
31
-
32
- messageId: 'useToHaveLength',
33
- node: (0, _util.method)(node)
34
- });
40
+ if (!(0, _utils.isExpectCall)(node)) {
41
+ return;
42
+ }
43
+
44
+ const _parseExpectCall = (0, _utils.parseExpectCall)(node),
45
+ _parseExpectCall$expe = _slicedToArray(_parseExpectCall.expect.arguments, 1),
46
+ argument = _parseExpectCall$expe[0],
47
+ matcher = _parseExpectCall.matcher;
48
+
49
+ if (!matcher || !(0, _utils.isParsedEqualityMatcherCall)(matcher) || !argument || argument.type !== _experimentalUtils.AST_NODE_TYPES.MemberExpression || !(0, _utils.isSupportedAccessor)(argument.property, 'length') || argument.property.type !== _experimentalUtils.AST_NODE_TYPES.Identifier) {
50
+ return;
35
51
  }
52
+
53
+ context.report({
54
+ fix(fixer) {
55
+ const propertyDot = context.getSourceCode().getFirstTokenBetween(argument.object, argument.property, token => token.value === '.');
56
+ /* istanbul ignore if */
57
+
58
+ if (propertyDot === null) {
59
+ throw new Error(`Unexpected null when attempting to fix ${context.getFilename()} - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
60
+ }
61
+
62
+ return [fixer.remove(propertyDot), fixer.remove(argument.property), fixer.replaceText(matcher.node.property, 'toHaveLength')];
63
+ },
64
+
65
+ messageId: 'useToHaveLength',
66
+ node: matcher.node.property
67
+ });
36
68
  }
37
69
 
38
70
  };
39
71
  }
40
72
 
41
- };
73
+ });
74
+
42
75
  exports.default = _default;
@@ -7,7 +7,7 @@ exports.default = void 0;
7
7
 
8
8
  var _experimentalUtils = require("@typescript-eslint/experimental-utils");
9
9
 
10
- var _tsUtils = require("./tsUtils");
10
+ var _utils = require("./utils");
11
11
 
12
12
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
13
13
 
@@ -17,12 +17,8 @@ function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d =
17
17
 
18
18
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
19
19
 
20
- function isOnlyTestTitle(node) {
21
- return node.arguments.length === 1;
22
- }
23
-
24
20
  function isFunctionBodyEmpty(node) {
25
- /* istanbul ignore next https://github.com/typescript-eslint/typescript-eslint/issues/734 */
21
+ /* istanbul ignore if https://github.com/typescript-eslint/typescript-eslint/issues/734 */
26
22
  if (!node.body) {
27
23
  throw new Error(`Unexpected null while performing prefer-todo - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
28
24
  }
@@ -34,21 +30,17 @@ function isTestBodyEmpty(node) {
34
30
  const _node$arguments = _slicedToArray(node.arguments, 2),
35
31
  fn = _node$arguments[1];
36
32
 
37
- return fn && (0, _tsUtils.isFunction)(fn) && isFunctionBodyEmpty(fn);
33
+ return fn && (0, _utils.isFunction)(fn) && isFunctionBodyEmpty(fn);
38
34
  }
39
35
 
40
36
  function addTodo(node, fixer) {
41
- const testName = (0, _tsUtils.getNodeName)(node.callee).split('.').shift();
37
+ const testName = (0, _utils.getNodeName)(node.callee).split('.').shift();
42
38
  return fixer.replaceText(node.callee, `${testName}.todo`);
43
39
  }
44
40
 
45
- function isFirstArgString(node) {
46
- return node.arguments[0] && (0, _tsUtils.isStringNode)(node.arguments[0]);
47
- }
41
+ const isTargetedTestCase = node => (0, _utils.isTestCase)(node) && ['it', 'test', 'it.skip', 'test.skip'].includes((0, _utils.getNodeName)(node.callee));
48
42
 
49
- const isTargetedTestCase = node => (0, _tsUtils.isTestCase)(node) && ['it', 'test', 'it.skip', 'test.skip'].includes((0, _tsUtils.getNodeName)(node.callee));
50
-
51
- var _default = (0, _tsUtils.createRule)({
43
+ var _default = (0, _utils.createRule)({
52
44
  name: __filename,
53
45
  meta: {
54
46
  docs: {
@@ -69,7 +61,11 @@ var _default = (0, _tsUtils.createRule)({
69
61
  create(context) {
70
62
  return {
71
63
  CallExpression(node) {
72
- if (!isTargetedTestCase(node) || !isFirstArgString(node)) {
64
+ const _node$arguments2 = _slicedToArray(node.arguments, 2),
65
+ firstArg = _node$arguments2[0],
66
+ secondArg = _node$arguments2[1];
67
+
68
+ if (!isTargetedTestCase(node) || !(0, _utils.isStringNode)(firstArg)) {
73
69
  return;
74
70
  }
75
71
 
@@ -77,11 +73,11 @@ var _default = (0, _tsUtils.createRule)({
77
73
  context.report({
78
74
  messageId: 'todoOverEmpty',
79
75
  node,
80
- fix: fixer => [fixer.removeRange([node.arguments[0].range[1], node.arguments[1].range[1]]), addTodo(node, fixer)]
76
+ fix: fixer => [fixer.removeRange([firstArg.range[1], secondArg.range[1]]), addTodo(node, fixer)]
81
77
  });
82
78
  }
83
79
 
84
- if (isOnlyTestTitle(node)) {
80
+ if ((0, _utils.hasOnlyOneArgument)(node)) {
85
81
  context.report({
86
82
  messageId: 'todoOverUnimplemented',
87
83
  node,
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _utils = require("./utils");
9
+
10
+ var _default = (0, _utils.createRule)({
11
+ name: __filename,
12
+ meta: {
13
+ docs: {
14
+ category: 'Best Practices',
15
+ description: 'Prevents test cases and hooks to be outside of a describe block',
16
+ recommended: false
17
+ },
18
+ messages: {
19
+ unexpectedTestCase: 'All test cases must be wrapped in a describe block.',
20
+ unexpectedHook: 'All hooks must be wrapped in a describe block.'
21
+ },
22
+ type: 'suggestion',
23
+ schema: []
24
+ },
25
+ defaultOptions: [],
26
+
27
+ create(context) {
28
+ let numberOfDescribeBlocks = 0;
29
+ return {
30
+ CallExpression(node) {
31
+ if ((0, _utils.isDescribe)(node)) {
32
+ numberOfDescribeBlocks++;
33
+ return;
34
+ }
35
+
36
+ if (numberOfDescribeBlocks === 0) {
37
+ if ((0, _utils.isTestCase)(node)) {
38
+ context.report({
39
+ node,
40
+ messageId: 'unexpectedTestCase'
41
+ });
42
+ return;
43
+ }
44
+
45
+ if ((0, _utils.isHook)(node)) {
46
+ context.report({
47
+ node,
48
+ messageId: 'unexpectedHook'
49
+ });
50
+ return;
51
+ }
52
+ }
53
+ },
54
+
55
+ 'CallExpression:exit'(node) {
56
+ if ((0, _utils.isDescribe)(node)) {
57
+ numberOfDescribeBlocks--;
58
+ }
59
+ }
60
+
61
+ };
62
+ }
63
+
64
+ });
65
+
66
+ exports.default = _default;
@@ -5,41 +5,45 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _util = require("./util");
8
+ var _utils = require("./utils");
9
9
 
10
- var _default = {
10
+ var _default = (0, _utils.createRule)({
11
+ name: __filename,
11
12
  meta: {
12
13
  docs: {
13
- url: (0, _util.getDocsUrl)(__filename)
14
+ category: 'Best Practices',
15
+ description: 'Require a message for `toThrow()`',
16
+ recommended: false
14
17
  },
15
18
  messages: {
16
19
  requireRethrow: 'Add an error message to {{ propertyName }}()'
17
20
  },
21
+ type: 'suggestion',
18
22
  schema: []
19
23
  },
24
+ defaultOptions: [],
20
25
 
21
26
  create(context) {
22
27
  return {
23
28
  CallExpression(node) {
24
- if (!(0, _util.expectCaseWithParent)(node)) {
29
+ if (!(0, _utils.isExpectCall)(node)) {
25
30
  return;
26
31
  }
27
32
 
28
- let targetNode = (0, _util.method)(node);
33
+ const _parseExpectCall = (0, _utils.parseExpectCall)(node),
34
+ matcher = _parseExpectCall.matcher,
35
+ modifier = _parseExpectCall.modifier;
29
36
 
30
- if (targetNode.name === 'rejects') {
31
- targetNode = (0, _util.method)(node.parent);
32
- }
33
-
34
- const propertyName = (0, _util.method)(targetNode) && (0, _util.method)(targetNode).name; // Look for `toThrow` calls with no arguments.
35
-
36
- if (['toThrow', 'toThrowError'].includes(propertyName) && !(0, _util.argument)(targetNode)) {
37
+ if (matcher && matcher.arguments && matcher.arguments.length === 0 && ['toThrow', 'toThrowError'].includes(matcher.name) && (!modifier || !(modifier.name === _utils.ModifierName.not || modifier.negation))) {
38
+ // Look for `toThrow` calls with no arguments.
37
39
  context.report({
38
40
  messageId: 'requireRethrow',
41
+ // todo: rename to 'addErrorMessage'
39
42
  data: {
40
- propertyName
43
+ propertyName: matcher.name
41
44
  },
42
- node: targetNode
45
+ // todo: rename to 'matcherName'
46
+ node: matcher.node.property
43
47
  });
44
48
  }
45
49
  }
@@ -47,5 +51,6 @@ var _default = {
47
51
  };
48
52
  }
49
53
 
50
- };
54
+ });
55
+
51
56
  exports.default = _default;