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,9 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _tsUtils = require("./tsUtils");
8
+ var _utils = require("./utils");
9
9
 
10
- var _default = (0, _tsUtils.createRule)({
10
+ var _default = (0, _utils.createRule)({
11
11
  name: __filename,
12
12
  meta: {
13
13
  docs: {
@@ -28,12 +28,12 @@ var _default = (0, _tsUtils.createRule)({
28
28
  let catchDepth = 0;
29
29
 
30
30
  function isThrowExpectCall(node) {
31
- return catchDepth > 0 && (0, _tsUtils.isExpectCall)(node);
31
+ return catchDepth > 0 && (0, _utils.isExpectCall)(node);
32
32
  }
33
33
 
34
34
  return {
35
35
  CallExpression(node) {
36
- if ((0, _tsUtils.isTestCase)(node)) {
36
+ if ((0, _utils.isTestCase)(node)) {
37
37
  isTest = true;
38
38
  } else if (isTest && isThrowExpectCall(node)) {
39
39
  context.report({
@@ -56,7 +56,7 @@ var _default = (0, _tsUtils.createRule)({
56
56
  },
57
57
 
58
58
  'CallExpression:exit'(node) {
59
- if ((0, _tsUtils.isTestCase)(node)) {
59
+ if ((0, _utils.isTestCase)(node)) {
60
60
  isTest = false;
61
61
  }
62
62
  }
@@ -5,34 +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: 'Suggest using `toBeCalledWith()` OR `toHaveBeenCalledWith()`',
16
+ recommended: false
14
17
  },
15
18
  messages: {
16
19
  preferCalledWith: 'Prefer {{name}}With(/* expected args */)'
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
- // Could check resolves/rejects here but not a likely idiom.
25
- if ((0, _util.expectCaseWithParent)(node) && !(0, _util.expectNotCase)(node)) {
26
- const methodNode = (0, _util.method)(node);
27
- const name = methodNode.name;
29
+ if (!(0, _utils.isExpectCall)(node)) {
30
+ return;
31
+ }
32
+
33
+ const _parseExpectCall = (0, _utils.parseExpectCall)(node),
34
+ modifier = _parseExpectCall.modifier,
35
+ matcher = _parseExpectCall.matcher; // Could check resolves/rejects here but not a likely idiom.
36
+
28
37
 
29
- if (name === 'toBeCalled' || name === 'toHaveBeenCalled') {
38
+ if (matcher && !modifier) {
39
+ if (['toBeCalled', 'toHaveBeenCalled'].includes(matcher.name)) {
30
40
  context.report({
31
41
  data: {
32
- name
42
+ name: matcher.name
33
43
  },
44
+ // todo: rename to 'matcherName'
34
45
  messageId: 'preferCalledWith',
35
- node: methodNode
46
+ node: matcher.node.property
36
47
  });
37
48
  }
38
49
  }
@@ -41,5 +52,6 @@ var _default = {
41
52
  };
42
53
  }
43
54
 
44
- };
55
+ });
56
+
45
57
  exports.default = _default;
@@ -5,70 +5,81 @@ 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
- const validateArguments = expression => {
11
- return expression.arguments && expression.arguments.length === 1 && Number.isInteger(expression.arguments[0].value);
12
- };
10
+ var _utils = require("./utils");
13
11
 
14
- const isExpectAssertionsOrHasAssertionsCall = expression => {
15
- try {
16
- const expectAssertionOrHasAssertionCall = expression.type === 'CallExpression' && expression.callee.type === 'MemberExpression' && expression.callee.object.name === 'expect' && (expression.callee.property.name === 'assertions' || expression.callee.property.name === 'hasAssertions');
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"); }
17
15
 
18
- if (expression.callee.property.name === 'assertions') {
19
- return expectAssertionOrHasAssertionCall && validateArguments(expression);
20
- }
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; }
21
17
 
22
- return expectAssertionOrHasAssertionCall;
23
- } catch (e) {
18
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
19
+
20
+ const isExpectAssertionsOrHasAssertionsCall = expression => {
21
+ if (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)) {
24
22
  return false;
25
23
  }
26
- };
27
24
 
28
- const getFunctionFirstLine = functionBody => {
29
- return functionBody[0] && functionBody[0].expression;
30
- };
25
+ const expectAssertionName = (0, _utils.getAccessorValue)(expression.callee.property);
31
26
 
32
- const isFirstLineExprStmt = functionBody => {
33
- return functionBody[0] && functionBody[0].type === 'ExpressionStatement';
34
- };
27
+ if (expectAssertionName !== 'assertions') {
28
+ return expectAssertionName === 'hasAssertions';
29
+ }
35
30
 
36
- const reportMsg = (context, node) => {
37
- context.report({
38
- messageId: 'haveExpectAssertions',
39
- node
40
- });
31
+ const _expression$arguments = _slicedToArray(expression.arguments, 1),
32
+ arg = _expression$arguments[0];
33
+
34
+ return expression.arguments && expression.arguments.length === 1 && arg.type === _experimentalUtils.AST_NODE_TYPES.Literal && typeof arg.value === 'number' && Number.isInteger(arg.value);
41
35
  };
42
36
 
43
- var _default = {
37
+ const getFunctionFirstLine = functionBody => functionBody[0] && functionBody[0].expression;
38
+
39
+ const isFirstLineExprStmt = functionBody => functionBody[0] && functionBody[0].type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement;
40
+
41
+ var _default = (0, _utils.createRule)({
42
+ name: __filename,
44
43
  meta: {
45
44
  docs: {
46
- url: (0, _util.getDocsUrl)(__filename)
45
+ category: 'Best Practices',
46
+ description: 'Suggest using `expect.assertions()` OR `expect.hasAssertions()`',
47
+ recommended: false
47
48
  },
48
49
  messages: {
49
50
  haveExpectAssertions: 'Every test should have either `expect.assertions(<number of assertions>)` or `expect.hasAssertions()` as its first expression'
50
51
  },
52
+ type: 'suggestion',
51
53
  schema: []
52
54
  },
55
+ defaultOptions: [],
53
56
 
54
57
  create(context) {
55
58
  return {
56
59
  'CallExpression[callee.name=/^(it|test)$/][arguments.1.body.body]'(node) {
57
60
  const testFuncBody = node.arguments[1].body.body;
58
61
 
59
- if (isFirstLineExprStmt(testFuncBody)) {
60
- const testFuncFirstLine = getFunctionFirstLine(testFuncBody);
62
+ if (!isFirstLineExprStmt(testFuncBody)) {
63
+ context.report({
64
+ messageId: 'haveExpectAssertions',
65
+ node
66
+ });
67
+ return;
68
+ }
69
+
70
+ const testFuncFirstLine = getFunctionFirstLine(testFuncBody);
61
71
 
62
- if (!isExpectAssertionsOrHasAssertionsCall(testFuncFirstLine)) {
63
- reportMsg(context, node);
64
- }
65
- } else {
66
- reportMsg(context, node);
72
+ if (!isExpectAssertionsOrHasAssertionsCall(testFuncFirstLine)) {
73
+ context.report({
74
+ messageId: 'haveExpectAssertions',
75
+ node
76
+ });
67
77
  }
68
78
  }
69
79
 
70
80
  };
71
81
  }
72
82
 
73
- };
83
+ });
84
+
74
85
  exports.default = _default;
@@ -7,9 +7,9 @@ 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
- var _default = (0, _tsUtils.createRule)({
12
+ var _default = (0, _utils.createRule)({
13
13
  name: __filename,
14
14
  meta: {
15
15
  docs: {
@@ -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
 
@@ -41,13 +41,13 @@ const getJestFnCall = node => {
41
41
  }
42
42
 
43
43
  if (obj.type === _experimentalUtils.AST_NODE_TYPES.Identifier) {
44
- return node.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && (0, _tsUtils.getNodeName)(node.callee) === 'jest.fn' ? node : null;
44
+ return node.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && (0, _utils.getNodeName)(node.callee) === 'jest.fn' ? node : null;
45
45
  }
46
46
 
47
47
  return getJestFnCall(obj);
48
48
  };
49
49
 
50
- var _default = (0, _tsUtils.createRule)({
50
+ var _default = (0, _utils.createRule)({
51
51
  name: __filename,
52
52
  meta: {
53
53
  docs: {
@@ -83,7 +83,7 @@ var _default = (0, _tsUtils.createRule)({
83
83
  arg = _jestFnCall$arguments[0];
84
84
 
85
85
  const argSource = arg && context.getSourceCode().getText(arg);
86
- const mockImplementation = argSource ? `.mockImplementation(${argSource})` : '';
86
+ const mockImplementation = argSource ? `.mockImplementation(${argSource})` : '.mockImplementation()';
87
87
  return [fixer.insertTextBefore(left, `jest.spyOn(`), fixer.replaceTextRange([left.object.range[1], left.property.range[0]], `, ${leftPropQuote}`), fixer.replaceTextRange([left.property.range[1], jestFnCall.range[1]], `${leftPropQuote})${mockImplementation}`)];
88
88
  }
89
89
 
@@ -5,9 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _tsUtils = require("./tsUtils");
8
+ var _utils = require("./utils");
9
9
 
10
- var _default = (0, _tsUtils.createRule)({
10
+ var _default = (0, _utils.createRule)({
11
11
  name: __filename,
12
12
  meta: {
13
13
  docs: {
@@ -19,28 +19,26 @@ var _default = (0, _tsUtils.createRule)({
19
19
  useToStrictEqual: 'Use toStrictEqual() instead'
20
20
  },
21
21
  fixable: 'code',
22
- schema: [],
23
- type: 'suggestion'
22
+ type: 'suggestion',
23
+ schema: []
24
24
  },
25
25
  defaultOptions: [],
26
26
 
27
27
  create(context) {
28
28
  return {
29
29
  CallExpression(node) {
30
- if (!(0, _tsUtils.isExpectCallWithParent)(node)) {
30
+ if (!(0, _utils.isExpectCall)(node)) {
31
31
  return;
32
32
  }
33
33
 
34
- const methodNode = node.parent.property;
34
+ const _parseExpectCall = (0, _utils.parseExpectCall)(node),
35
+ matcher = _parseExpectCall.matcher;
35
36
 
36
- if (methodNode && methodNode.name === 'toEqual') {
37
+ if (matcher && matcher.name === 'toEqual') {
37
38
  context.report({
38
- fix(fixer) {
39
- return [fixer.replaceText(methodNode, 'toStrictEqual')];
40
- },
41
-
39
+ fix: fixer => [fixer.replaceText(matcher.node.property, 'toStrictEqual')],
42
40
  messageId: 'useToStrictEqual',
43
- node: methodNode
41
+ node: matcher.node.property
44
42
  });
45
43
  }
46
44
  }
@@ -5,38 +5,55 @@ 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
+ const isNullLiteral = node => node.type === _experimentalUtils.AST_NODE_TYPES.Literal && node.value === null;
13
+ /**
14
+ * Checks if the given `ParsedExpectMatcher` is a call to one of the equality matchers,
15
+ * with a `null` literal as the sole argument.
16
+ *
17
+ * @param {ParsedExpectMatcher} matcher
18
+ *
19
+ * @return {matcher is ParsedEqualityMatcherCall<MaybeTypeCast<NullLiteral>>}
20
+ */
21
+
22
+
23
+ const isNullEqualityMatcher = matcher => (0, _utils.isParsedEqualityMatcherCall)(matcher) && isNullLiteral((0, _utils.followTypeAssertionChain)(matcher.arguments[0]));
24
+
25
+ var _default = (0, _utils.createRule)({
26
+ name: __filename,
11
27
  meta: {
12
28
  docs: {
13
- url: (0, _util.getDocsUrl)(__filename)
29
+ category: 'Best Practices',
30
+ description: 'Suggest using `toBeNull()`',
31
+ recommended: false
14
32
  },
15
33
  messages: {
16
34
  useToBeNull: 'Use toBeNull() instead'
17
35
  },
18
36
  fixable: 'code',
37
+ type: 'suggestion',
19
38
  schema: []
20
39
  },
40
+ defaultOptions: [],
21
41
 
22
42
  create(context) {
23
43
  return {
24
44
  CallExpression(node) {
25
- const is = (0, _util.expectToBeCase)(node, null) || (0, _util.expectToEqualCase)(node, null);
26
- const isNot = (0, _util.expectNotToEqualCase)(node, null) || (0, _util.expectNotToBeCase)(node, null);
27
-
28
- if (is || isNot) {
29
- context.report({
30
- fix(fixer) {
31
- if (is) {
32
- return [fixer.replaceText((0, _util.method)(node), 'toBeNull'), fixer.remove((0, _util.argument)(node))];
33
- }
45
+ if (!(0, _utils.isExpectCall)(node)) {
46
+ return;
47
+ }
34
48
 
35
- return [fixer.replaceText((0, _util.method2)(node), 'toBeNull'), fixer.remove((0, _util.argument2)(node))];
36
- },
49
+ const _parseExpectCall = (0, _utils.parseExpectCall)(node),
50
+ matcher = _parseExpectCall.matcher;
37
51
 
52
+ if (matcher && isNullEqualityMatcher(matcher)) {
53
+ context.report({
54
+ fix: fixer => [fixer.replaceText(matcher.node.property, 'toBeNull'), fixer.remove(matcher.arguments[0])],
38
55
  messageId: 'useToBeNull',
39
- node: is ? (0, _util.method)(node) : (0, _util.method2)(node)
56
+ node: matcher.node.property
40
57
  });
41
58
  }
42
59
  }
@@ -44,5 +61,6 @@ var _default = {
44
61
  };
45
62
  }
46
63
 
47
- };
64
+ });
65
+
48
66
  exports.default = _default;
@@ -5,38 +5,55 @@ 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
+ const isUndefinedIdentifier = node => node.type === _experimentalUtils.AST_NODE_TYPES.Identifier && node.name === 'undefined';
13
+ /**
14
+ * Checks if the given `ParsedExpectMatcher` is a call to one of the equality matchers,
15
+ * with a `undefined` identifier as the sole argument.
16
+ *
17
+ * @param {ParsedExpectMatcher} matcher
18
+ *
19
+ * @return {matcher is ParsedEqualityMatcherCall<MaybeTypeCast<UndefinedIdentifier>>}
20
+ */
21
+
22
+
23
+ const isUndefinedEqualityMatcher = matcher => (0, _utils.isParsedEqualityMatcherCall)(matcher) && isUndefinedIdentifier((0, _utils.followTypeAssertionChain)(matcher.arguments[0]));
24
+
25
+ var _default = (0, _utils.createRule)({
26
+ name: __filename,
11
27
  meta: {
12
28
  docs: {
13
- url: (0, _util.getDocsUrl)(__filename)
29
+ category: 'Best Practices',
30
+ description: 'Suggest using `toBeUndefined()`',
31
+ recommended: false
14
32
  },
15
33
  messages: {
16
34
  useToBeUndefined: 'Use toBeUndefined() instead'
17
35
  },
18
36
  fixable: 'code',
37
+ type: 'suggestion',
19
38
  schema: []
20
39
  },
40
+ defaultOptions: [],
21
41
 
22
42
  create(context) {
23
43
  return {
24
44
  CallExpression(node) {
25
- const is = (0, _util.expectToBeCase)(node, undefined) || (0, _util.expectToEqualCase)(node, undefined);
26
- const isNot = (0, _util.expectNotToEqualCase)(node, undefined) || (0, _util.expectNotToBeCase)(node, undefined);
27
-
28
- if (is || isNot) {
29
- context.report({
30
- fix(fixer) {
31
- if (is) {
32
- return [fixer.replaceText((0, _util.method)(node), 'toBeUndefined'), fixer.remove((0, _util.argument)(node))];
33
- }
45
+ if (!(0, _utils.isExpectCall)(node)) {
46
+ return;
47
+ }
34
48
 
35
- return [fixer.replaceText((0, _util.method2)(node), 'toBeUndefined'), fixer.remove((0, _util.argument2)(node))];
36
- },
49
+ const _parseExpectCall = (0, _utils.parseExpectCall)(node),
50
+ matcher = _parseExpectCall.matcher;
37
51
 
52
+ if (matcher && isUndefinedEqualityMatcher(matcher)) {
53
+ context.report({
54
+ fix: fixer => [fixer.replaceText(matcher.node.property, 'toBeUndefined'), fixer.remove(matcher.arguments[0])],
38
55
  messageId: 'useToBeUndefined',
39
- node: is ? (0, _util.method)(node) : (0, _util.method2)(node)
56
+ node: matcher.node.property
40
57
  });
41
58
  }
42
59
  }
@@ -44,5 +61,6 @@ var _default = {
44
61
  };
45
62
  }
46
63
 
47
- };
64
+ });
65
+
48
66
  exports.default = _default;