Skip to content

Commit a443d7a

Browse files
jfmengelssindresorhus
authored andcommitted
Add no-async-fn-without-await rule (fixes #132) (#140)
1 parent 7cfdf34 commit a443d7a

File tree

6 files changed

+132
-0
lines changed

6 files changed

+132
-0
lines changed
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Ensure that async tests use `await`
2+
3+
Translations: [Français](https://github.com/avajs/ava-docs/blob/master/fr_FR/related/eslint-plugin-ava/docs/rules/no-async-fn-without-await.md)
4+
5+
AVA comes with built-in support for [async functions](http://www.2ality.com/2016/02/async-functions.html) (async/await). This allows you to write shorter and clearer tests.
6+
7+
Declaring an async test without using the `await` keyword means that either a Promise is not awaited on as intended, or that the function could have been declared as a regular function, which is confusing and slower.
8+
9+
This rule will report an error when it finds an async test which does not use the `await` keyword.
10+
11+
12+
## Fail
13+
14+
```js
15+
import test from 'ava';
16+
17+
test(async t => {
18+
return foo().then(res => {
19+
t.is(res, 1);
20+
});
21+
});
22+
```
23+
24+
25+
## Pass
26+
27+
```js
28+
import test from 'ava';
29+
30+
test(async t => {
31+
t.is(await foo(), 1);
32+
});
33+
```

index.js

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = {
1616
'ava/assertion-arguments': 'error',
1717
'ava/assertion-message': ['off', 'always'],
1818
'ava/max-asserts': ['off', 5],
19+
'ava/no-async-fn-without-await': 'error',
1920
'ava/no-cb-test': 'off',
2021
'ava/no-duplicate-modifiers': 'error',
2122
'ava/no-identical-title': 'error',

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
},
7474
"devDependencies": {
7575
"ava": "*",
76+
"babel-eslint": "^6.1.2",
7677
"coveralls": "^2.11.9",
7778
"eslint": "^3.0.1",
7879
"eslint-ava-rule-tester": "^2.0.0",

readme.md

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Configure it in `package.json`.
3434
"ava/assertion-arguments": "error",
3535
"ava/assertion-message": ["off", "always"],
3636
"ava/max-asserts": ["off", 5],
37+
"ava/no-async-fn-without-await": "error",
3738
"ava/no-cb-test": "off",
3839
"ava/no-duplicate-modifiers": "error",
3940
"ava/no-identical-title": "error",
@@ -68,6 +69,7 @@ The rules will only activate in test files.
6869
- [assertion-arguments](docs/rules/assertion-arguments.md) - Enforce passing correct arguments to assertions.
6970
- [assertion-message](docs/rules/assertion-message.md) - Enforce or disallow assertion messages.
7071
- [max-asserts](docs/rules/max-asserts.md) - Limit the number of assertions in a test.
72+
- [no-async-fn-without-await](docs/rules/no-async-fn-without-await.md) - Ensure that async tests use `await`.
7173
- [no-cb-test](docs/rules/no-cb-test.md) - Ensure no `test.cb()` is used.
7274
- [no-duplicate-modifiers](docs/rules/no-duplicate-modifiers.md) - Ensure tests do not have duplicate modifiers.
7375
- [no-identical-title](docs/rules/no-identical-title.md) - Ensure no tests have the same title.

rules/no-async-fn-without-await.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use strict';
2+
const visitIf = require('enhance-visitors').visitIf;
3+
const createAvaRule = require('../create-ava-rule');
4+
5+
const create = context => {
6+
const ava = createAvaRule();
7+
let testIsAsync = false;
8+
let testUsed = false;
9+
10+
return ava.merge({
11+
'CallExpression': visitIf([
12+
ava.isInTestFile,
13+
ava.isTestNode
14+
])(node => {
15+
const implementationFn = node.arguments[0];
16+
testIsAsync = implementationFn && implementationFn.async;
17+
}),
18+
'YieldExpression': () => {
19+
if (testIsAsync) {
20+
testUsed = true;
21+
}
22+
},
23+
'CallExpression:exit': visitIf([
24+
ava.isInTestFile,
25+
ava.isTestNode
26+
])(node => {
27+
if (testIsAsync && !testUsed) {
28+
context.report({
29+
node,
30+
message: 'Function was declared as `async` but doesn\'t use `await`'
31+
});
32+
}
33+
testIsAsync = false;
34+
testUsed = false;
35+
})
36+
});
37+
};
38+
39+
module.exports = {
40+
create,
41+
meta: {}
42+
};

test/no-async-fn-without-await.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import test from 'ava';
2+
import avaRuleTester from 'eslint-ava-rule-tester';
3+
import rule from '../rules/no-async-fn-without-await';
4+
5+
const ruleTester = avaRuleTester(test, {
6+
parser: 'babel-eslint',
7+
env: {
8+
es6: true
9+
}
10+
});
11+
12+
const error = {
13+
ruleId: 'no-async-fn-without-await',
14+
message: 'Function was declared as `async` but doesn\'t use `await`'
15+
};
16+
const header = `const test = require('ava');\n`;
17+
18+
ruleTester.run('no-async-fn-without-await', rule, {
19+
valid: [
20+
`${header} test(fn);`,
21+
`${header} test(t => {});`,
22+
`${header} test(function(t) {});`,
23+
`${header} test(async t => { await foo(); });`,
24+
`${header} test(async t => { t.is(await foo(), 1); });`,
25+
`${header} test(async function(t) { await foo(); });`,
26+
`${header} test(async t => { if (bar) { await foo(); } });`,
27+
`${header} test(async t => { if (bar) {} else { await foo(); } });`,
28+
// shouldn't be triggered since it's not a test file
29+
'test(async t => {});'
30+
],
31+
invalid: [
32+
{
33+
code: `${header} test(async t => {});`,
34+
errors: [error]
35+
},
36+
{
37+
code: `${header} test(async function(t) {});`,
38+
errors: [error]
39+
},
40+
{
41+
code: `${header} test(async t => {}); test(async t => {});`,
42+
errors: [error, error]
43+
},
44+
{
45+
code: `${header} test(async t => {}); test(async t => { await foo(); });`,
46+
errors: [error]
47+
},
48+
{
49+
code: `${header} test(async t => { await foo(); }); test(async t => {});`,
50+
errors: [error]
51+
}
52+
]
53+
});

0 commit comments

Comments
 (0)