eslint-plugin-jest 26.6.0 → 26.7.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <div align="center">
2
2
  <a href="https://eslint.org/">
3
- <img width="150" height="150" src="https://eslint.org/assets/img/logo.svg">
3
+ <img width="150" height="150" src="https://eslint.org/assets/images/logo/eslint-logo-color.svg">
4
4
  </a>
5
5
  <a href="https://facebook.github.io/jest/">
6
6
  <img width="150" height="150" vspace="" hspace="25" src="https://jestjs.io/img/jest.png">
@@ -232,6 +232,7 @@ installations requiring long-term consistency.
232
232
  | [prefer-hooks-in-order](docs/rules/prefer-hooks-in-order.md) | Prefer having hooks in a consistent order | | |
233
233
  | [prefer-hooks-on-top](docs/rules/prefer-hooks-on-top.md) | Suggest having hooks before any test cases | | |
234
234
  | [prefer-lowercase-title](docs/rules/prefer-lowercase-title.md) | Enforce lowercase test names | | ![fixable][] |
235
+ | [prefer-mock-promise-shorthand](docs/rules/prefer-mock-promise-shorthand.md) | Prefer mock resolved/rejected shorthands for promises | | ![fixable][] |
235
236
  | [prefer-snapshot-hint](docs/rules/prefer-snapshot-hint.md) | Prefer including a hint with external snapshots | | |
236
237
  | [prefer-spy-on](docs/rules/prefer-spy-on.md) | Suggest using `jest.spyOn()` | | ![fixable][] |
237
238
  | [prefer-strict-equal](docs/rules/prefer-strict-equal.md) | Suggest using `toStrictEqual()` | | ![suggest][] |
@@ -0,0 +1,34 @@
1
+ # Prefer mock resolved/rejected shorthands for promises (`prefer-mock-promise-shorthand`)
2
+
3
+ When working with mocks of functions that return promises, Jest provides some
4
+ API sugar functions to reduce the amount of boilerplate you have to write.
5
+
6
+ These methods should be preferred when possible.
7
+
8
+ ## Rule Details
9
+
10
+ The following patterns are warnings:
11
+
12
+ ```js
13
+ jest.fn().mockImplementation(() => Promise.resolve(123));
14
+ jest
15
+ .spyOn(fs.promises, 'readFile')
16
+ .mockReturnValue(Promise.reject(new Error('oh noes!')));
17
+
18
+ myFunction
19
+ .mockReturnValueOnce(Promise.resolve(42))
20
+ .mockImplementationOnce(() => Promise.resolve(42))
21
+ .mockReturnValue(Promise.reject(new Error('too many calls!')));
22
+ ```
23
+
24
+ The following patterns are not warnings:
25
+
26
+ ```js
27
+ jest.fn().mockResolvedValue(123);
28
+ jest.spyOn(fs.promises, 'readFile').mockRejectedValue(new Error('oh noes!'));
29
+
30
+ myFunction
31
+ .mockResolvedValueOnce(42)
32
+ .mockResolvedValueOnce(42)
33
+ .mockRejectedValue(new Error('too many calls!'));
34
+ ```
@@ -16,7 +16,7 @@ var _default = (0, _utils.createRule)({
16
16
  recommended: false
17
17
  },
18
18
  messages: {
19
- preferCalledWith: 'Prefer {{name}}With(/* expected args */)'
19
+ preferCalledWith: 'Prefer {{ matcherName }}With(/* expected args */)'
20
20
  },
21
21
  type: 'suggestion',
22
22
  schema: []
@@ -42,7 +42,7 @@ var _default = (0, _utils.createRule)({
42
42
  if (['toBeCalled', 'toHaveBeenCalled'].includes(matcher.name)) {
43
43
  context.report({
44
44
  data: {
45
- name: matcher.name
45
+ matcherName: matcher.name
46
46
  },
47
47
  messageId: 'preferCalledWith',
48
48
  node: matcher.node.property
@@ -132,7 +132,7 @@ var _default = (0, _utils2.createRule)({
132
132
  data: {
133
133
  preferredMatcher
134
134
  },
135
- node: (negation || matcher).node.property
135
+ node: matcher.node.property
136
136
  });
137
137
  }
138
138
 
@@ -96,7 +96,7 @@ var _default = (0, _utils2.createRule)({
96
96
  },
97
97
  fix: buildFixer(equalityMatcher)
98
98
  })),
99
- node: (negation || matcher).node.property
99
+ node: matcher.node.property
100
100
  });
101
101
  }
102
102
 
@@ -0,0 +1,111 @@
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 withOnce = (name, addOnce) => {
13
+ return `${name}${addOnce ? 'Once' : ''}`;
14
+ };
15
+
16
+ const findSingleReturnArgumentNode = fnNode => {
17
+ var _fnNode$body$body$;
18
+
19
+ if (fnNode.body.type !== _utils.AST_NODE_TYPES.BlockStatement) {
20
+ return fnNode.body;
21
+ }
22
+
23
+ if (((_fnNode$body$body$ = fnNode.body.body[0]) === null || _fnNode$body$body$ === void 0 ? void 0 : _fnNode$body$body$.type) === _utils.AST_NODE_TYPES.ReturnStatement) {
24
+ return fnNode.body.body[0].argument;
25
+ }
26
+
27
+ return null;
28
+ };
29
+
30
+ var _default = (0, _utils2.createRule)({
31
+ name: __filename,
32
+ meta: {
33
+ docs: {
34
+ category: 'Best Practices',
35
+ description: 'Prefer mock resolved/rejected shorthands for promises',
36
+ recommended: false
37
+ },
38
+ messages: {
39
+ useMockShorthand: 'Prefer {{ replacement }}'
40
+ },
41
+ schema: [],
42
+ type: 'suggestion',
43
+ fixable: 'code'
44
+ },
45
+ defaultOptions: [],
46
+
47
+ create(context) {
48
+ const report = (property, isOnce, outerArgNode, innerArgNode = outerArgNode) => {
49
+ if ((innerArgNode === null || innerArgNode === void 0 ? void 0 : innerArgNode.type) !== _utils.AST_NODE_TYPES.CallExpression) {
50
+ return;
51
+ }
52
+
53
+ const argName = (0, _utils2.getNodeName)(innerArgNode);
54
+
55
+ if (argName !== 'Promise.resolve' && argName !== 'Promise.reject') {
56
+ return;
57
+ }
58
+
59
+ const replacement = withOnce(argName.endsWith('reject') ? 'mockRejectedValue' : 'mockResolvedValue', isOnce);
60
+ context.report({
61
+ node: property,
62
+ messageId: 'useMockShorthand',
63
+ data: {
64
+ replacement
65
+ },
66
+
67
+ fix(fixer) {
68
+ const sourceCode = context.getSourceCode(); // there shouldn't be more than one argument, but if there is don't try
69
+ // fixing since we have no idea what to do with the extra arguments
70
+
71
+ if (innerArgNode.arguments.length > 1) {
72
+ return null;
73
+ }
74
+
75
+ return [fixer.replaceText(property, replacement), fixer.replaceText(outerArgNode, // the value argument for both Promise methods is optional,
76
+ // whereas for Jest they're required so use an explicit undefined
77
+ // if no argument is being passed to the call we're replacing
78
+ innerArgNode.arguments.length === 1 ? sourceCode.getText(innerArgNode.arguments[0]) : 'undefined')];
79
+ }
80
+
81
+ });
82
+ };
83
+
84
+ return {
85
+ CallExpression(node) {
86
+ if (node.callee.type !== _utils.AST_NODE_TYPES.MemberExpression || !(0, _utils2.isSupportedAccessor)(node.callee.property) || node.arguments.length === 0) {
87
+ return;
88
+ }
89
+
90
+ const mockFnName = (0, _utils2.getAccessorValue)(node.callee.property);
91
+ const isOnce = mockFnName.endsWith('Once');
92
+
93
+ if (mockFnName === withOnce('mockReturnValue', isOnce)) {
94
+ report(node.callee.property, isOnce, node.arguments[0]);
95
+ } else if (mockFnName === withOnce('mockImplementation', isOnce)) {
96
+ const [arg] = node.arguments;
97
+
98
+ if (!(0, _utils2.isFunction)(arg)) {
99
+ return;
100
+ }
101
+
102
+ report(node.callee.property, isOnce, arg, findSingleReturnArgumentNode(arg));
103
+ }
104
+ }
105
+
106
+ };
107
+ }
108
+
109
+ });
110
+
111
+ exports.default = _default;
@@ -86,7 +86,7 @@ var _default = (0, _utils2.createRule)({
86
86
  },
87
87
 
88
88
  messageId: 'useToContain',
89
- node: (modifier || matcher).node.property
89
+ node: matcher.node.property
90
90
  });
91
91
  }
92
92
 
@@ -26,7 +26,7 @@ const getPromiseCallExpressionNode = node => {
26
26
  node = node.parent;
27
27
  }
28
28
 
29
- if (node.type === _utils.AST_NODE_TYPES.CallExpression && node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.object) && (0, _utils2.getAccessorValue)(node.callee.object) === 'Promise' && node.parent) {
29
+ if (node.type === _utils.AST_NODE_TYPES.CallExpression && node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.object, 'Promise') && node.parent) {
30
30
  return node;
31
31
  }
32
32
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-jest",
3
- "version": "26.6.0",
3
+ "version": "26.7.0",
4
4
  "description": "ESLint rules for Jest",
5
5
  "keywords": [
6
6
  "eslint",
@@ -158,5 +158,5 @@
158
158
  "resolutions": {
159
159
  "@typescript-eslint/experimental-utils": "^5.0.0"
160
160
  },
161
- "packageManager": "yarn@3.2.1"
161
+ "packageManager": "yarn@3.2.2"
162
162
  }