Skip to content

Commit d0cea37

Browse files
mcampaMario Campa
and
Mario Campa
authored
feat(prefer-expect-assertions): add onlyFunctionsWithAsyncKeyword option (#677)
Co-authored-by: Mario Campa <[email protected]>
1 parent 387d970 commit d0cea37

File tree

3 files changed

+101
-5
lines changed

3 files changed

+101
-5
lines changed

docs/rules/prefer-expect-assertions.md

+42
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,45 @@ test('my test', () => {
5555
expect(someThing()).toEqual('foo');
5656
});
5757
```
58+
59+
## Options
60+
61+
#### `onlyFunctionsWithAsyncKeyword`
62+
63+
When `true`, this rule will only warn for tests that use the `async` keyword.
64+
65+
```json
66+
{
67+
"rules": {
68+
"jest/prefer-expect-assertions": [
69+
"warn",
70+
{ "onlyFunctionsWithAsyncKeyword": true }
71+
]
72+
}
73+
}
74+
```
75+
76+
When `onlyFunctionsWithAsyncKeyword` option is set to `true`, the following
77+
pattern would be a warning:
78+
79+
```js
80+
test('my test', async () => {
81+
const result = await someAsyncFunc();
82+
expect(result).toBe('foo');
83+
});
84+
```
85+
86+
While the following patterns would not be considered warnings:
87+
88+
```js
89+
test('my test', () => {
90+
const result = someFunction();
91+
expect(result).toBe('foo');
92+
});
93+
94+
test('my test', async () => {
95+
expect.assertions(1);
96+
const result = await someAsyncFunc();
97+
expect(result).toBe('foo');
98+
});
99+
```

src/rules/__tests__/prefer-expect-assertions.test.ts

+38-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import rule from '../prefer-expect-assertions';
66
const ruleTester = new TSESLint.RuleTester({
77
parser: resolveFrom(require.resolve('eslint'), 'espree'),
88
parserOptions: {
9-
ecmaVersion: 2015,
9+
ecmaVersion: 2017,
1010
},
1111
});
1212

@@ -205,6 +205,21 @@ ruleTester.run('prefer-expect-assertions', rule, {
205205
},
206206
],
207207
},
208+
{
209+
code: dedent`
210+
it("it1", async function() {
211+
expect(someValue).toBe(true);
212+
})
213+
`,
214+
options: [{ onlyFunctionsWithAsyncKeyword: true }],
215+
errors: [
216+
{
217+
messageId: 'haveExpectAssertions',
218+
column: 1,
219+
line: 1,
220+
},
221+
],
222+
},
208223
],
209224

210225
valid: [
@@ -223,5 +238,27 @@ ruleTester.run('prefer-expect-assertions', rule, {
223238
'test("it1")',
224239
'itHappensToStartWithIt("foo", function() {})',
225240
'testSomething("bar", function() {})',
241+
'it(async () => {expect.assertions(0);})',
242+
{
243+
code: dedent`
244+
it("it1", async () => {
245+
expect.assertions(1);
246+
expect(someValue).toBe(true)
247+
})
248+
`,
249+
options: [{ onlyFunctionsWithAsyncKeyword: true }],
250+
},
251+
{
252+
code: dedent`
253+
it("it1", function() {
254+
expect(someValue).toBe(true)
255+
})
256+
`,
257+
options: [{ onlyFunctionsWithAsyncKeyword: true }],
258+
},
259+
{
260+
code: 'it("it1", () => {})',
261+
options: [{ onlyFunctionsWithAsyncKeyword: true }],
262+
},
226263
],
227264
});

src/rules/prefer-expect-assertions.ts

+21-4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ interface PreferExpectAssertionsCallExpression extends TSESTree.CallExpression {
4646
TSESTree.ArrowFunctionExpression & { body: TSESTree.BlockStatement },
4747
];
4848
}
49+
interface RuleOptions {
50+
onlyFunctionsWithAsyncKeyword?: boolean;
51+
}
4952

5053
type MessageIds =
5154
| 'hasAssertionsTakesNoArguments'
@@ -61,7 +64,7 @@ const suggestions: Array<[MessageIds, string]> = [
6164
['suggestAddingAssertions', 'expect.assertions();'],
6265
];
6366

64-
export default createRule<[], MessageIds>({
67+
export default createRule<[RuleOptions], MessageIds>({
6568
name: __filename,
6669
meta: {
6770
docs: {
@@ -85,14 +88,28 @@ export default createRule<[], MessageIds>({
8588
suggestRemovingExtraArguments: 'Remove extra arguments',
8689
},
8790
type: 'suggestion',
88-
schema: [],
91+
schema: [
92+
{
93+
type: 'object',
94+
properties: {
95+
onlyFunctionsWithAsyncKeyword: {
96+
type: 'boolean',
97+
},
98+
},
99+
additionalProperties: false,
100+
},
101+
],
89102
},
90-
defaultOptions: [],
91-
create(context) {
103+
defaultOptions: [{ onlyFunctionsWithAsyncKeyword: false }],
104+
create(context, [options]) {
92105
return {
93106
'CallExpression[callee.name=/^(it|test)$/][arguments.1.body.body]'(
94107
node: PreferExpectAssertionsCallExpression,
95108
) {
109+
if (options.onlyFunctionsWithAsyncKeyword && !node.arguments[1].async) {
110+
return;
111+
}
112+
96113
const testFuncBody = node.arguments[1].body.body;
97114

98115
if (!isFirstLineExprStmt(testFuncBody)) {

0 commit comments

Comments
 (0)