eslint-plugin-jest 29.7.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/README.md CHANGED
@@ -394,11 +394,12 @@ Manually fixable by
394
394
 
395
395
  ### Requires Type Checking
396
396
 
397
- | Name                     | Description | 💼 | ⚠️ | 🔧 | 💡 |
398
- | :----------------------------------------------------------------- | :----------------------------------------------------------- | :-- | :-- | :-- | :-- |
399
- | [no-error-equal](docs/rules/no-error-equal.md) | Disallow using equality matchers on error types | | | | |
400
- | [no-unnecessary-assertion](docs/rules/no-unnecessary-assertion.md) | Disallow unnecessary assertions based on types | | | | |
401
- | [unbound-method](docs/rules/unbound-method.md) | Enforce unbound methods are called with their expected scope | | | | |
397
+ | Name                      | Description | 💼 | ⚠️ | 🔧 | 💡 |
398
+ | :------------------------------------------------------------------- | :------------------------------------------------------------------------------------------ | :-- | :-- | :-- | :-- |
399
+ | [no-error-equal](docs/rules/no-error-equal.md) | Disallow using equality matchers on error types | | | | |
400
+ | [no-unnecessary-assertion](docs/rules/no-unnecessary-assertion.md) | Disallow unnecessary assertions based on types | | | | |
401
+ | [unbound-method](docs/rules/unbound-method.md) | Enforce unbound methods are called with their expected scope | | | | |
402
+ | [valid-expect-with-promise](docs/rules/valid-expect-with-promise.md) | Require that `resolve` and `reject` modifiers are present (and only) for promise-like types | | | | |
402
403
 
403
404
  <!-- end auto-generated rules list -->
404
405
 
@@ -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` or `undefined` on
14
- something that cannot be those types, as that indicates either the assertion can
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
  ```
@@ -0,0 +1,40 @@
1
+ # Require that `resolve` and `reject` modifiers are present (and only) for promise-like types (`valid-expect-with-promise`)
2
+
3
+ 💭 This rule requires
4
+ [type information](https://typescript-eslint.io/linting/typed-linting).
5
+
6
+ <!-- end auto-generated rule header -->
7
+
8
+ When working with promises, you must remember to use `resolves` and `rejects` to
9
+ assert on the value returned (or thrown) by the promise, rather than the promise
10
+ itself.
11
+
12
+ Inversely, while Jest does not prevent you from using `resolves` and `rejects`
13
+ on non-promise values, it is not necessary.
14
+
15
+ When TypeScript is in use, it is possible to determine when `resolves` and
16
+ `rejects` should and should not be needed.
17
+
18
+ ## Rule details
19
+
20
+ This rule warns when:
21
+
22
+ - an `expect` is given a promise-like value but without `resolves` or `rejects`
23
+ - an `expect` is not given a promise-like value, but is used with `resolves` or
24
+ `rejects`
25
+
26
+ The following patterns are considered warnings:
27
+
28
+ ```ts
29
+ expect('hello world').resolves.toBe('hello sunshine');
30
+
31
+ expect(new Promise(r => r(0))).toThrow('oh noes!');
32
+ ```
33
+
34
+ The following patterns are not considered warnings:
35
+
36
+ ```ts
37
+ expect('hello world').toBe('hello sunshine');
38
+
39
+ expect(new Promise(r => r(0))).rejects.toThrow('oh noes!');
40
+ ```
@@ -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 isNullable = canBe(services.getTypeAtLocation(argument), matcherName === 'toBeNull' ? TypeFlags.Null : TypeFlags.Undefined);
71
- if (!isNullable) {
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
  });
@@ -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
+ }
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _utils = require("@typescript-eslint/utils");
8
+ var _utils2 = require("./utils");
9
+ var _default = exports.default = (0, _utils2.createRule)({
10
+ name: __filename,
11
+ meta: {
12
+ docs: {
13
+ description: 'Require that `resolve` and `reject` modifiers are present (and only) for promise-like types',
14
+ requiresTypeChecking: true
15
+ },
16
+ messages: {
17
+ poorlyExpectedPromise: 'Subject is a promise so resolve or reject should be used',
18
+ unneededRejectResolve: 'Subject is not a promise so {{ modifier }} is not needed'
19
+ },
20
+ type: 'suggestion',
21
+ schema: []
22
+ },
23
+ defaultOptions: [],
24
+ create(context) {
25
+ const services = _utils.ESLintUtils.getParserServices(context);
26
+ return {
27
+ CallExpression(node) {
28
+ const jestFnCall = (0, _utils2.parseJestFnCall)(node, context);
29
+ if (jestFnCall?.type !== 'expect' || jestFnCall.head.node.parent.type !== _utils.AST_NODE_TYPES.CallExpression) {
30
+ return;
31
+ }
32
+ const [argument] = jestFnCall.head.node.parent.arguments;
33
+ const isPromiseLike = (0, _utils2.isBuiltinSymbolLike)(services.program, services.getTypeAtLocation(argument), 'Promise');
34
+ const promiseModifier = jestFnCall.modifiers.find(nod => (0, _utils2.getAccessorValue)(nod) !== 'not');
35
+ if (isPromiseLike && !promiseModifier) {
36
+ context.report({
37
+ messageId: 'poorlyExpectedPromise',
38
+ node
39
+ });
40
+ return;
41
+ }
42
+ if (!isPromiseLike && promiseModifier) {
43
+ context.report({
44
+ messageId: 'unneededRejectResolve',
45
+ data: {
46
+ modifier: (0, _utils2.getAccessorValue)(promiseModifier)
47
+ },
48
+ node: promiseModifier
49
+ });
50
+ }
51
+ }
52
+ };
53
+ }
54
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-jest",
3
- "version": "29.7.0",
3
+ "version": "29.9.0",
4
4
  "description": "ESLint rules for Jest",
5
5
  "keywords": [
6
6
  "eslint",