Skip to content

Commit e283efc

Browse files
committed
feat(no-useless-await): Remove useless awaits from expect methods
Fixes #306
1 parent ef8cfa5 commit e283efc

File tree

3 files changed

+92
-23
lines changed

3 files changed

+92
-23
lines changed

docs/rules/no-useless-await.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Examples of **incorrect** code for this rule:
1010
```javascript
1111
await page.locator('.my-element')
1212
await page.getByRole('.my-element')
13+
14+
await expect(1).toBe(1)
15+
await expect(true).toBeTruthy()
1316
```
1417

1518
Examples of **correct** code for this rule:
@@ -20,4 +23,10 @@ page.getByRole('.my-element')
2023

2124
await page.$('.my-element')
2225
await page.goto('.my-element')
26+
27+
expect(1).toBe(1)
28+
expect(true).toBeTruthy()
29+
30+
await expect(page.locator('.foo')).toBeVisible()
31+
await expect(page.locator('.foo')).toHaveText('bar')
2332
```

src/rules/no-useless-await.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,23 @@ runRuleTester('no-useless-await', rule, {
181181
errors: [{ column: 1, endColumn: 6, line: 1, messageId }],
182182
output: 'frame.parentFrame()',
183183
},
184+
185+
// Expect methods
186+
{
187+
code: 'await expect(true).toBe(true)',
188+
errors: [{ column: 1, endColumn: 6, line: 1, messageId }],
189+
output: 'expect(true).toBe(true)',
190+
},
191+
{
192+
code: 'await expect(true).toBeTruthy()',
193+
errors: [{ column: 1, endColumn: 6, line: 1, messageId }],
194+
output: 'expect(true).toBeTruthy()',
195+
},
196+
{
197+
code: 'await expect(true).toEqual(true)',
198+
errors: [{ column: 1, endColumn: 6, line: 1, messageId }],
199+
output: 'expect(true).toEqual(true)',
200+
},
184201
],
185202
valid: [
186203
'await foo()',
@@ -195,5 +212,12 @@ runRuleTester('no-useless-await', rule, {
195212
'await page.waitForLoadState({ waitUntil: "load" })',
196213
'await page.waitForURL(url, { waitUntil: "load" })',
197214
'await page.locator(".hello-world").waitFor()',
215+
216+
'expect(true).toBe(true)',
217+
'expect(true).toBeTruthy()',
218+
'expect(true).toEqual(true)',
219+
220+
'await expect(page.locator(".my-element")).toBeVisible()',
221+
'await expect(page.locator(".my-element")).toHaveText("test")',
198222
],
199223
})

src/rules/no-useless-await.ts

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import { Rule } from 'eslint'
12
import ESTree from 'estree'
23
import { getStringValue, isPageMethod } from '../utils/ast'
34
import { createRule } from '../utils/createRule'
5+
import { parseFnCall } from '../utils/parseFnCall'
46

57
const locatorMethods = new Set([
68
'and',
@@ -38,6 +40,32 @@ const pageMethods = new Set([
3840
'workers',
3941
])
4042

43+
const expectMatchers = new Set([
44+
'toBe',
45+
'toBeCloseTo',
46+
'toBeDefined',
47+
'toBeFalsy',
48+
'toBeGreaterThan',
49+
'toBeGreaterThanOrEqual',
50+
'toBeInstanceOf',
51+
'toBeLessThan',
52+
'toBeLessThanOrEqual',
53+
'toBeNaN',
54+
'toBeNull',
55+
'toBeTruthy',
56+
'toBeUndefined',
57+
'toContain',
58+
'toContainEqual',
59+
'toEqual',
60+
'toHaveLength',
61+
'toHaveProperty',
62+
'toMatch',
63+
'toMatchObject',
64+
'toStrictEqual',
65+
'toThrow',
66+
'toThrowError',
67+
])
68+
4169
function isSupportedMethod(node: ESTree.CallExpression) {
4270
if (node.callee.type !== 'MemberExpression') return false
4371

@@ -50,32 +78,40 @@ function isSupportedMethod(node: ESTree.CallExpression) {
5078

5179
export default createRule({
5280
create(context) {
53-
return {
54-
AwaitExpression(node) {
55-
// Must be a call expression
56-
if (node.argument.type !== 'CallExpression') return
57-
58-
// Must be a foo.bar() call, bare calls are ignored
59-
const { callee } = node.argument
60-
if (callee.type !== 'MemberExpression') return
81+
function fix(node: ESTree.Node) {
82+
const start = node.loc!.start
83+
const range = node.range!
6184

62-
// Must be a method we care about
63-
if (!isSupportedMethod(node.argument)) return
85+
context.report({
86+
fix: (fixer) => fixer.removeRange([range[0], range[0] + 6]),
87+
loc: {
88+
end: {
89+
column: start.column + 5,
90+
line: start.line,
91+
},
92+
start,
93+
},
94+
messageId: 'noUselessAwait',
95+
})
96+
}
6497

65-
const start = node.loc!.start
66-
const range = node.range!
98+
return {
99+
'AwaitExpression > CallExpression'(
100+
node: ESTree.CallExpression & Rule.NodeParentExtension,
101+
) {
102+
// await page.locator('.foo')
103+
if (
104+
node.callee.type === 'MemberExpression' &&
105+
isSupportedMethod(node)
106+
) {
107+
return fix(node.parent)
108+
}
67109

68-
context.report({
69-
fix: (fixer) => fixer.removeRange([range[0], range[0] + 6]),
70-
loc: {
71-
end: {
72-
column: start.column + 5,
73-
line: start.line,
74-
},
75-
start,
76-
},
77-
messageId: 'noUselessAwait',
78-
})
110+
// await expect(true).toBe(true)
111+
const call = parseFnCall(context, node)
112+
if (call?.type === 'expect' && expectMatchers.has(call.matcherName)) {
113+
return fix(node.parent)
114+
}
79115
},
80116
}
81117
},

0 commit comments

Comments
 (0)