eslint-plugin-jest 24.5.2 → 24.6.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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [24.6.0](https://github.com/jest-community/eslint-plugin-jest/compare/v24.5.2...v24.6.0) (2021-10-09)
2
+
3
+
4
+ ### Features
5
+
6
+ * **valid-expect-in-promise:** re-implement rule ([#916](https://github.com/jest-community/eslint-plugin-jest/issues/916)) ([7a49c58](https://github.com/jest-community/eslint-plugin-jest/commit/7a49c5831e3d85a60c11e385203b8f83d98ad580))
7
+
1
8
  ## [24.5.2](https://github.com/jest-community/eslint-plugin-jest/compare/v24.5.1...v24.5.2) (2021-10-04)
2
9
 
3
10
 
package/README.md CHANGED
@@ -193,7 +193,7 @@ installations requiring long-term consistency.
193
193
  | [require-top-level-describe](docs/rules/require-top-level-describe.md) | Require test cases and hooks to be inside a `describe` block | | |
194
194
  | [valid-describe](docs/rules/valid-describe.md) | Enforce valid `describe()` callback | ![recommended][] | |
195
195
  | [valid-expect](docs/rules/valid-expect.md) | Enforce valid `expect()` usage | ![recommended][] | |
196
- | [valid-expect-in-promise](docs/rules/valid-expect-in-promise.md) | Enforce having return statement when testing with promises | ![recommended][] | |
196
+ | [valid-expect-in-promise](docs/rules/valid-expect-in-promise.md) | Ensure promises that have expectations in their chain are valid | ![recommended][] | |
197
197
  | [valid-title](docs/rules/valid-title.md) | Enforce valid titles | ![recommended][] | ![fixable][] |
198
198
 
199
199
  <!-- end base rules list -->
@@ -1,31 +1,72 @@
1
- # Enforce having return statement when testing with promises (`valid-expect-in-promise`)
1
+ # Ensure promises that have expectations in their chain are valid (`valid-expect-in-promise`)
2
2
 
3
- Ensure to return promise when having assertions in `then` or `catch` block of
4
- promise
3
+ Ensure promises that include expectations are returned or awaited.
5
4
 
6
5
  ## Rule details
7
6
 
8
- This rule looks for tests that have assertions in `then` and `catch` methods on
9
- promises that are not returned by the test.
7
+ This rule flags any promises within the body of a test that include expectations
8
+ that have either not been returned or awaited.
10
9
 
11
- ### Default configuration
12
-
13
- The following pattern is considered warning:
10
+ The following patterns is considered warning:
14
11
 
15
12
  ```js
16
- it('promise test', () => {
17
- somePromise.then(data => {
18
- expect(data).toEqual('foo');
13
+ it('promises a person', () => {
14
+ api.getPersonByName('bob').then(person => {
15
+ expect(person).toHaveProperty('name', 'Bob');
16
+ });
17
+ });
18
+
19
+ it('promises a counted person', () => {
20
+ const promise = api.getPersonByName('bob').then(person => {
21
+ expect(person).toHaveProperty('name', 'Bob');
22
+ });
23
+
24
+ promise.then(() => {
25
+ expect(analytics.gottenPeopleCount).toBe(1);
19
26
  });
20
27
  });
28
+
29
+ it('promises multiple people', () => {
30
+ const firstPromise = api.getPersonByName('bob').then(person => {
31
+ expect(person).toHaveProperty('name', 'Bob');
32
+ });
33
+ const secondPromise = api.getPersonByName('alice').then(person => {
34
+ expect(person).toHaveProperty('name', 'Alice');
35
+ });
36
+
37
+ return Promise.any([firstPromise, secondPromise]);
38
+ });
21
39
  ```
22
40
 
23
41
  The following pattern is not warning:
24
42
 
25
43
  ```js
26
- it('promise test', () => {
27
- return somePromise.then(data => {
28
- expect(data).toEqual('foo');
44
+ it('promises a person', async () => {
45
+ await api.getPersonByName('bob').then(person => {
46
+ expect(person).toHaveProperty('name', 'Bob');
29
47
  });
30
48
  });
49
+
50
+ it('promises a counted person', () => {
51
+ let promise = api.getPersonByName('bob').then(person => {
52
+ expect(person).toHaveProperty('name', 'Bob');
53
+ });
54
+
55
+ promise = promise.then(() => {
56
+ expect(analytics.gottenPeopleCount).toBe(1);
57
+ });
58
+
59
+ return promise;
60
+ });
61
+
62
+ it('promises multiple people', () => {
63
+ const firstPromise = api.getPersonByName('bob').then(person => {
64
+ expect(person).toHaveProperty('name', 'Bob');
65
+ });
66
+ const secondPromise = api.getPersonByName('alice').then(person => {
67
+ expect(person).toHaveProperty('name', 'Alice');
68
+ });
69
+
70
+ return Promise.allSettled([firstPromise, secondPromise]);
71
+ });
31
72
  ```
@@ -100,8 +100,6 @@ var _default = (0, _utils.createRule)({
100
100
 
101
101
  return {
102
102
  CallExpression(node) {
103
- var _matcher$node$parent;
104
-
105
103
  if (!(0, _utils.isExpectCall)(node)) {
106
104
  return;
107
105
  }
@@ -110,7 +108,7 @@ var _default = (0, _utils.createRule)({
110
108
  matcher
111
109
  } = (0, _utils.parseExpectCall)(node);
112
110
 
113
- if ((matcher === null || matcher === void 0 ? void 0 : (_matcher$node$parent = matcher.node.parent) === null || _matcher$node$parent === void 0 ? void 0 : _matcher$node$parent.type) !== _experimentalUtils.AST_NODE_TYPES.CallExpression) {
111
+ if ((matcher === null || matcher === void 0 ? void 0 : matcher.node.parent.type) !== _experimentalUtils.AST_NODE_TYPES.CallExpression) {
114
112
  return;
115
113
  }
116
114
 
@@ -233,7 +233,7 @@ const reparseAsMatcher = parsedMember => ({ ...parsedMember,
233
233
  *
234
234
  * If this matcher isn't called, this will be `null`.
235
235
  */
236
- arguments: parsedMember.node.parent && parsedMember.node.parent.type === _experimentalUtils.AST_NODE_TYPES.CallExpression ? parsedMember.node.parent.arguments : null
236
+ arguments: parsedMember.node.parent.type === _experimentalUtils.AST_NODE_TYPES.CallExpression ? parsedMember.node.parent.arguments : null
237
237
  });
238
238
  /**
239
239
  * Re-parses the given `parsedMember` as a `ParsedExpectModifier`.
@@ -260,7 +260,7 @@ const reparseMemberAsModifier = parsedMember => {
260
260
  throw new Error(`modifier name must be either "${ModifierName.resolves}" or "${ModifierName.rejects}" (got "${parsedMember.name}")`);
261
261
  }
262
262
 
263
- const negation = parsedMember.node.parent && isExpectMember(parsedMember.node.parent, ModifierName.not) ? parsedMember.node.parent : undefined;
263
+ const negation = isExpectMember(parsedMember.node.parent, ModifierName.not) ? parsedMember.node.parent : undefined;
264
264
  return { ...parsedMember,
265
265
  negation
266
266
  };
@@ -297,7 +297,7 @@ const parseExpectCall = expect => {
297
297
  const modifier = expectation.modifier = reparseMemberAsModifier(parsedMember);
298
298
  const memberNode = modifier.negation || modifier.node;
299
299
 
300
- if (!memberNode.parent || !isExpectMember(memberNode.parent)) {
300
+ if (!isExpectMember(memberNode.parent)) {
301
301
  return expectation;
302
302
  }
303
303
 
@@ -9,96 +9,204 @@ var _experimentalUtils = require("@typescript-eslint/experimental-utils");
9
9
 
10
10
  var _utils = require("./utils");
11
11
 
12
- const isPromiseChainCall = node => node.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && node.callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(node.callee.property) && ['then', 'catch', 'finally'].includes((0, _utils.getAccessorValue)(node.callee.property));
13
-
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
- }
12
+ const isPromiseChainCall = node => {
13
+ if (node.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && node.callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(node.callee.property)) {
14
+ // promise methods should have at least 1 argument
15
+ if (node.arguments.length === 0) {
16
+ return false;
17
+ }
20
18
 
21
- if (line.type === _experimentalUtils.AST_NODE_TYPES.ReturnStatement && line.argument) {
22
- return isFullExpectCall(line.argument);
23
- }
19
+ switch ((0, _utils.getAccessorValue)(node.callee.property)) {
20
+ case 'then':
21
+ return node.arguments.length < 3;
24
22
 
25
- return false;
26
- });
23
+ case 'catch':
24
+ case 'finally':
25
+ return node.arguments.length < 2;
26
+ }
27
27
  }
28
28
 
29
- return isFullExpectCall(body);
29
+ return false;
30
30
  };
31
31
 
32
- const isFullExpectCall = expression => expression.type === _experimentalUtils.AST_NODE_TYPES.CallExpression && (0, _utils.isExpectMember)(expression.callee);
32
+ const findTopMostCallExpression = node => {
33
+ let topMostCallExpression = node;
34
+ let {
35
+ parent
36
+ } = node;
33
37
 
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
- });
38
+ while (parent) {
39
+ if (parent.type === _experimentalUtils.AST_NODE_TYPES.CallExpression) {
40
+ topMostCallExpression = parent;
41
+ parent = parent.parent;
42
+ continue;
43
+ }
44
+
45
+ if (parent.type !== _experimentalUtils.AST_NODE_TYPES.MemberExpression) {
46
+ break;
47
+ }
48
+
49
+ parent = parent.parent;
50
+ }
51
+
52
+ return topMostCallExpression;
46
53
  };
47
54
 
48
- const isPromiseReturnedLater = (node, testFunctionBody) => {
49
- let promiseName;
55
+ const isTestCaseCallWithCallbackArg = node => {
56
+ if (!(0, _utils.isTestCaseCall)(node)) {
57
+ return false;
58
+ }
59
+
60
+ const isJestEach = (0, _utils.getNodeName)(node).endsWith('.each');
50
61
 
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;
62
+ if (isJestEach && node.callee.type !== _experimentalUtils.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;
55
68
  }
56
69
 
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);
70
+ if (isJestEach || node.arguments.length >= 2) {
71
+ const [, callback] = node.arguments;
72
+ const callbackArgIndex = Number(isJestEach);
73
+ return callback && (0, _utils.isFunction)(callback) && callback.params.length === 1 + callbackArgIndex;
74
+ }
75
+
76
+ return false;
59
77
  };
60
78
 
61
- const findTestFunction = node => {
62
- while (node) {
63
- var _node$parent;
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 === _experimentalUtils.AST_NODE_TYPES.CallExpression && node.argument.arguments.length > 0) {
89
+ const nodeName = (0, _utils.getNodeName)(node.argument);
90
+
91
+ if (['Promise.all', 'Promise.allSettled'].includes(nodeName)) {
92
+ const [firstArg] = node.argument.arguments;
64
93
 
65
- if ((0, _utils.isFunction)(node) && ((_node$parent = node.parent) === null || _node$parent === void 0 ? void 0 : _node$parent.type) === _experimentalUtils.AST_NODE_TYPES.CallExpression && (0, _utils.isTestCaseCall)(node.parent)) {
66
- return node;
94
+ if (firstArg.type === _experimentalUtils.AST_NODE_TYPES.ArrayExpression && firstArg.elements.some(nod => (0, _utils.isIdentifier)(nod, name))) {
95
+ return true;
96
+ }
67
97
  }
68
98
 
69
- node = node.parent;
99
+ if (['Promise.resolve', 'Promise.reject'].includes(nodeName) && node.argument.arguments.length === 1) {
100
+ return (0, _utils.isIdentifier)(node.argument.arguments[0], name);
101
+ }
70
102
  }
71
103
 
72
- return null;
104
+ return node.argument.type === _experimentalUtils.AST_NODE_TYPES.Identifier && (0, _utils.isIdentifier)(node.argument, name);
73
105
  };
106
+ /**
107
+ * Attempts to determine if the runtime value represented by the given `identifier`
108
+ * is `await`ed or `return`ed within the given `body` of statements
109
+ */
74
110
 
75
- const isParentThenOrPromiseReturned = (node, testFunctionBody) => node.type === _experimentalUtils.AST_NODE_TYPES.ReturnStatement || isPromiseReturnedLater(node, testFunctionBody);
76
111
 
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);
82
- return true;
112
+ const isValueAwaitedOrReturned = (identifier, body) => {
113
+ const {
114
+ name
115
+ } = identifier;
116
+
117
+ for (const node of body) {
118
+ // skip all nodes that are before this identifier, because they'd probably
119
+ // be affecting a different runtime value (e.g. due to reassignment)
120
+ if (node.range[0] <= identifier.range[0]) {
121
+ continue;
122
+ }
123
+
124
+ if (node.type === _experimentalUtils.AST_NODE_TYPES.ReturnStatement) {
125
+ return isPromiseMethodThatUsesValue(node, identifier);
126
+ }
127
+
128
+ if (node.type === _experimentalUtils.AST_NODE_TYPES.ExpressionStatement) {
129
+ if (node.expression.type === _experimentalUtils.AST_NODE_TYPES.AwaitExpression) {
130
+ return isPromiseMethodThatUsesValue(node.expression, identifier);
131
+ } // (re)assignment changes the runtime value, so if we've not found an
132
+ // await or return already we act as if we've reached the end of the body
133
+
134
+
135
+ if (node.expression.type === _experimentalUtils.AST_NODE_TYPES.AssignmentExpression) {
136
+ var _getNodeName;
137
+
138
+ // unless we're assigning to the same identifier, in which case
139
+ // we might be chaining off the existing promise value
140
+ if ((0, _utils.isIdentifier)(node.expression.left, name) && (_getNodeName = (0, _utils.getNodeName)(node.expression.right)) !== null && _getNodeName !== void 0 && _getNodeName.startsWith(`${name}.`) && isPromiseChainCall(node.expression.right)) {
141
+ continue;
142
+ }
143
+
144
+ break;
83
145
  }
84
146
  }
85
147
 
86
- return false;
87
- });
148
+ if (node.type === _experimentalUtils.AST_NODE_TYPES.BlockStatement && isValueAwaitedOrReturned(identifier, node.body)) {
149
+ return true;
150
+ }
151
+ }
152
+
153
+ return false;
88
154
  };
89
155
 
90
- const isHavingAsyncCallBackParam = testFunction => testFunction.params[0] && testFunction.params[0].type === _experimentalUtils.AST_NODE_TYPES.Identifier;
156
+ const findFirstBlockBodyUp = node => {
157
+ let parent = node;
158
+
159
+ while (parent) {
160
+ if (parent.type === _experimentalUtils.AST_NODE_TYPES.BlockStatement) {
161
+ return parent.body;
162
+ }
163
+
164
+ parent = parent.parent;
165
+ }
166
+ /* istanbul ignore next */
167
+
168
+
169
+ throw new Error(`Could not find BlockStatement - please file a github issue at https://github.com/jest-community/eslint-plugin-jest`);
170
+ };
171
+
172
+ const isDirectlyWithinTestCaseCall = node => {
173
+ let parent = node;
174
+
175
+ while (parent) {
176
+ if ((0, _utils.isFunction)(parent)) {
177
+ var _parent;
178
+
179
+ parent = parent.parent;
180
+ return !!(((_parent = parent) === null || _parent === void 0 ? void 0 : _parent.type) === _experimentalUtils.AST_NODE_TYPES.CallExpression && (0, _utils.isTestCaseCall)(parent));
181
+ }
182
+
183
+ parent = parent.parent;
184
+ }
185
+
186
+ return false;
187
+ };
188
+
189
+ const isVariableAwaitedOrReturned = variable => {
190
+ const body = findFirstBlockBodyUp(variable); // it's pretty much impossible for us to track destructuring assignments,
191
+ // so we return true to bailout gracefully
192
+
193
+ if (!(0, _utils.isIdentifier)(variable.id)) {
194
+ return true;
195
+ }
196
+
197
+ return isValueAwaitedOrReturned(variable.id, body);
198
+ };
91
199
 
92
200
  var _default = (0, _utils.createRule)({
93
201
  name: __filename,
94
202
  meta: {
95
203
  docs: {
96
204
  category: 'Best Practices',
97
- description: 'Enforce having return statement when testing with promises',
205
+ description: 'Ensure promises that have expectations in their chain are valid',
98
206
  recommended: 'error'
99
207
  },
100
208
  messages: {
101
- returnPromise: 'Promise should be returned to test its fulfillment or rejection'
209
+ expectInFloatingPromise: "This promise should either be returned or awaited to ensure the expects in it's chain are called"
102
210
  },
103
211
  type: 'suggestion',
104
212
  schema: []
@@ -106,30 +214,106 @@ var _default = (0, _utils.createRule)({
106
214
  defaultOptions: [],
107
215
 
108
216
  create(context) {
217
+ let inTestCaseWithDoneCallback = false; // an array of booleans representing each promise chain we enter, with the
218
+ // boolean value representing if we think a given chain contains an expect
219
+ // in it's body.
220
+ //
221
+ // since we only care about the inner-most chain, we represent the state in
222
+ // reverse with the inner-most being the first item, as that makes it
223
+ // slightly less code to assign to by not needing to know the length
224
+
225
+ const chains = [];
109
226
  return {
110
227
  CallExpression(node) {
111
- if (!isPromiseChainCall(node) || node.parent && node.parent.type === _experimentalUtils.AST_NODE_TYPES.AwaitExpression) {
228
+ // there are too many ways that the done argument could be used with
229
+ // promises that contain expect that would make the promise safe for us
230
+ if (isTestCaseCallWithCallbackArg(node)) {
231
+ inTestCaseWithDoneCallback = true;
112
232
  return;
113
- }
233
+ } // if this call expression is a promise chain, add it to the stack with
234
+ // value of "false", as we assume there are no expect calls initially
114
235
 
115
- const testFunction = findTestFunction(node);
116
236
 
117
- if (testFunction && !isHavingAsyncCallBackParam(testFunction)) {
118
- const {
119
- body
120
- } = testFunction;
237
+ if (isPromiseChainCall(node)) {
238
+ chains.unshift(false);
239
+ return;
240
+ } // if we're within a promise chain, and this call expression looks like
241
+ // an expect call, mark the deepest chain as having an expect call
121
242
 
122
- if (body.type !== _experimentalUtils.AST_NODE_TYPES.BlockStatement) {
123
- return;
243
+
244
+ if (chains.length > 0 && (0, _utils.isExpectCall)(node)) {
245
+ chains[0] = true;
246
+ }
247
+ },
248
+
249
+ 'CallExpression:exit'(node) {
250
+ // there are too many ways that the "done" argument could be used to
251
+ // make promises containing expects safe in a test for us to be able to
252
+ // accurately check, so we just bail out completely if it's present
253
+ if (inTestCaseWithDoneCallback) {
254
+ if ((0, _utils.isTestCaseCall)(node)) {
255
+ inTestCaseWithDoneCallback = false;
124
256
  }
125
257
 
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
258
+ return;
259
+ }
260
+
261
+ if (!isPromiseChainCall(node)) {
262
+ return;
263
+ } // since we're exiting this call expression (which is a promise chain)
264
+ // we remove it from the stack of chains, since we're unwinding
265
+
266
+
267
+ const hasExpectCall = chains.shift(); // if the promise chain we're exiting doesn't contain an expect,
268
+ // then we don't need to check it for anything
269
+
270
+ if (!hasExpectCall) {
271
+ return;
272
+ }
273
+
274
+ const {
275
+ parent
276
+ } = findTopMostCallExpression(node); // if we don't have a parent (which is technically impossible at runtime)
277
+ // or our parent is not directly within the test case, we stop checking
278
+ // because we're most likely in the body of a function being defined
279
+ // within the test, which we can't track
130
280
 
131
- verifyExpectWithReturn(node.arguments.slice(0, 2), node.callee, context, testFunctionBody);
281
+ if (!parent || !isDirectlyWithinTestCaseCall(parent)) {
282
+ return;
132
283
  }
284
+
285
+ switch (parent.type) {
286
+ case _experimentalUtils.AST_NODE_TYPES.VariableDeclarator:
287
+ {
288
+ if (isVariableAwaitedOrReturned(parent)) {
289
+ return;
290
+ }
291
+
292
+ break;
293
+ }
294
+
295
+ case _experimentalUtils.AST_NODE_TYPES.AssignmentExpression:
296
+ {
297
+ if (parent.left.type === _experimentalUtils.AST_NODE_TYPES.Identifier && isValueAwaitedOrReturned(parent.left, findFirstBlockBodyUp(parent))) {
298
+ return;
299
+ }
300
+
301
+ break;
302
+ }
303
+
304
+ case _experimentalUtils.AST_NODE_TYPES.ExpressionStatement:
305
+ break;
306
+
307
+ case _experimentalUtils.AST_NODE_TYPES.ReturnStatement:
308
+ case _experimentalUtils.AST_NODE_TYPES.AwaitExpression:
309
+ default:
310
+ return;
311
+ }
312
+
313
+ context.report({
314
+ messageId: 'expectInFloatingPromise',
315
+ node: parent
316
+ });
133
317
  }
134
318
 
135
319
  };
@@ -26,19 +26,25 @@ const getPromiseCallExpressionNode = node => {
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 === _experimentalUtils.AST_NODE_TYPES.CallExpression && node.callee.type === _experimentalUtils.AST_NODE_TYPES.MemberExpression && (0, _utils.isSupportedAccessor)(node.callee.object) && (0, _utils.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 && [_experimentalUtils.AST_NODE_TYPES.CallExpression, _experimentalUtils.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 === _experimentalUtils.AST_NODE_TYPES.CallExpression && (0, _utils.isExpectMember)(grandParentNode.callee) && ['then', 'catch'].includes((0, _utils.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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-jest",
3
- "version": "24.5.2",
3
+ "version": "24.6.0",
4
4
  "description": "Eslint rules for Jest",
5
5
  "keywords": [
6
6
  "eslint",