Skip to content

Commit

Permalink
fix(valid-expect): work with .then (#352)
Browse files Browse the repository at this point in the history
Fixes #347
  • Loading branch information
yatki authored and SimenB committed Jul 25, 2019
1 parent f9b6668 commit 0bbfb3a
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
64 changes: 64 additions & 0 deletions src/rules/__tests__/valid-expect.test.js
Expand Up @@ -42,6 +42,35 @@ ruleTester.run('valid-expect', rule, {
'test("valid-expect", async () => { await Promise.race([expect(Promise.reject(2)).not.rejects.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });',
'test("valid-expect", async () => { await Promise.allSettled([expect(Promise.reject(2)).not.rejects.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });',
'test("valid-expect", async () => { await Promise.any([expect(Promise.reject(2)).not.rejects.toBeDefined(), expect(Promise.reject(2)).rejects.not.toBeDefined()]); });',
'test("valid-expect", async () => { return expect(Promise.reject(2)).not.resolves.toBeDefined().then(() => console.log("valid-case")); });',
'test("valid-expect", async () => { return expect(Promise.reject(2)).not.resolves.toBeDefined().then(() => console.log("valid-case")).then(() => console.log("another valid case")); });',
'test("valid-expect", async () => { return expect(Promise.reject(2)).not.resolves.toBeDefined().catch(() => console.log("valid-case")); });',
'test("valid-expect", async () => { return expect(Promise.reject(2)).not.resolves.toBeDefined().then(() => console.log("valid-case")).catch(() => console.log("another valid case")); });',
'test("valid-expect", async () => { return expect(Promise.reject(2)).not.resolves.toBeDefined().then(() => { expect(someMock).toHaveBeenCalledTimes(1); }); });',
'test("valid-expect", async () => { await expect(Promise.reject(2)).not.resolves.toBeDefined().then(() => console.log("valid-case")); });',
'test("valid-expect", async () => { await expect(Promise.reject(2)).not.resolves.toBeDefined().then(() => console.log("valid-case")).then(() => console.log("another valid case")); });',
'test("valid-expect", async () => { await expect(Promise.reject(2)).not.resolves.toBeDefined().catch(() => console.log("valid-case")); });',
'test("valid-expect", async () => { await expect(Promise.reject(2)).not.resolves.toBeDefined().then(() => console.log("valid-case")).catch(() => console.log("another valid case")); });',
'test("valid-expect", async () => { await expect(Promise.reject(2)).not.resolves.toBeDefined().then(() => { expect(someMock).toHaveBeenCalledTimes(1); }); });',
{
code: `test("valid-expect", () => {
return expect(functionReturningAPromise()).resolves.toEqual(1).then(() => {
return expect(Promise.resolve(2)).resolves.toBe(1);
});
});`,
},
{
code: `test("valid-expect", () => {
return expect(functionReturningAPromise()).resolves.toEqual(1).then(async () => {
await expect(Promise.resolve(2)).resolves.toBe(1);
});
});`,
},
{
code: `test("valid-expect", () => {
return expect(functionReturningAPromise()).resolves.toEqual(1).then(() => expect(Promise.resolve(2)).resolves.toBe(1));
});`,
},
],

invalid: [
Expand Down Expand Up @@ -484,5 +513,40 @@ ruleTester.run('valid-expect', rule, {
},
],
},
{
code: `test("valid-expect", () => {
return expect(functionReturningAPromise()).resolves.toEqual(1).then(() => {
expect(Promise.resolve(2)).resolves.toBe(1);
});
});`,
errors: [
{
line: 3,
column: 11,
endLine: 3,
endColumn: 54,
messageId: 'asyncMustBeAwaited',
data: { orReturned: ' or returned' },
},
],
},
{
code: `test("valid-expect", () => {
return expect(functionReturningAPromise()).resolves.toEqual(1).then(async () => {
await expect(Promise.resolve(2)).resolves.toBe(1);
expect(Promise.resolve(4)).resolves.toBe(4);
});
});`,
errors: [
{
line: 4,
column: 11,
endLine: 4,
endColumn: 54,
messageId: 'asyncMustBeAwaited',
data: { orReturned: ' or returned' },
},
],
},
],
});
20 changes: 20 additions & 0 deletions src/rules/valid-expect.js
Expand Up @@ -63,6 +63,24 @@ const getPromiseCallExpressionNode = node => {
return null;
};

const getParentIfThenified = node => {
const grandParentNode = node.parent && node.parent.parent;

if (
grandParentNode &&
grandParentNode.type === 'CallExpression' &&
grandParentNode.callee &&
grandParentNode.callee.type === 'MemberExpression' &&
['then', 'catch'].includes(grandParentNode.callee.property.name) &&
grandParentNode.parent
) {
// Just in case `then`s are chained look one above.
return getParentIfThenified(grandParentNode);
}

return node;
};

const checkIfValidReturn = (parentCallExpressionNode, allowReturn) => {
const validParentNodeTypes = ['ArrowFunctionExpression', 'AwaitExpression'];
if (allowReturn) {
Expand Down Expand Up @@ -223,6 +241,8 @@ export default {
const orReturned = allowReturn ? ' or returned' : '';
let messageId = 'asyncMustBeAwaited';

parentNode = getParentIfThenified(parentNode);

// Promise.x([expect()]) || Promise.x(expect())
if (promiseArgumentTypes.includes(parentNode.parent.type)) {
const promiseNode = getPromiseCallExpressionNode(
Expand Down

0 comments on commit 0bbfb3a

Please sign in to comment.