eslint-plugin-jest 29.8.0 → 29.9.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/docs/rules/no-unnecessary-assertion.md +7 -3
- package/lib/rules/no-error-equal.js +1 -71
- package/lib/rules/no-unnecessary-assertion.js +4 -4
- package/lib/rules/utils/index.js +11 -0
- package/lib/rules/utils/ts.js +73 -0
- package/lib/rules/valid-expect-with-promise.js +1 -71
- package/package.json +1 -1
|
@@ -10,9 +10,9 @@ provided that the types are accurate.
|
|
|
10
10
|
|
|
11
11
|
## Rule details
|
|
12
12
|
|
|
13
|
-
This rule warns when you do an assertion about being `null
|
|
14
|
-
something that cannot be those types, as that indicates either the
|
|
15
|
-
be removed or the types need to be adjusted.
|
|
13
|
+
This rule warns when you do an assertion about being `null`, `undefined`, or
|
|
14
|
+
`NaN` on something that cannot be those types, as that indicates either the
|
|
15
|
+
assertion can be removed or the types need to be adjusted.
|
|
16
16
|
|
|
17
17
|
The following patterns are considered warnings:
|
|
18
18
|
|
|
@@ -22,6 +22,8 @@ expect('hello world'.match('sunshine') ?? []).toBeNull();
|
|
|
22
22
|
expect(User.findOrThrow(1)).toBeDefined();
|
|
23
23
|
|
|
24
24
|
expect(map.getOrInsert('key', 'default')).not.toBeUndefined();
|
|
25
|
+
|
|
26
|
+
expect(user.name).not.toBeNaN();
|
|
25
27
|
```
|
|
26
28
|
|
|
27
29
|
The following patterns are not considered warnings:
|
|
@@ -32,4 +34,6 @@ expect('hello world'.match('sunshine')).toBeNull();
|
|
|
32
34
|
expect(User.findOrNull(1)).toBeDefined();
|
|
33
35
|
|
|
34
36
|
expect(map.get('key')).not.toBeUndefined();
|
|
37
|
+
|
|
38
|
+
expect(user.age).not.toBeNaN();
|
|
35
39
|
```
|
|
@@ -6,70 +6,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
var _utils = require("@typescript-eslint/utils");
|
|
8
8
|
var _utils2 = require("./utils");
|
|
9
|
-
let SymbolFlags;
|
|
10
|
-
let TypeFlags;
|
|
11
|
-
function isSymbolFromDefaultLibrary(program, symbol) {
|
|
12
|
-
/* istanbul ignore next */
|
|
13
|
-
const declarations = symbol.getDeclarations() ?? [];
|
|
14
|
-
for (const declaration of declarations) {
|
|
15
|
-
const sourceFile = declaration.getSourceFile();
|
|
16
|
-
|
|
17
|
-
/* istanbul ignore else */
|
|
18
|
-
if (program.isSourceFileDefaultLibrary(sourceFile)) {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/* istanbul ignore next */
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
function isBuiltinSymbolLike(program, type, symbolName) {
|
|
27
|
-
return isBuiltinSymbolLikeRecurser(program, type, subType => {
|
|
28
|
-
const symbol = subType.getSymbol();
|
|
29
|
-
if (!symbol) {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
const actualSymbolName = symbol.getName();
|
|
33
|
-
if (actualSymbolName === symbolName && isSymbolFromDefaultLibrary(program, symbol)) {
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
function isBuiltinSymbolLikeRecurser(program, type, predicate) {
|
|
40
|
-
if (type.isIntersection()) {
|
|
41
|
-
return type.types.some(t => isBuiltinSymbolLikeRecurser(program, t, predicate));
|
|
42
|
-
}
|
|
43
|
-
if (type.isUnion()) {
|
|
44
|
-
return type.types.every(t => isBuiltinSymbolLikeRecurser(program, t, predicate));
|
|
45
|
-
}
|
|
46
|
-
if (isTypeParameter(type)) {
|
|
47
|
-
const t = type.getConstraint();
|
|
48
|
-
if (t) {
|
|
49
|
-
return isBuiltinSymbolLikeRecurser(program, t, predicate);
|
|
50
|
-
}
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
const predicateResult = predicate(type);
|
|
54
|
-
if (typeof predicateResult === 'boolean') {
|
|
55
|
-
return predicateResult;
|
|
56
|
-
}
|
|
57
|
-
const symbol = type.getSymbol();
|
|
58
|
-
|
|
59
|
-
/* istanbul ignore next */
|
|
60
|
-
if (symbol && symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
|
|
61
|
-
const checker = program.getTypeChecker();
|
|
62
|
-
for (const baseType of checker.getBaseTypes(type)) {
|
|
63
|
-
if (isBuiltinSymbolLikeRecurser(program, baseType, predicate)) {
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
function isTypeParameter(type) {
|
|
71
|
-
return (type.flags & TypeFlags.TypeParameter) !== 0;
|
|
72
|
-
}
|
|
73
9
|
var _default = exports.default = (0, _utils2.createRule)({
|
|
74
10
|
name: __filename,
|
|
75
11
|
meta: {
|
|
@@ -86,12 +22,6 @@ var _default = exports.default = (0, _utils2.createRule)({
|
|
|
86
22
|
defaultOptions: [],
|
|
87
23
|
create(context) {
|
|
88
24
|
const services = _utils.ESLintUtils.getParserServices(context);
|
|
89
|
-
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
91
|
-
({
|
|
92
|
-
TypeFlags,
|
|
93
|
-
SymbolFlags
|
|
94
|
-
} = require('typescript'));
|
|
95
25
|
return {
|
|
96
26
|
CallExpression(node) {
|
|
97
27
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
@@ -99,7 +29,7 @@ var _default = exports.default = (0, _utils2.createRule)({
|
|
|
99
29
|
return;
|
|
100
30
|
}
|
|
101
31
|
const [argument] = jestFnCall.head.node.parent.arguments;
|
|
102
|
-
if (isBuiltinSymbolLike(services.program, services.getTypeAtLocation(argument), 'Error')) {
|
|
32
|
+
if ((0, _utils2.isBuiltinSymbolLike)(services.program, services.getTypeAtLocation(argument), 'Error')) {
|
|
103
33
|
context.report({
|
|
104
34
|
messageId: 'equalError',
|
|
105
35
|
node
|
|
@@ -58,7 +58,7 @@ var _default = exports.default = (0, _utils2.createRule)({
|
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
60
|
const matcherName = (0, _utils2.getAccessorValue)(jestFnCall.matcher);
|
|
61
|
-
if (!['toBeNull', 'toBeDefined', 'toBeUndefined'].includes(matcherName)) {
|
|
61
|
+
if (!['toBeNull', 'toBeDefined', 'toBeUndefined', 'toBeNaN'].includes(matcherName)) {
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -67,12 +67,12 @@ var _default = exports.default = (0, _utils2.createRule)({
|
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
const [argument] = jestFnCall.head.node.parent.arguments;
|
|
70
|
-
const
|
|
71
|
-
if (!
|
|
70
|
+
const isTypePossible = canBe(services.getTypeAtLocation(argument), matcherName === 'toBeNaN' ? TypeFlags.NumberLike : matcherName === 'toBeNull' ? TypeFlags.Null : TypeFlags.Undefined);
|
|
71
|
+
if (!isTypePossible) {
|
|
72
72
|
context.report({
|
|
73
73
|
messageId: 'unnecessaryAssertion',
|
|
74
74
|
data: {
|
|
75
|
-
thing: matcherName === 'toBeNull' ? 'null' : 'undefined'
|
|
75
|
+
thing: matcherName === 'toBeNaN' ? 'a number' : matcherName === 'toBeNull' ? 'null' : 'undefined'
|
|
76
76
|
},
|
|
77
77
|
node
|
|
78
78
|
});
|
package/lib/rules/utils/index.js
CHANGED
|
@@ -57,4 +57,15 @@ Object.keys(_parseJestFnCall).forEach(function (key) {
|
|
|
57
57
|
return _parseJestFnCall[key];
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
|
+
});
|
|
61
|
+
var _ts = require("./ts");
|
|
62
|
+
Object.keys(_ts).forEach(function (key) {
|
|
63
|
+
if (key === "default" || key === "__esModule") return;
|
|
64
|
+
if (key in exports && exports[key] === _ts[key]) return;
|
|
65
|
+
Object.defineProperty(exports, key, {
|
|
66
|
+
enumerable: true,
|
|
67
|
+
get: function () {
|
|
68
|
+
return _ts[key];
|
|
69
|
+
}
|
|
70
|
+
});
|
|
60
71
|
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isBuiltinSymbolLike = isBuiltinSymbolLike;
|
|
7
|
+
let SymbolFlags;
|
|
8
|
+
let TypeFlags;
|
|
9
|
+
function isSymbolFromDefaultLibrary(program, symbol) {
|
|
10
|
+
/* istanbul ignore next */
|
|
11
|
+
const declarations = symbol.getDeclarations() ?? [];
|
|
12
|
+
for (const declaration of declarations) {
|
|
13
|
+
const sourceFile = declaration.getSourceFile();
|
|
14
|
+
|
|
15
|
+
/* istanbul ignore else */
|
|
16
|
+
if (program.isSourceFileDefaultLibrary(sourceFile)) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* istanbul ignore next */
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
function isBuiltinSymbolLike(program, type, symbolName) {
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
26
|
+
({
|
|
27
|
+
TypeFlags,
|
|
28
|
+
SymbolFlags
|
|
29
|
+
} = require('typescript'));
|
|
30
|
+
return isBuiltinSymbolLikeRecurser(program, type, subType => {
|
|
31
|
+
const symbol = subType.getSymbol();
|
|
32
|
+
if (!symbol) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
const actualSymbolName = symbol.getName();
|
|
36
|
+
if (actualSymbolName === symbolName && isSymbolFromDefaultLibrary(program, symbol)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function isBuiltinSymbolLikeRecurser(program, type, predicate) {
|
|
43
|
+
if (type.isIntersection()) {
|
|
44
|
+
return type.types.some(t => isBuiltinSymbolLikeRecurser(program, t, predicate));
|
|
45
|
+
}
|
|
46
|
+
if (type.isUnion()) {
|
|
47
|
+
return type.types.every(t => isBuiltinSymbolLikeRecurser(program, t, predicate));
|
|
48
|
+
}
|
|
49
|
+
if (isTypeParameter(type)) {
|
|
50
|
+
const t = type.getConstraint();
|
|
51
|
+
if (t) {
|
|
52
|
+
return isBuiltinSymbolLikeRecurser(program, t, predicate);
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const predicateResult = predicate(type);
|
|
57
|
+
if (typeof predicateResult === 'boolean') {
|
|
58
|
+
return predicateResult;
|
|
59
|
+
}
|
|
60
|
+
const symbol = type.getSymbol();
|
|
61
|
+
if (symbol && symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
|
|
62
|
+
const checker = program.getTypeChecker();
|
|
63
|
+
for (const baseType of checker.getBaseTypes(type)) {
|
|
64
|
+
if (isBuiltinSymbolLikeRecurser(program, baseType, predicate)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
function isTypeParameter(type) {
|
|
72
|
+
return (type.flags & TypeFlags.TypeParameter) !== 0;
|
|
73
|
+
}
|
|
@@ -6,70 +6,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
var _utils = require("@typescript-eslint/utils");
|
|
8
8
|
var _utils2 = require("./utils");
|
|
9
|
-
let SymbolFlags;
|
|
10
|
-
let TypeFlags;
|
|
11
|
-
function isSymbolFromDefaultLibrary(program, symbol) {
|
|
12
|
-
/* istanbul ignore next */
|
|
13
|
-
const declarations = symbol.getDeclarations() ?? [];
|
|
14
|
-
for (const declaration of declarations) {
|
|
15
|
-
const sourceFile = declaration.getSourceFile();
|
|
16
|
-
|
|
17
|
-
/* istanbul ignore else */
|
|
18
|
-
if (program.isSourceFileDefaultLibrary(sourceFile)) {
|
|
19
|
-
return true;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/* istanbul ignore next */
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
function isBuiltinSymbolLike(program, type, symbolName) {
|
|
27
|
-
return isBuiltinSymbolLikeRecurser(program, type, subType => {
|
|
28
|
-
const symbol = subType.getSymbol();
|
|
29
|
-
if (!symbol) {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
const actualSymbolName = symbol.getName();
|
|
33
|
-
if (actualSymbolName === symbolName && isSymbolFromDefaultLibrary(program, symbol)) {
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
function isBuiltinSymbolLikeRecurser(program, type, predicate) {
|
|
40
|
-
if (type.isIntersection()) {
|
|
41
|
-
return type.types.some(t => isBuiltinSymbolLikeRecurser(program, t, predicate));
|
|
42
|
-
}
|
|
43
|
-
if (type.isUnion()) {
|
|
44
|
-
return type.types.every(t => isBuiltinSymbolLikeRecurser(program, t, predicate));
|
|
45
|
-
}
|
|
46
|
-
if (isTypeParameter(type)) {
|
|
47
|
-
const t = type.getConstraint();
|
|
48
|
-
if (t) {
|
|
49
|
-
return isBuiltinSymbolLikeRecurser(program, t, predicate);
|
|
50
|
-
}
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
const predicateResult = predicate(type);
|
|
54
|
-
if (typeof predicateResult === 'boolean') {
|
|
55
|
-
return predicateResult;
|
|
56
|
-
}
|
|
57
|
-
const symbol = type.getSymbol();
|
|
58
|
-
|
|
59
|
-
/* istanbul ignore next */
|
|
60
|
-
if (symbol && symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
|
|
61
|
-
const checker = program.getTypeChecker();
|
|
62
|
-
for (const baseType of checker.getBaseTypes(type)) {
|
|
63
|
-
if (isBuiltinSymbolLikeRecurser(program, baseType, predicate)) {
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
function isTypeParameter(type) {
|
|
71
|
-
return (type.flags & TypeFlags.TypeParameter) !== 0;
|
|
72
|
-
}
|
|
73
9
|
var _default = exports.default = (0, _utils2.createRule)({
|
|
74
10
|
name: __filename,
|
|
75
11
|
meta: {
|
|
@@ -87,12 +23,6 @@ var _default = exports.default = (0, _utils2.createRule)({
|
|
|
87
23
|
defaultOptions: [],
|
|
88
24
|
create(context) {
|
|
89
25
|
const services = _utils.ESLintUtils.getParserServices(context);
|
|
90
|
-
|
|
91
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
92
|
-
({
|
|
93
|
-
TypeFlags,
|
|
94
|
-
SymbolFlags
|
|
95
|
-
} = require('typescript'));
|
|
96
26
|
return {
|
|
97
27
|
CallExpression(node) {
|
|
98
28
|
const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
|
|
@@ -100,7 +30,7 @@ var _default = exports.default = (0, _utils2.createRule)({
|
|
|
100
30
|
return;
|
|
101
31
|
}
|
|
102
32
|
const [argument] = jestFnCall.head.node.parent.arguments;
|
|
103
|
-
const isPromiseLike = isBuiltinSymbolLike(services.program, services.getTypeAtLocation(argument), 'Promise');
|
|
33
|
+
const isPromiseLike = (0, _utils2.isBuiltinSymbolLike)(services.program, services.getTypeAtLocation(argument), 'Promise');
|
|
104
34
|
const promiseModifier = jestFnCall.modifiers.find(nod => (0, _utils2.getAccessorValue)(nod) !== 'not');
|
|
105
35
|
if (isPromiseLike && !promiseModifier) {
|
|
106
36
|
context.report({
|