eslint-plugin-jest 24.4.2 → 26.1.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 (77) hide show
  1. package/README.md +75 -50
  2. package/docs/rules/expect-expect.md +42 -1
  3. package/docs/rules/max-nested-describe.md +4 -5
  4. package/docs/rules/no-conditional-expect.md +57 -3
  5. package/docs/rules/no-conditional-in-test.md +79 -0
  6. package/docs/rules/no-deprecated-functions.md +5 -0
  7. package/docs/rules/no-done-callback.md +3 -3
  8. package/docs/rules/no-if.md +5 -0
  9. package/docs/rules/no-standalone-expect.md +3 -3
  10. package/docs/rules/no-test-return-statement.md +1 -2
  11. package/docs/rules/prefer-comparison-matcher.md +55 -0
  12. package/docs/rules/prefer-equality-matcher.md +29 -0
  13. package/docs/rules/prefer-expect-assertions.md +126 -0
  14. package/docs/rules/prefer-expect-resolves.md +53 -0
  15. package/docs/rules/prefer-hooks-on-top.md +72 -48
  16. package/docs/rules/{lowercase-name.md → prefer-lowercase-title.md} +7 -7
  17. package/docs/rules/prefer-snapshot-hint.md +188 -0
  18. package/docs/rules/prefer-to-be.md +53 -0
  19. package/docs/rules/require-hook.md +187 -0
  20. package/docs/rules/require-top-level-describe.md +28 -0
  21. package/docs/rules/{valid-describe.md → valid-describe-callback.md} +1 -1
  22. package/docs/rules/valid-expect-in-promise.md +55 -14
  23. package/docs/rules/valid-expect.md +13 -0
  24. package/docs/rules/valid-title.md +30 -2
  25. package/lib/index.js +2 -3
  26. package/lib/processors/snapshot-processor.js +1 -1
  27. package/lib/rules/consistent-test-it.js +20 -20
  28. package/lib/rules/detectJestVersion.js +29 -0
  29. package/lib/rules/expect-expect.js +25 -11
  30. package/lib/rules/max-nested-describe.js +5 -5
  31. package/lib/rules/no-conditional-expect.js +9 -9
  32. package/lib/rules/no-conditional-in-test.js +60 -0
  33. package/lib/rules/no-deprecated-functions.js +14 -32
  34. package/lib/rules/no-done-callback.js +10 -10
  35. package/lib/rules/no-export.js +6 -6
  36. package/lib/rules/no-focused-tests.js +11 -11
  37. package/lib/rules/no-identical-title.js +3 -3
  38. package/lib/rules/no-if.js +13 -11
  39. package/lib/rules/no-interpolation-in-snapshots.js +6 -6
  40. package/lib/rules/no-jasmine-globals.js +10 -10
  41. package/lib/rules/no-large-snapshots.js +11 -11
  42. package/lib/rules/no-standalone-expect.js +14 -14
  43. package/lib/rules/no-test-prefixes.js +6 -6
  44. package/lib/rules/no-test-return-statement.js +8 -8
  45. package/lib/rules/prefer-comparison-matcher.js +139 -0
  46. package/lib/rules/prefer-equality-matcher.js +98 -0
  47. package/lib/rules/prefer-expect-assertions.js +93 -11
  48. package/lib/rules/prefer-expect-resolves.js +48 -0
  49. package/lib/rules/prefer-hooks-on-top.js +1 -1
  50. package/lib/rules/{lowercase-name.js → prefer-lowercase-title.js} +20 -1
  51. package/lib/rules/prefer-snapshot-hint.js +112 -0
  52. package/lib/rules/prefer-spy-on.js +9 -9
  53. package/lib/rules/prefer-to-be.js +136 -0
  54. package/lib/rules/prefer-to-contain.js +19 -67
  55. package/lib/rules/prefer-to-have-length.js +9 -14
  56. package/lib/rules/prefer-todo.js +9 -9
  57. package/lib/rules/require-hook.js +121 -0
  58. package/lib/rules/require-top-level-describe.js +40 -6
  59. package/lib/rules/utils.js +34 -30
  60. package/lib/rules/{valid-describe.js → valid-describe-callback.js} +9 -9
  61. package/lib/rules/valid-expect-in-promise.js +336 -67
  62. package/lib/rules/valid-expect.js +36 -19
  63. package/lib/rules/valid-title.js +61 -61
  64. package/package.json +40 -27
  65. package/CHANGELOG.md +0 -513
  66. package/docs/rules/no-expect-resolves.md +0 -47
  67. package/docs/rules/no-truthy-falsy.md +0 -53
  68. package/docs/rules/no-try-expect.md +0 -63
  69. package/docs/rules/prefer-inline-snapshots.md +0 -51
  70. package/docs/rules/prefer-to-be-null.md +0 -33
  71. package/docs/rules/prefer-to-be-undefined.md +0 -33
  72. package/lib/rules/no-expect-resolves.js +0 -40
  73. package/lib/rules/no-truthy-falsy.js +0 -58
  74. package/lib/rules/no-try-expect.js +0 -89
  75. package/lib/rules/prefer-inline-snapshots.js +0 -69
  76. package/lib/rules/prefer-to-be-null.js +0 -67
  77. package/lib/rules/prefer-to-be-undefined.js +0 -67
@@ -5,100 +5,293 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _experimentalUtils = require("@typescript-eslint/experimental-utils");
8
+ var _utils = require("@typescript-eslint/utils");
9
9
 
10
- var _utils = require("./utils");
10
+ var _utils2 = require("./utils");
11
11
 
12
- const isThenOrCatchCall = node => node.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && node.callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(node.callee.property) && ['then', 'catch'].includes((0, _utils.getAccessorValue)(node.callee.property));
12
+ const isPromiseChainCall = node => {
13
+ if (node.type === _utils.AST_NODE_TYPES.CallExpression && node.callee.type === _utils.AST_NODE_TYPES.MemberExpression && (0, _utils2.isSupportedAccessor)(node.callee.property)) {
14
+ // promise methods should have at least 1 argument
15
+ if (node.arguments.length === 0) {
16
+ return false;
17
+ }
13
18
 
14
- const isExpectCallPresentInFunction = body => {
15
- if (body.type === _experimentalUtils.AST_NODE_TYPES.BlockStatement) {
16
- return body.body.find(line => {
17
- if (line.type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement) {
18
- return isFullExpectCall(line.expression);
19
- }
19
+ switch ((0, _utils2.getAccessorValue)(node.callee.property)) {
20
+ case 'then':
21
+ return node.arguments.length < 3;
22
+
23
+ case 'catch':
24
+ case 'finally':
25
+ return node.arguments.length < 2;
26
+ }
27
+ }
28
+
29
+ return false;
30
+ };
31
+
32
+ const findTopMostCallExpression = node => {
33
+ let topMostCallExpression = node;
34
+ let {
35
+ parent
36
+ } = node;
37
+
38
+ while (parent) {
39
+ if (parent.type === _utils.AST_NODE_TYPES.CallExpression) {
40
+ topMostCallExpression = parent;
41
+ parent = parent.parent;
42
+ continue;
43
+ }
44
+
45
+ if (parent.type !== _utils.AST_NODE_TYPES.MemberExpression) {
46
+ break;
47
+ }
48
+
49
+ parent = parent.parent;
50
+ }
51
+
52
+ return topMostCallExpression;
53
+ };
54
+
55
+ const isTestCaseCallWithCallbackArg = node => {
56
+ if (!(0, _utils2.isTestCaseCall)(node)) {
57
+ return false;
58
+ }
59
+
60
+ const isJestEach = (0, _utils2.getNodeName)(node).endsWith('.each');
61
+
62
+ if (isJestEach && node.callee.type !== _utils.AST_NODE_TYPES.TaggedTemplateExpression) {
63
+ // isJestEach but not a TaggedTemplateExpression, so this must be
64
+ // the `jest.each([])()` syntax which this rule doesn't support due
65
+ // to its complexity (see jest-community/eslint-plugin-jest#710)
66
+ // so we return true to trigger bailout
67
+ return true;
68
+ }
69
+
70
+ if (isJestEach || node.arguments.length >= 2) {
71
+ const [, callback] = node.arguments;
72
+ const callbackArgIndex = Number(isJestEach);
73
+ return callback && (0, _utils2.isFunction)(callback) && callback.params.length === 1 + callbackArgIndex;
74
+ }
75
+
76
+ return false;
77
+ };
78
+
79
+ const isPromiseMethodThatUsesValue = (node, identifier) => {
80
+ const {
81
+ name
82
+ } = identifier;
83
+
84
+ if (node.argument === null) {
85
+ return false;
86
+ }
87
+
88
+ if (node.argument.type === _utils.AST_NODE_TYPES.CallExpression && node.argument.arguments.length > 0) {
89
+ const nodeName = (0, _utils2.getNodeName)(node.argument);
20
90
 
21
- if (line.type === _experimentalUtils.AST_NODE_TYPES.ReturnStatement && line.argument) {
22
- return isFullExpectCall(line.argument);
91
+ if (['Promise.all', 'Promise.allSettled'].includes(nodeName)) {
92
+ const [firstArg] = node.argument.arguments;
93
+
94
+ if (firstArg.type === _utils.AST_NODE_TYPES.ArrayExpression && firstArg.elements.some(nod => (0, _utils2.isIdentifier)(nod, name))) {
95
+ return true;
23
96
  }
97
+ }
24
98
 
25
- return false;
26
- });
99
+ if (['Promise.resolve', 'Promise.reject'].includes(nodeName) && node.argument.arguments.length === 1) {
100
+ return (0, _utils2.isIdentifier)(node.argument.arguments[0], name);
101
+ }
27
102
  }
28
103
 
29
- return isFullExpectCall(body);
104
+ return (0, _utils2.isIdentifier)(node.argument, name);
30
105
  };
106
+ /**
107
+ * Attempts to determine if the runtime value represented by the given `identifier`
108
+ * is `await`ed within the given array of elements
109
+ */
31
110
 
32
- const isFullExpectCall = expression => expression.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && (0, _utils.isExpectMember)(expression.callee);
33
111
 
34
- const reportReturnRequired = (context, node) => {
35
- context.report({
36
- loc: {
37
- end: {
38
- column: node.loc.end.column,
39
- line: node.loc.end.line
40
- },
41
- start: node.loc.start
42
- },
43
- messageId: 'returnPromise',
44
- node
45
- });
112
+ const isValueAwaitedInElements = (name, elements) => {
113
+ for (const element of elements) {
114
+ if (element.type === _utils.AST_NODE_TYPES.AwaitExpression && (0, _utils2.isIdentifier)(element.argument, name)) {
115
+ return true;
116
+ }
117
+
118
+ if (element.type === _utils.AST_NODE_TYPES.ArrayExpression && isValueAwaitedInElements(name, element.elements)) {
119
+ return true;
120
+ }
121
+ }
122
+
123
+ return false;
46
124
  };
125
+ /**
126
+ * Attempts to determine if the runtime value represented by the given `identifier`
127
+ * is `await`ed as an argument along the given call expression
128
+ */
129
+
130
+
131
+ const isValueAwaitedInArguments = (name, call) => {
132
+ let node = call;
133
+
134
+ while (node) {
135
+ if (node.type === _utils.AST_NODE_TYPES.CallExpression) {
136
+ if (isValueAwaitedInElements(name, node.arguments)) {
137
+ return true;
138
+ }
139
+
140
+ node = node.callee;
141
+ }
47
142
 
48
- const isPromiseReturnedLater = (node, testFunctionBody) => {
49
- let promiseName;
143
+ if (node.type !== _utils.AST_NODE_TYPES.MemberExpression) {
144
+ break;
145
+ }
50
146
 
51
- if (node.type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement && node.expression.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && node.expression.callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(node.expression.callee.object)) {
52
- promiseName = (0, _utils.getAccessorValue)(node.expression.callee.object);
53
- } else if (node.type === _experimentalUtils.AST_NODE_TYPES.VariableDeclarator && node.id.type === _experimentalUtils.AST_NODE_TYPES.Identifier) {
54
- promiseName = node.id.name;
147
+ node = node.object;
55
148
  }
56
149
 
57
- const lastLineInTestFunc = testFunctionBody[testFunctionBody.length - 1];
58
- return lastLineInTestFunc.type === _experimentalUtils.AST_NODE_TYPES.ReturnStatement && lastLineInTestFunc.argument && ('name' in lastLineInTestFunc.argument && lastLineInTestFunc.argument.name === promiseName || !promiseName);
150
+ return false;
59
151
  };
60
152
 
61
- const isTestFunc = node => node.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && (0, _utils.isSupportedAccessor)(node.callee) && [_utils.TestCaseName.it, _utils.TestCaseName.test].includes((0, _utils.getAccessorValue)(node.callee));
153
+ const getLeftMostCallExpression = call => {
154
+ let leftMostCallExpression = call;
155
+ let node = call;
62
156
 
63
- const findTestFunction = node => {
64
157
  while (node) {
65
- if ((0, _utils.isFunction)(node) && node.parent && isTestFunc(node.parent)) {
66
- return node;
158
+ if (node.type === _utils.AST_NODE_TYPES.CallExpression) {
159
+ leftMostCallExpression = node;
160
+ node = node.callee;
161
+ }
162
+
163
+ if (node.type !== _utils.AST_NODE_TYPES.MemberExpression) {
164
+ break;
67
165
  }
68
166
 
69
- node = node.parent;
167
+ node = node.object;
70
168
  }
71
169
 
72
- return null;
170
+ return leftMostCallExpression;
73
171
  };
172
+ /**
173
+ * Attempts to determine if the runtime value represented by the given `identifier`
174
+ * is `await`ed or `return`ed within the given `body` of statements
175
+ */
176
+
74
177
 
75
- const isParentThenOrPromiseReturned = (node, testFunctionBody) => node.type === _experimentalUtils.AST_NODE_TYPES.ReturnStatement || isPromiseReturnedLater(node, testFunctionBody);
178
+ const isValueAwaitedOrReturned = (identifier, body) => {
179
+ const {
180
+ name
181
+ } = identifier;
76
182
 
77
- const verifyExpectWithReturn = (promiseCallbacks, node, context, testFunctionBody) => {
78
- promiseCallbacks.some(promiseCallback => {
79
- if (promiseCallback && (0, _utils.isFunction)(promiseCallback)) {
80
- if (isExpectCallPresentInFunction(promiseCallback.body) && node.parent.parent && !isParentThenOrPromiseReturned(node.parent.parent, testFunctionBody)) {
81
- reportReturnRequired(context, node.parent.parent);
183
+ for (const node of body) {
184
+ // skip all nodes that are before this identifier, because they'd probably
185
+ // be affecting a different runtime value (e.g. due to reassignment)
186
+ if (node.range[0] <= identifier.range[0]) {
187
+ continue;
188
+ }
189
+
190
+ if (node.type === _utils.AST_NODE_TYPES.ReturnStatement) {
191
+ return isPromiseMethodThatUsesValue(node, identifier);
192
+ }
193
+
194
+ if (node.type === _utils.AST_NODE_TYPES.ExpressionStatement) {
195
+ // it's possible that we're awaiting the value as an argument
196
+ if (node.expression.type === _utils.AST_NODE_TYPES.CallExpression) {
197
+ if (isValueAwaitedInArguments(name, node.expression)) {
198
+ return true;
199
+ }
200
+
201
+ const leftMostCall = getLeftMostCallExpression(node.expression);
202
+
203
+ if ((0, _utils2.isExpectCall)(leftMostCall) && leftMostCall.arguments.length > 0 && (0, _utils2.isIdentifier)(leftMostCall.arguments[0], name)) {
204
+ const {
205
+ modifier
206
+ } = (0, _utils2.parseExpectCall)(leftMostCall);
207
+
208
+ if ((modifier === null || modifier === void 0 ? void 0 : modifier.name) === _utils2.ModifierName.resolves || (modifier === null || modifier === void 0 ? void 0 : modifier.name) === _utils2.ModifierName.rejects) {
209
+ return true;
210
+ }
211
+ }
212
+ }
213
+
214
+ if (node.expression.type === _utils.AST_NODE_TYPES.AwaitExpression && isPromiseMethodThatUsesValue(node.expression, identifier)) {
82
215
  return true;
216
+ } // (re)assignment changes the runtime value, so if we've not found an
217
+ // await or return already we act as if we've reached the end of the body
218
+
219
+
220
+ if (node.expression.type === _utils.AST_NODE_TYPES.AssignmentExpression) {
221
+ var _getNodeName;
222
+
223
+ // unless we're assigning to the same identifier, in which case
224
+ // we might be chaining off the existing promise value
225
+ if ((0, _utils2.isIdentifier)(node.expression.left, name) && (_getNodeName = (0, _utils2.getNodeName)(node.expression.right)) !== null && _getNodeName !== void 0 && _getNodeName.startsWith(`${name}.`) && isPromiseChainCall(node.expression.right)) {
226
+ continue;
227
+ }
228
+
229
+ break;
83
230
  }
84
231
  }
85
232
 
86
- return false;
87
- });
233
+ if (node.type === _utils.AST_NODE_TYPES.BlockStatement && isValueAwaitedOrReturned(identifier, node.body)) {
234
+ return true;
235
+ }
236
+ }
237
+
238
+ return false;
239
+ };
240
+
241
+ const findFirstBlockBodyUp = node => {
242
+ let parent = node;
243
+
244
+ while (parent) {
245
+ if (parent.type === _utils.AST_NODE_TYPES.BlockStatement) {
246
+ return parent.body;
247
+ }
248
+
249
+ parent = parent.parent;
250
+ }
251
+ /* istanbul ignore next */
252
+
253
+
254
+ throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
255
+ };
256
+
257
+ const isDirectlyWithinTestCaseCall = node => {
258
+ let parent = node;
259
+
260
+ while (parent) {
261
+ if ((0, _utils2.isFunction)(parent)) {
262
+ var _parent;
263
+
264
+ parent = parent.parent;
265
+ return !!(((_parent = parent) === null || _parent === void 0 ? void 0 : _parent.type) === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isTestCaseCall)(parent));
266
+ }
267
+
268
+ parent = parent.parent;
269
+ }
270
+
271
+ return false;
88
272
  };
89
273
 
90
- const isHavingAsyncCallBackParam = testFunction => testFunction.params[0] && testFunction.params[0].type === _experimentalUtils.AST_NODE_TYPES.Identifier;
274
+ const isVariableAwaitedOrReturned = variable => {
275
+ const body = findFirstBlockBodyUp(variable); // it's pretty much impossible for us to track destructuring assignments,
276
+ // so we return true to bailout gracefully
277
+
278
+ if (!(0, _utils2.isIdentifier)(variable.id)) {
279
+ return true;
280
+ }
91
281
 
92
- var _default = (0, _utils.createRule)({
282
+ return isValueAwaitedOrReturned(variable.id, body);
283
+ };
284
+
285
+ var _default = (0, _utils2.createRule)({
93
286
  name: __filename,
94
287
  meta: {
95
288
  docs: {
96
289
  category: 'Best Practices',
97
- description: 'Enforce having return statement when testing with promises',
290
+ description: 'Ensure promises that have expectations in their chain are valid',
98
291
  recommended: 'error'
99
292
  },
100
293
  messages: {
101
- returnPromise: 'Promise should be returned to test its fulfillment or rejection'
294
+ expectInFloatingPromise: "This promise should either be returned or awaited to ensure the expects in it's chain are called"
102
295
  },
103
296
  type: 'suggestion',
104
297
  schema: []
@@ -106,30 +299,106 @@ var _default = (0, _utils.createRule)({
106
299
  defaultOptions: [],
107
300
 
108
301
  create(context) {
302
+ let inTestCaseWithDoneCallback = false; // an array of booleans representing each promise chain we enter, with the
303
+ // boolean value representing if we think a given chain contains an expect
304
+ // in it's body.
305
+ //
306
+ // since we only care about the inner-most chain, we represent the state in
307
+ // reverse with the inner-most being the first item, as that makes it
308
+ // slightly less code to assign to by not needing to know the length
309
+
310
+ const chains = [];
109
311
  return {
110
312
  CallExpression(node) {
111
- if (!isThenOrCatchCall(node) || node.parent && node.parent.type === _experimentalUtils.AST_NODE_TYPES.AwaitExpression) {
313
+ // there are too many ways that the done argument could be used with
314
+ // promises that contain expect that would make the promise safe for us
315
+ if (isTestCaseCallWithCallbackArg(node)) {
316
+ inTestCaseWithDoneCallback = true;
112
317
  return;
113
- }
318
+ } // if this call expression is a promise chain, add it to the stack with
319
+ // value of "false", as we assume there are no expect calls initially
114
320
 
115
- const testFunction = findTestFunction(node);
116
321
 
117
- if (testFunction && !isHavingAsyncCallBackParam(testFunction)) {
118
- const {
119
- body
120
- } = testFunction;
322
+ if (isPromiseChainCall(node)) {
323
+ chains.unshift(false);
324
+ return;
325
+ } // if we're within a promise chain, and this call expression looks like
326
+ // an expect call, mark the deepest chain as having an expect call
121
327
 
122
- if (body.type !== _experimentalUtils.AST_NODE_TYPES.BlockStatement) {
123
- return;
328
+
329
+ if (chains.length > 0 && (0, _utils2.isExpectCall)(node)) {
330
+ chains[0] = true;
331
+ }
332
+ },
333
+
334
+ 'CallExpression:exit'(node) {
335
+ // there are too many ways that the "done" argument could be used to
336
+ // make promises containing expects safe in a test for us to be able to
337
+ // accurately check, so we just bail out completely if it's present
338
+ if (inTestCaseWithDoneCallback) {
339
+ if ((0, _utils2.isTestCaseCall)(node)) {
340
+ inTestCaseWithDoneCallback = false;
124
341
  }
125
342
 
126
- const testFunctionBody = body.body; // then block can have two args, fulfillment & rejection
127
- // then block can have one args, fulfillment
128
- // catch block can have one args, rejection
129
- // ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
343
+ return;
344
+ }
345
+
346
+ if (!isPromiseChainCall(node)) {
347
+ return;
348
+ } // since we're exiting this call expression (which is a promise chain)
349
+ // we remove it from the stack of chains, since we're unwinding
350
+
130
351
 
131
- verifyExpectWithReturn(node.arguments.slice(0, 2), node.callee, context, testFunctionBody);
352
+ const hasExpectCall = chains.shift(); // if the promise chain we're exiting doesn't contain an expect,
353
+ // then we don't need to check it for anything
354
+
355
+ if (!hasExpectCall) {
356
+ return;
357
+ }
358
+
359
+ const {
360
+ parent
361
+ } = findTopMostCallExpression(node); // if we don't have a parent (which is technically impossible at runtime)
362
+ // or our parent is not directly within the test case, we stop checking
363
+ // because we're most likely in the body of a function being defined
364
+ // within the test, which we can't track
365
+
366
+ if (!parent || !isDirectlyWithinTestCaseCall(parent)) {
367
+ return;
132
368
  }
369
+
370
+ switch (parent.type) {
371
+ case _utils.AST_NODE_TYPES.VariableDeclarator:
372
+ {
373
+ if (isVariableAwaitedOrReturned(parent)) {
374
+ return;
375
+ }
376
+
377
+ break;
378
+ }
379
+
380
+ case _utils.AST_NODE_TYPES.AssignmentExpression:
381
+ {
382
+ if (parent.left.type === _utils.AST_NODE_TYPES.Identifier && isValueAwaitedOrReturned(parent.left, findFirstBlockBodyUp(parent))) {
383
+ return;
384
+ }
385
+
386
+ break;
387
+ }
388
+
389
+ case _utils.AST_NODE_TYPES.ExpressionStatement:
390
+ break;
391
+
392
+ case _utils.AST_NODE_TYPES.ReturnStatement:
393
+ case _utils.AST_NODE_TYPES.AwaitExpression:
394
+ default:
395
+ return;
396
+ }
397
+
398
+ context.report({
399
+ messageId: 'expectInFloatingPromise',
400
+ node: parent
401
+ });
133
402
  }
134
403
 
135
404
  };
@@ -5,9 +5,9 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _experimentalUtils = require("@typescript-eslint/experimental-utils");
8
+ var _utils = require("@typescript-eslint/utils");
9
9
 
10
- var _utils = require("./utils");
10
+ var _utils2 = require("./utils");
11
11
 
12
12
  /*
13
13
  * This implementation is ported from from eslint-plugin-jasmine.
@@ -22,23 +22,29 @@ var _utils = require("./utils");
22
22
  * @Returns CallExpressionNode
23
23
  */
24
24
  const getPromiseCallExpressionNode = node => {
25
- if (node.type === _experimentalUtils.AST_NODE_TYPES.ArrayExpression && node.parent && node.parent.type === _experimentalUtils.AST_NODE_TYPES.CallExpression) {
25
+ if (node.type === _utils.AST_NODE_TYPES.ArrayExpression && node.parent && node.parent.type === _utils.AST_NODE_TYPES.CallExpression) {
26
26
  node = node.parent;
27
27
  }
28
28
 
29
- if (node.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && node.callee && node.callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(node.callee.object) && (0, _utils.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) && (0, _utils2.getAccessorValue)(node.callee.object) === 'Promise' && node.parent) {
30
30
  return node;
31
31
  }
32
32
 
33
33
  return null;
34
34
  };
35
35
 
36
- const findPromiseCallExpressionNode = node => node.parent && node.parent.parent && [_experimentalUtils.AST_NODE_TYPES.CallExpression, _experimentalUtils.AST_NODE_TYPES.ArrayExpression].includes(node.parent.type) ? getPromiseCallExpressionNode(node.parent) : null;
36
+ const findPromiseCallExpressionNode = node => {
37
+ var _node$parent;
38
+
39
+ return (_node$parent = node.parent) !== null && _node$parent !== void 0 && _node$parent.parent && [_utils.AST_NODE_TYPES.CallExpression, _utils.AST_NODE_TYPES.ArrayExpression].includes(node.parent.type) ? getPromiseCallExpressionNode(node.parent) : null;
40
+ };
37
41
 
38
42
  const getParentIfThenified = node => {
39
- const grandParentNode = node.parent && node.parent.parent;
43
+ var _node$parent2;
44
+
45
+ const grandParentNode = (_node$parent2 = node.parent) === null || _node$parent2 === void 0 ? void 0 : _node$parent2.parent;
40
46
 
41
- if (grandParentNode && grandParentNode.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && grandParentNode.callee && (0, _utils.isExpectMember)(grandParentNode.callee) && ['then', 'catch'].includes((0, _utils.getAccessorValue)(grandParentNode.callee.property)) && grandParentNode.parent) {
47
+ if (grandParentNode && grandParentNode.type === _utils.AST_NODE_TYPES.CallExpression && (0, _utils2.isExpectMember)(grandParentNode.callee) && ['then', 'catch'].includes((0, _utils2.getAccessorValue)(grandParentNode.callee.property)) && grandParentNode.parent) {
42
48
  // Just in case `then`s are chained look one above.
43
49
  return getParentIfThenified(grandParentNode);
44
50
  }
@@ -47,25 +53,27 @@ const getParentIfThenified = node => {
47
53
  };
48
54
 
49
55
  const isAcceptableReturnNode = (node, allowReturn) => {
50
- if (allowReturn && node.type === _experimentalUtils.AST_NODE_TYPES.ReturnStatement) {
56
+ if (allowReturn && node.type === _utils.AST_NODE_TYPES.ReturnStatement) {
51
57
  return true;
52
58
  }
53
59
 
54
- if (node.type === _experimentalUtils.AST_NODE_TYPES.ConditionalExpression && node.parent) {
60
+ if (node.type === _utils.AST_NODE_TYPES.ConditionalExpression && node.parent) {
55
61
  return isAcceptableReturnNode(node.parent, allowReturn);
56
62
  }
57
63
 
58
- return [_experimentalUtils.AST_NODE_TYPES.ArrowFunctionExpression, _experimentalUtils.AST_NODE_TYPES.AwaitExpression].includes(node.type);
64
+ return [_utils.AST_NODE_TYPES.ArrowFunctionExpression, _utils.AST_NODE_TYPES.AwaitExpression].includes(node.type);
59
65
  };
60
66
 
61
- const isNoAssertionsParentNode = node => node.type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement || node.type === _experimentalUtils.AST_NODE_TYPES.AwaitExpression && node.parent !== undefined && node.parent.type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement;
67
+ const isNoAssertionsParentNode = node => node.type === _utils.AST_NODE_TYPES.ExpressionStatement || node.type === _utils.AST_NODE_TYPES.AwaitExpression && node.parent !== undefined && node.parent.type === _utils.AST_NODE_TYPES.ExpressionStatement;
62
68
 
63
69
  const promiseArrayExceptionKey = ({
64
70
  start,
65
71
  end
66
72
  }) => `${start.line}:${start.column}-${end.line}:${end.column}`;
67
73
 
68
- var _default = (0, _utils.createRule)({
74
+ const defaultAsyncMatchers = ['toReject', 'toResolve'];
75
+
76
+ var _default = (0, _utils2.createRule)({
69
77
  name: __filename,
70
78
  meta: {
71
79
  docs: {
@@ -90,6 +98,12 @@ var _default = (0, _utils.createRule)({
90
98
  type: 'boolean',
91
99
  default: false
92
100
  },
101
+ asyncMatchers: {
102
+ type: 'array',
103
+ items: {
104
+ type: 'string'
105
+ }
106
+ },
93
107
  minArgs: {
94
108
  type: 'number',
95
109
  minimum: 1
@@ -104,12 +118,14 @@ var _default = (0, _utils.createRule)({
104
118
  },
105
119
  defaultOptions: [{
106
120
  alwaysAwait: false,
121
+ asyncMatchers: defaultAsyncMatchers,
107
122
  minArgs: 1,
108
123
  maxArgs: 1
109
124
  }],
110
125
 
111
126
  create(context, [{
112
127
  alwaysAwait,
128
+ asyncMatchers = defaultAsyncMatchers,
113
129
  minArgs = 1,
114
130
  maxArgs = 1
115
131
  }]) {
@@ -130,7 +146,7 @@ var _default = (0, _utils.createRule)({
130
146
 
131
147
  return {
132
148
  CallExpression(node) {
133
- if (!(0, _utils.isExpectCall)(node)) {
149
+ if (!(0, _utils2.isExpectCall)(node)) {
134
150
  return;
135
151
  }
136
152
 
@@ -138,10 +154,10 @@ var _default = (0, _utils.createRule)({
138
154
  expect,
139
155
  modifier,
140
156
  matcher
141
- } = (0, _utils.parseExpectCall)(node);
157
+ } = (0, _utils2.parseExpectCall)(node);
142
158
 
143
159
  if (expect.arguments.length < minArgs) {
144
- const expectLength = (0, _utils.getAccessorValue)(expect.callee).length;
160
+ const expectLength = (0, _utils2.getAccessorValue)(expect.callee).length;
145
161
  const loc = {
146
162
  start: {
147
163
  column: node.loc.start.column + expectLength,
@@ -200,7 +216,7 @@ var _default = (0, _utils.createRule)({
200
216
  return;
201
217
  }
202
218
 
203
- if ((0, _utils.isExpectMember)(matcher.node.parent)) {
219
+ if ((0, _utils2.isExpectMember)(matcher.node.parent)) {
204
220
  context.report({
205
221
  messageId: 'modifierUnknown',
206
222
  data: {
@@ -219,8 +235,9 @@ var _default = (0, _utils.createRule)({
219
235
  }
220
236
 
221
237
  const parentNode = matcher.node.parent;
238
+ const shouldBeAwaited = modifier && modifier.name !== _utils2.ModifierName.not || asyncMatchers.includes(matcher.name);
222
239
 
223
- if (!parentNode.parent || !modifier || modifier.name === _utils.ModifierName.not) {
240
+ if (!parentNode.parent || !shouldBeAwaited) {
224
241
  return;
225
242
  }
226
243
  /**
@@ -229,7 +246,7 @@ var _default = (0, _utils.createRule)({
229
246
  */
230
247
 
231
248
 
232
- const isParentArrayExpression = parentNode.parent.type === _experimentalUtils.AST_NODE_TYPES.ArrayExpression;
249
+ const isParentArrayExpression = parentNode.parent.type === _utils.AST_NODE_TYPES.ArrayExpression;
233
250
  const orReturned = alwaysAwait ? '' : ' or returned';
234
251
  /**
235
252
  * An async assertion can be chained with `then` or `catch` statements.
@@ -260,7 +277,7 @@ var _default = (0, _utils.createRule)({
260
277
 
261
278
  // nothing called on "expect()"
262
279
  'CallExpression:exit'(node) {
263
- if ((0, _utils.isExpectCall)(node) && isNoAssertionsParentNode(node.parent)) {
280
+ if ((0, _utils2.isExpectCall)(node) && isNoAssertionsParentNode(node.parent)) {
264
281
  context.report({
265
282
  messageId: 'matcherNotFound',
266
283
  node