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 +2 -1
- package/docs/rules/prefer-mock-promise-shorthand.md +34 -0
- package/lib/rules/prefer-called-with.js +2 -2
- package/lib/rules/prefer-comparison-matcher.js +1 -1
- package/lib/rules/prefer-equality-matcher.js +1 -1
- package/lib/rules/prefer-mock-promise-shorthand.js +111 -0
- package/lib/rules/prefer-to-contain.js +1 -1
- package/lib/rules/valid-expect.js +1 -1
- package/package.json +2 -2
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/
|
|
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 {{
|
|
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
|
-
|
|
45
|
+
matcherName: matcher.name
|
|
46
46
|
},
|
|
47
47
|
messageId: 'preferCalledWith',
|
|
48
48
|
node: matcher.node.property
|
|
@@ -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;
|
|
@@ -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
|
|
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.
|
|
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.
|
|
161
|
+
"packageManager": "yarn@3.2.2"
|
|
162
162
|
}
|