Skip to content

Commit 02a5062

Browse files
authored
feat: add custom missing await rule (#4)
1 parent b591f22 commit 02a5062

File tree

9 files changed

+5718
-44
lines changed

9 files changed

+5718
-44
lines changed

.github/workflows/test.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: Test
2+
on:
3+
push:
4+
branches: [master]
5+
pull_request:
6+
branches: [master]
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
strategy:
11+
matrix:
12+
node-version: [12.x, 14.x, 16.x]
13+
steps:
14+
- uses: actions/checkout@v2
15+
- name: Use Node.js ${{ matrix.node-version }}
16+
uses: actions/setup-node@v1
17+
with:
18+
node-version: ${{ matrix.node-version }}
19+
- run: npm ci
20+
- run: npm test

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/

README.md

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,61 @@
1-
# ESLint Jest Playwright globals
1+
# ESLint Jest Playwright
22

3-
> ESLint globals for your [Jest](https://jestjs.io/) [Playwright](https://github.com/microsoft/playwright) ([jest-playwright](https://github.com/mmarkelov/jest-playwright/)) installation.
3+
> ESLint plugin for your [Jest](https://jestjs.io/) [Playwright](https://github.com/microsoft/playwright) ([jest-playwright](https://github.com/mmarkelov/jest-playwright/)) installation.
4+
5+
## Installation
6+
7+
Yarn
8+
9+
```txt
10+
yarn add -D eslint-plugin-jest-playwright
11+
```
12+
13+
NPM
14+
15+
```txt
16+
npm install -D eslint-plugin-jest-playwright
17+
```
418

519
## Usage
620

721
Add `plugin:jest-playwright/recommended` to your extends ESLint configuration. For example:
822

923
```json
1024
{
11-
"extends": [
12-
"plugin:jest-playwright/recommended"
13-
]
25+
"extends": ["plugin:jest-playwright/recommended"],
26+
"plugins": ["jest-playwright"]
1427
}
1528
```
1629

17-
## Installation
30+
## Rules
1831

19-
Yarn
32+
### `missing-playwright-expect` 🔧
2033

21-
```txt
22-
yarn add -D eslint-plugin-jest-playwright
34+
Enforce Jest Playwright expect statements to be awaited.
35+
36+
#### Example
37+
38+
Example of **incorrect** code for this rule:
39+
40+
```js
41+
expect(page).toHaveText("text");
2342
```
2443

25-
NPM
44+
Example of **correct** code for this rule:
2645

27-
```txt
28-
npm install -D eslint-plugin-jest-playwright
46+
```js
47+
await expect(page).toHaveText("text");
48+
```
49+
50+
#### Options
51+
52+
The rule accepts a non-required option which can be used to specify custom matchers which this rule should also warn about. This is useful when creating your own async matchers.
53+
54+
```json
55+
{
56+
"jest-playwright/missing-playwright-await": [
57+
"error",
58+
{ "customMatchers": ["toHaveAttribute"] }
59+
]
60+
}
2961
```

index.js

Lines changed: 0 additions & 30 deletions
This file was deleted.

lib/index.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const missingPlaywrightAwait = require("./rules/missing-playwright-await");
2+
3+
module.exports = {
4+
configs: {
5+
recommended: {
6+
env: {
7+
"shared-node-browser": true,
8+
jest: true,
9+
},
10+
rules: {
11+
"jest-playwright/missing-playwright-await": "error",
12+
"jest/no-standalone-expect": [
13+
"error",
14+
{
15+
additionalTestBlockFunctions: [
16+
"test.jestPlaywrightDebug",
17+
"it.jestPlaywrightDebug",
18+
"test.jestPlaywrightSkip",
19+
"it.jestPlaywrightSkip",
20+
"test.jestPlaywrightConfig",
21+
"it.jestPlaywrightConfig",
22+
],
23+
},
24+
],
25+
},
26+
globals: {
27+
browserName: true,
28+
deviceName: true,
29+
browser: true,
30+
context: true,
31+
page: true,
32+
jestPlaywright: true,
33+
},
34+
},
35+
},
36+
rules: {
37+
"missing-playwright-await": missingPlaywrightAwait,
38+
},
39+
};

lib/rules/missing-playwright-await.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
function getPromiseMemberExpressionNode(node, matchers) {
2+
if (node.property.type === "Identifier" && matchers.has(node.property.name)) {
3+
return node;
4+
}
5+
}
6+
7+
function isValidExpect(node) {
8+
const parentType =
9+
node.parent && node.parent.parent && node.parent.parent.type;
10+
11+
// Don't report on nodes which are already awaited or returned
12+
return parentType === "AwaitExpression" || parentType === "ReturnStatement";
13+
}
14+
15+
module.exports = {
16+
create(context) {
17+
const options = context.options[0] || {};
18+
const matchers = new Set([
19+
"toHaveSelector",
20+
"toHaveSelectorCount",
21+
"toHaveText",
22+
"toEqualText",
23+
"toEqualValue",
24+
"toEqualUrl",
25+
"toHaveFocus",
26+
// Add any custom matchers to the set
27+
...(options.customMatchers || []),
28+
]);
29+
30+
return {
31+
MemberExpression(statement) {
32+
const node = getPromiseMemberExpressionNode(statement, matchers);
33+
if (!node || isValidExpect(node)) return;
34+
35+
context.report({
36+
fix(fixer) {
37+
return fixer.insertTextBefore(node, "await ");
38+
},
39+
messageId: "missingAwait",
40+
node,
41+
});
42+
},
43+
};
44+
},
45+
meta: {
46+
docs: {
47+
category: "Possible Errors",
48+
description: "Enforce Jest Playwright expect statements to be awaited.",
49+
recommended: true,
50+
},
51+
fixable: "code",
52+
messages: {
53+
missingAwait: "Playwright expectations must be awaited or returned.",
54+
},
55+
schema: [
56+
{
57+
additionalProperties: false,
58+
properties: {
59+
customMatchers: {
60+
items: { type: "string" },
61+
type: "array",
62+
},
63+
},
64+
type: "object",
65+
},
66+
],
67+
type: "problem",
68+
},
69+
};

0 commit comments

Comments
 (0)