Skip to content

Commit 3ee3874

Browse files
chrisblossomSimenB
authored andcommitted
fix(require-tothrow-message): require throw messages on async functions (#303)
1 parent b3a360d commit 3ee3874

File tree

3 files changed

+72
-4
lines changed

3 files changed

+72
-4
lines changed

docs/rules/require-tothrow-message.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ The following patterns are considered warnings:
1818
expect(() => a()).toThrow();
1919

2020
expect(() => a()).toThrowError();
21+
22+
await expect(a()).rejects.toThrow();
23+
24+
await expect(a()).rejects.toThrowError();
2125
```
2226

2327
The following patterns are not considered warnings:
@@ -26,4 +30,8 @@ The following patterns are not considered warnings:
2630
expect(() => a()).toThrow('a');
2731

2832
expect(() => a()).toThrowError('a');
33+
34+
await expect(a()).rejects.toThrow('a');
35+
36+
await expect(a()).rejects.toThrowError('a');
2937
```

src/rules/__tests__/require-tothrow-message.test.js

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import rule from '../require-tothrow-message';
33

44
const ruleTester = new RuleTester({
55
parserOptions: {
6-
ecmaVersion: 6,
6+
ecmaVersion: 8,
77
},
88
});
99

@@ -12,19 +12,51 @@ ruleTester.run('require-tothrow-message', rule, {
1212
// String
1313
"expect(() => { throw new Error('a'); }).toThrow('a');",
1414
"expect(() => { throw new Error('a'); }).toThrowError('a');",
15+
`test('string', async () => {
16+
const throwErrorAsync = async () => { throw new Error('a') };
17+
await expect(throwErrorAsync()).rejects.toThrow('a');
18+
await expect(throwErrorAsync()).rejects.toThrowError('a');
19+
})`,
1520

1621
// Template literal
1722
"const a = 'a'; expect(() => { throw new Error('a'); }).toThrow(`${a}`);",
23+
"const a = 'a'; expect(() => { throw new Error('a'); }).toThrowError(`${a}`);",
24+
`test('Template literal', async () => {
25+
const a = 'a';
26+
const throwErrorAsync = async () => { throw new Error('a') };
27+
await expect(throwErrorAsync()).rejects.toThrow(\`\${a}\`);
28+
await expect(throwErrorAsync()).rejects.toThrowError(\`\${a}\`);
29+
})`,
1830

1931
// Regex
2032
"expect(() => { throw new Error('a'); }).toThrow(/^a$/);",
33+
"expect(() => { throw new Error('a'); }).toThrowError(/^a$/);",
34+
`test('Regex', async () => {
35+
const throwErrorAsync = async () => { throw new Error('a') };
36+
await expect(throwErrorAsync()).rejects.toThrow(/^a$/);
37+
await expect(throwErrorAsync()).rejects.toThrowError(/^a$/);
38+
})`,
2139

2240
// Function
2341
"expect(() => { throw new Error('a'); })" +
2442
".toThrow((() => { return 'a'; })());",
43+
"expect(() => { throw new Error('a'); })" +
44+
".toThrowError((() => { return 'a'; })());",
45+
`test('Function', async () => {
46+
const throwErrorAsync = async () => { throw new Error('a') };
47+
const fn = () => { return 'a'; };
48+
await expect(throwErrorAsync()).rejects.toThrow(fn());
49+
await expect(throwErrorAsync()).rejects.toThrowError(fn());
50+
})`,
2551

2652
// Allow no message for `not`.
2753
"expect(() => { throw new Error('a'); }).not.toThrow();",
54+
"expect(() => { throw new Error('a'); }).not.toThrowError();",
55+
`test('Allow no message for "not"', async () => {
56+
const throwErrorAsync = async () => { throw new Error('a') };
57+
await expect(throwErrorAsync()).resolves.not.toThrow();
58+
await expect(throwErrorAsync()).resolves.not.toThrowError();
59+
})`,
2860
],
2961

3062
invalid: [
@@ -52,5 +84,28 @@ ruleTester.run('require-tothrow-message', rule, {
5284
},
5385
],
5486
},
87+
88+
// Empty rejects.toThrow / rejects.toThrowError
89+
{
90+
code: `test('empty rejects.toThrow', async () => {
91+
const throwErrorAsync = async () => { throw new Error('a') };
92+
await expect(throwErrorAsync()).rejects.toThrow();
93+
await expect(throwErrorAsync()).rejects.toThrowError();
94+
})`,
95+
errors: [
96+
{
97+
messageId: 'requireRethrow',
98+
data: { propertyName: 'toThrow' },
99+
column: 49,
100+
line: 3,
101+
},
102+
{
103+
messageId: 'requireRethrow',
104+
data: { propertyName: 'toThrowError' },
105+
column: 49,
106+
line: 4,
107+
},
108+
],
109+
},
55110
],
56111
});

src/rules/require-tothrow-message.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,22 @@ export default {
1717
return;
1818
}
1919

20-
const propertyName = method(node) && method(node).name;
20+
let targetNode = method(node);
21+
if (targetNode.name === 'rejects') {
22+
targetNode = method(node.parent);
23+
}
24+
25+
const propertyName = method(targetNode) && method(targetNode).name;
2126

2227
// Look for `toThrow` calls with no arguments.
2328
if (
2429
['toThrow', 'toThrowError'].includes(propertyName) &&
25-
!argument(node)
30+
!argument(targetNode)
2631
) {
2732
context.report({
2833
messageId: 'requireRethrow',
2934
data: { propertyName },
30-
node: method(node),
35+
node: targetNode,
3136
});
3237
}
3338
},

0 commit comments

Comments
 (0)