Skip to content

Commit 97d2e49

Browse files
authored
Merge branch 'main' into no-slow-tests
2 parents aa663aa + 35e37a1 commit 97d2e49

File tree

124 files changed

+3436
-1991
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+3436
-1991
lines changed

.eslintignore

-2
This file was deleted.

.eslintrc

-11
This file was deleted.

.github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
node-version: [16.x, 18.x, 20.x]
12+
node-version: [18.x, 20.x, 22.x]
1313
steps:
1414
- name: Setup Node.js ${{ matrix.node-version }}
1515
uses: mskelton/setup-pnpm@v2

README.md

+9-51
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,11 @@ pnpm add -D eslint-plugin-playwright
2828

2929
## Usage
3030

31-
This plugin bundles two configurations to work with both `@playwright/test` or
32-
`jest-playwright`. The recommended setup is to use the `files` field to target
33-
only Playwright test files. In the examples below, this is done by targeting
34-
files in the `tests` directory and only applying the Playwright rules to those
35-
files. In your project, you may need to change the `files` field to match your
36-
Playwright test file patterns.
37-
38-
### With [Playwright test runner](https://playwright.dev/docs/writing-tests)
31+
The recommended setup is to use the `files` field to target only Playwright test
32+
files. In the examples below, this is done by targeting files in the `tests`
33+
directory and only applying the Playwright rules to those files. In your
34+
project, you may need to change the `files` field to match your Playwright test
35+
file patterns.
3936

4037
[Flat config](https://eslint.org/docs/latest/use/configure/configuration-files-new)
4138
(**eslint.config.js**)
@@ -47,10 +44,8 @@ export default [
4744
{
4845
...playwright.configs['flat/recommended'],
4946
files: ['tests/**'],
50-
},
51-
{
52-
files: ['tests/**'],
5347
rules: {
48+
...playwright.configs['flat/recommended'].rules,
5449
// Customize Playwright rules
5550
// ...
5651
},
@@ -72,45 +67,6 @@ export default [
7267
}
7368
```
7469

75-
### With [Jest Playwright](https://github.com/playwright-community/jest-playwright)
76-
77-
[Flat config](https://eslint.org/docs/latest/use/configure/configuration-files-new)
78-
(**eslint.config.js**)
79-
80-
```javascript
81-
import playwright from 'eslint-plugin-playwright'
82-
import jest from 'eslint-plugin-jest'
83-
84-
export default [
85-
{
86-
...playwright.configs['flat/jest-playwright'],
87-
files: ['tests/**'],
88-
},
89-
{
90-
files: ['tests/**'],
91-
plugins: { jest },
92-
rules: {
93-
// Customize Playwright rules
94-
// ...
95-
},
96-
},
97-
]
98-
```
99-
100-
[Legacy config](https://eslint.org/docs/latest/use/configure/configuration-files)
101-
(**.eslintrc**)
102-
103-
```json
104-
{
105-
"overrides": [
106-
{
107-
"files": "tests/**",
108-
"extends": "plugin:playwright/jest-playwright"
109-
}
110-
]
111-
}
112-
```
113-
11470
## Settings
11571

11672
### Aliased Playwright Globals
@@ -163,7 +119,7 @@ CLI option\
163119
| Rule | Description || 🔧 | 💡 |
164120
| --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | :-: | :-: | :-: |
165121
| [expect-expect](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/expect-expect.md) | Enforce assertion to be made in a test body || | |
166-
| [max-expects](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/max-expects.md) | Enforces a maximum number assertion calls in a test body | | | |
122+
| [max-expects](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/max-expects.md) | Enforces a maximum number assertion calls in a test body | | | |
167123
| [max-nested-describe](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/max-nested-describe.md) | Enforces a maximum depth to nested describe calls || | |
168124
| [missing-playwright-await](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/missing-playwright-await.md) | Enforce Playwright APIs to be awaited || 🔧 | |
169125
| [no-commented-out-tests](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-commented-out-tests.md) | Disallow commented out tests | | | |
@@ -195,6 +151,8 @@ CLI option\
195151
| [prefer-hooks-in-order](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-hooks-in-order.md) | Prefer having hooks in a consistent order | | | |
196152
| [prefer-hooks-on-top](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-hooks-on-top.md) | Suggest having hooks before any test cases | | | |
197153
| [prefer-lowercase-title](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-lowercase-title.md) | Enforce lowercase test names | | 🔧 | |
154+
| [prefer-native-locators](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-native-locators.md) | Suggest built-in locators over `page.locator()` | | 🔧 | |
155+
| [prefer-locator](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-locator.md) | Suggest locators over page methods | | | |
198156
| [prefer-strict-equal](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-strict-equal.md) | Suggest using `toStrictEqual()` | | | 💡 |
199157
| [prefer-to-be](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-to-be.md) | Suggest using `toBe()` | | 🔧 | |
200158
| [prefer-to-contain](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-to-contain.md) | Suggest using `toContain()` | | 🔧 | |

docs/rules/no-useless-await.md

+9
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
```

docs/rules/prefer-locator.md

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Suggest using `page.locator()` (`prefer-locator`)
2+
3+
Suggest using locators and their associated methods instead of page methods for
4+
performing actions.
5+
6+
## Rule details
7+
8+
This rule triggers a warning if page methods are used, instead of locators.
9+
10+
The following patterns are considered warnings:
11+
12+
```javascript
13+
page.click('css=button')
14+
await page.click('css=button')
15+
await page.dblclick('xpath=//button')
16+
await page.fill('input[type="password"]', 'password')
17+
18+
await page.frame('frame-name').click('css=button')
19+
```
20+
21+
The following pattern are **not** warnings:
22+
23+
```javascript
24+
const locator = page.locator('css=button')
25+
await page.getByRole('password').fill('password')
26+
await page.getByLabel('User Name').fill('John')
27+
await page.getByRole('button', { name: 'Sign in' }).click()
28+
await page.locator('input[type="password"]').fill('password')
29+
await page.locator('css=button').click()
30+
await page.locator('xpath=//button').dblclick()
31+
32+
await page.frameLocator('#my-iframe').getByText('Submit').click()
33+
```

docs/rules/prefer-native-locators.md

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Suggest using native Playwright locators (`prefer-native-locators`)
2+
3+
Playwright has built-in locators for common query selectors such as finding
4+
elements by placeholder text, ARIA role, accessible name, and more. This rule
5+
suggests using these native locators instead of using `page.locator()` with an
6+
equivalent selector.
7+
8+
In some cases this can be more robust too, such as finding elements by ARIA role
9+
or accessible name, because some elements have implicit roles, and there are
10+
multiple ways to specify accessible names.
11+
12+
## Rule details
13+
14+
Examples of **incorrect** code for this rule:
15+
16+
```javascript
17+
page.locator('[aria-label="View more"]')
18+
page.locator('[role="button"]')
19+
page.locator('[placeholder="Enter some text..."]')
20+
page.locator('[alt="Playwright logo"]')
21+
page.locator('[title="Additional context"]')
22+
page.locator('[data-testid="password-input"]')
23+
```
24+
25+
Examples of **correct** code for this rule:
26+
27+
```javascript
28+
page.getByLabel('View more')
29+
page.getByRole('Button')
30+
page.getByPlaceholder('Enter some text...')
31+
page.getByAltText('Playwright logo')
32+
page.getByTestId('password-input')
33+
page.getByTitle('Additional context')
34+
```
35+
36+
## Options
37+
38+
```json
39+
{
40+
"playwright/prefer-native-locators": [
41+
"error",
42+
{
43+
"testIdAttribute": "data-testid"
44+
}
45+
]
46+
}
47+
```
48+
49+
### `testIdAttribute`
50+
51+
Default: `data-testid`
52+
53+
This string option specifies the test ID attribute to look for and replace with
54+
`page.getByTestId()` calls. If you are using
55+
[`page.setTestIdAttribute()`](https://playwright.dev/docs/api/class-selectors#selectors-set-test-id-attribute),
56+
this should be set to the same value as what you pass in to that method.
57+
58+
Examples of **incorrect** code when using
59+
`{ "testIdAttribute": "data-custom-testid" }` option:
60+
61+
```js
62+
page.locator('[data-custom-testid="password-input"]')
63+
```
64+
65+
Examples of **correct** code when using
66+
`{ "testIdAttribute": "data-custom-testid" }` option:
67+
68+
```js
69+
page.getByTestId('password-input')
70+
```

docs/rules/valid-title.md

+14
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,19 @@ test(123, () => {})
4646
test.describe(String(/.+/), () => {})
4747
test.describe(myFunction, () => {})
4848
test.describe(6, function () {})
49+
50+
const title = 123
51+
test(title, () => {})
4952
```
5053

5154
Examples of **correct** code for this rule:
5255

5356
```javascript
5457
test('is a string', () => {})
5558
test.describe('is a string', () => {})
59+
60+
const title = 'is a string'
61+
test(title, () => {})
5662
```
5763

5864
Examples of **correct** code when `ignoreTypeOfDescribeName` is `true`:
@@ -143,6 +149,7 @@ test.describe('foo', () => {
143149
```ts
144150
interface Options {
145151
ignoreSpaces?: boolean
152+
ignoreTypeOfStepName?: boolean
146153
ignoreTypeOfTestName?: boolean
147154
ignoreTypeOfDescribeName?: boolean
148155
disallowedWords?: string[]
@@ -157,6 +164,13 @@ Default: `false`
157164

158165
When enabled, the leading and trailing spaces won't be checked.
159166

167+
#### `ignoreTypeOfStepName`
168+
169+
Default: `true`
170+
171+
When enabled, the type of the first argument to `test.step` blocks won't be
172+
checked.
173+
160174
#### `ignoreTypeOfDescribeName`
161175

162176
Default: `false`

eslint.config.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import mskelton from '@mskelton/eslint-config'
2+
3+
export default [
4+
...mskelton.recommended,
5+
{
6+
ignores: ['dist', 'examples'],
7+
},
8+
{
9+
files: ['**/*.test.ts'],
10+
rules: {
11+
'no-template-curly-in-string': 'off',
12+
},
13+
},
14+
]

examples/.eslintrc

-24
This file was deleted.

examples/eslint.config.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import playwright from 'eslint-plugin-playwright'
2+
3+
export default {
4+
...playwright.configs['flat/recommended'],
5+
rules: {
6+
...playwright.configs['flat/recommended'].rules,
7+
'playwright/no-commented-out-tests': 'error',
8+
'playwright/no-duplicate-hooks': 'error',
9+
'playwright/no-get-by-title': 'error',
10+
'playwright/no-nth-methods': 'error',
11+
'playwright/no-raw-locators': 'error',
12+
'playwright/no-restricted-matchers': 'error',
13+
'playwright/prefer-comparison-matcher': 'error',
14+
'playwright/prefer-equality-matcher': 'error',
15+
'playwright/prefer-hooks-in-order': 'error',
16+
'playwright/prefer-hooks-on-top': 'error',
17+
'playwright/prefer-lowercase-title': 'error',
18+
'playwright/prefer-strict-equal': 'error',
19+
'playwright/prefer-to-be': 'error',
20+
'playwright/prefer-to-contain': 'error',
21+
'playwright/prefer-to-have-count': 'error',
22+
'playwright/prefer-to-have-length': 'error',
23+
'playwright/require-to-throw-message': 'error',
24+
'playwright/require-top-level-describe': 'error',
25+
},
26+
}

examples/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
},
77
"dependencies": {
88
"@playwright/test": "^1.42.0",
9-
"eslint": "^8.51.0",
9+
"eslint": "^9.13.0",
1010
"eslint-plugin-playwright": "file:../"
1111
},
1212
"devDependencies": {

index.cjs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// eslint-disable-next-line @typescript-eslint/no-require-imports
2+
module.exports = require('./dist/index.cjs')

index.d.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Linter, Rule } from 'eslint'
2+
3+
declare const config: {
4+
configs: {
5+
'flat/recommended': Linter.Config
6+
'playwright-test': Linter.Config
7+
recommended: Linter.Config
8+
}
9+
rules: Record<string, Rule.RuleModule>
10+
}
11+
12+
export default config

index.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import plugin from './dist/index.cjs'
2+
3+
export default plugin

0 commit comments

Comments
 (0)