eslint-plugin-playwright 0.10.0 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 Max Schmitt
3
+ Copyright (c) 2022 Max Schmitt
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -3,25 +3,27 @@
3
3
  [![Test](https://github.com/playwright-community/eslint-plugin-playwright/actions/workflows/test.yml/badge.svg)](https://github.com/playwright-community/eslint-plugin-playwright/actions/workflows/test.yml)
4
4
  [![NPM](https://img.shields.io/npm/v/eslint-plugin-playwright)](https://www.npmjs.com/package/eslint-plugin-playwright)
5
5
 
6
- > ESLint plugin for your [Playwright](https://github.com/microsoft/playwright) testing needs.
6
+ > ESLint plugin for your [Playwright](https://github.com/microsoft/playwright)
7
+ > testing needs.
7
8
 
8
9
  ## Installation
9
10
 
10
11
  Yarn
11
12
 
12
- ```sh
13
+ ```bash
13
14
  yarn add -D eslint-plugin-playwright
14
15
  ```
15
16
 
16
17
  NPM
17
18
 
18
- ```sh
19
+ ```bash
19
20
  npm install -D eslint-plugin-playwright
20
21
  ```
21
22
 
22
23
  ## Usage
23
24
 
24
- This plugin bundles two configurations to work with both `@playwright/test` or `jest-playwright`.
25
+ This plugin bundles two configurations to work with both `@playwright/test` or
26
+ `jest-playwright`.
25
27
 
26
28
  ### With [Playwright test runner](https://playwright.dev/docs/test-intro)
27
29
 
@@ -39,360 +41,29 @@ This plugin bundles two configurations to work with both `@playwright/test` or `
39
41
  }
40
42
  ```
41
43
 
42
- ## Rules
43
-
44
- ### `missing-playwright-await` 🔧
45
-
46
- Identify false positives when async Playwright APIs are not properly awaited.
47
-
48
- #### Example
49
-
50
- Example of **incorrect** code for this rule:
51
-
52
- ```js
53
- expect(page).toMatchText('text');
54
-
55
- test.step('clicks the button', async () => {
56
- await page.click('button');
57
- });
58
- ```
59
-
60
- Example of **correct** code for this rule:
61
-
62
- ```js
63
- await expect(page).toMatchText('text');
64
-
65
- await test.step('clicks the button', async () => {
66
- await page.click('button');
67
- });
68
- ```
69
-
70
- #### Options
71
-
72
- 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 `expect` matchers.
73
-
74
- ```json
75
- {
76
- "playwright/missing-playwright-await": [
77
- "error",
78
- { "customMatchers": ["toBeCustomThing"] }
79
- ]
80
- }
81
- ```
82
-
83
- ### `no-page-pause`
84
-
85
- Prevent usage of `page.pause()`.
86
-
87
- #### Example
88
-
89
- Example of **incorrect** code for this rule:
90
-
91
- ```js
92
- await page.click('button');
93
- await page.pause();
94
- ```
95
-
96
- Example of **correct** code for this rule:
97
-
98
- ```js
99
- await page.click('button');
100
- ```
101
-
102
- ### `no-element-handle`
103
-
104
- Disallow the creation of element handles with `page.$` or `page.$$`.
105
-
106
- Examples of **incorrect** code for this rule:
107
-
108
- ```js
109
- // Element Handle
110
- const buttonHandle = await page.$('button');
111
- await buttonHandle.click();
112
-
113
- // Element Handles
114
- const linkHandles = await page.$$('a');
115
- ```
116
-
117
- Example of **correct** code for this rule:
118
-
119
- ```js
120
- const buttonLocator = page.locator('button');
121
- await buttonLocator.click();
122
- ```
123
-
124
- ### `no-eval`
125
-
126
- Disallow usage of `page.$eval` and `page.$$eval`.
127
-
128
- Examples of **incorrect** code for this rule:
129
-
130
- ```js
131
- const searchValue = await page.$eval('#search', (el) => el.value);
132
-
133
- const divCounts = await page.$$eval(
134
- 'div',
135
- (divs, min) => divs.length >= min,
136
- 10
137
- );
138
-
139
- await page.$eval('#search', (el) => el.value);
140
-
141
- await page.$$eval('#search', (el) => el.value);
142
- ```
143
-
144
- Example of **correct** code for this rule:
145
-
146
- ```js
147
- await page.locator('button').evaluate((node) => node.innerText);
148
-
149
- await page.locator('div').evaluateAll((divs, min) => divs.length >= min, 10);
150
- ```
151
-
152
- ### `no-focused-test`
153
-
154
- Disallow usage of `.only()` annotation
155
-
156
- Examples of **incorrect** code for this rule:
157
-
158
- ```js
159
- test.only('focus this test', async ({ page }) => {});
160
-
161
- test.describe.only('focus two tests', () => {
162
- test('one', async ({ page }) => {});
163
- test('two', async ({ page }) => {});
164
- });
165
-
166
- test.describe.parallel.only('focus two tests in parallel mode', () => {
167
- test('one', async ({ page }) => {});
168
- test('two', async ({ page }) => {});
169
- });
170
-
171
- test.describe.serial.only('focus two tests in serial mode', () => {
172
- test('one', async ({ page }) => {});
173
- test('two', async ({ page }) => {});
174
- });
175
- ```
176
-
177
- Examples of **correct** code for this rule:
178
-
179
- ```js
180
- test('this test', async ({ page }) => {});
181
-
182
- test.describe('two tests', () => {
183
- test('one', async ({ page }) => {});
184
- test('two', async ({ page }) => {});
185
- });
186
-
187
- test.describe.parallel('two tests in parallel mode', () => {
188
- test('one', async ({ page }) => {});
189
- test('two', async ({ page }) => {});
190
- });
191
-
192
- test.describe.serial('two tests in serial mode', () => {
193
- test('one', async ({ page }) => {});
194
- test('two', async ({ page }) => {});
195
- });
196
- ```
197
-
198
- ### `no-wait-for-timeout`
199
-
200
- Disallow usage of `page.waitForTimeout()`.
201
-
202
- Example of **incorrect** code for this rule:
203
-
204
- ```js
205
- await page.waitForTimeout(5000);
206
- ```
207
-
208
- Examples of **correct** code for this rule:
209
-
210
- ```js
211
- // Use signals such as network events, selectors becoming visible and others instead.
212
- await page.waitForLoadState();
213
-
214
- await page.waitForUrl('/home');
215
-
216
- await page.waitForFunction(() => window.innerWidth < 100);
217
- ```
218
-
219
- ### `no-skipped-test`
220
-
221
- Disallow usage of the `.skip()` annotation.
222
-
223
- Examples of **incorrect** code for this rule:
224
-
225
- ```js
226
- test.skip('skip this test', async ({ page }) => {});
227
-
228
- test.describe.skip('skip two tests', () => {
229
- test('one', async ({ page }) => {});
230
- test('two', async ({ page }) => {});
231
- });
232
-
233
- test.describe('skip test inside describe', () => {
234
- test.skip();
235
- });
236
-
237
- test.describe('skip test conditionally', async ({ browserName }) => {
238
- test.skip(browserName === 'firefox', 'Working on it');
239
- });
240
- ```
241
-
242
- Examples of **correct** code for this rule:
243
-
244
- ```js
245
- test('this test', async ({ page }) => {});
246
-
247
- test.describe('two tests', () => {
248
- test('one', async ({ page }) => {});
249
- test('two', async ({ page }) => {});
250
- });
251
- ```
252
-
253
- ### `no-force-option`
254
-
255
- Disallow usage of the `{ force: true }` option.
256
-
257
- Examples of **incorrect** code for this rule:
258
-
259
- ```js
260
- await page.locator('button').click({ force: true });
261
-
262
- await page.locator('check').check({ force: true });
263
-
264
- await page.locator('input').fill('something', { force: true });
265
- ```
266
-
267
- Examples of **correct** code for this rule:
268
-
269
- ```js
270
- await page.locator('button').click();
271
-
272
- await page.locator('check').check();
273
-
274
- await page.locator('input').fill('something');
275
- ```
276
-
277
- ### `max-nested-describe`
278
-
279
- Enforces a maximum depth to nested `.describe()` calls. Useful for improving readability and parallelization of tests.
280
-
281
- Uses a default max depth option of `{ "max": 5 }`.
282
-
283
- Examples of **incorrect** code for this rule (using defaults):
284
-
285
- ```js
286
- test.describe('level 1', () => {
287
- test.describe('level 2', () => {
288
- test.describe('level 3', () => {
289
- test.describe('level 4', () => {
290
- test.describe('level 5', () => {
291
- test.describe('level 6', () => {
292
- test('this test', async ({ page }) => {});
293
- test('that test', async ({ page }) => {});
294
- });
295
- });
296
- });
297
- });
298
- });
299
- });
300
- ```
301
-
302
- Examples of **correct** code for this rule (using defaults):
303
-
304
- ```js
305
- test.describe('first level', () => {
306
- test.describe('second level', () => {
307
- test('this test', async ({ page }) => {});
308
- test('that test', async ({ page }) => {});
309
- });
310
- });
311
- ```
312
-
313
- #### Options
314
-
315
- The rule accepts a non-required option to override the default maximum nested describe depth (5).
316
-
317
- ```json
318
- {
319
- "playwright/max-nested-describe": ["error", { "max": 3 }]
320
- }
321
- ```
322
-
323
- ### `no-conditional-in-test`
324
-
325
- Disallow conditional statements such as `if`, `switch`, and ternary expressions within tests.
326
-
327
- Examples of **incorrect** code for this rule:
328
-
329
- ```js
330
- test('foo', async ({ page }) => {
331
- if (someCondition) {
332
- bar();
333
- }
334
- });
335
-
336
- test('bar', async ({ page }) => {
337
- switch (mode) {
338
- case 'single':
339
- generateOne();
340
- break;
341
- case 'double':
342
- generateTwo();
343
- break;
344
- case 'multiple':
345
- generateMany();
346
- break;
347
- }
348
-
349
- await expect(page.locator('.my-image').count()).toBeGreaterThan(0);
350
- });
351
-
352
- test('baz', async ({ page }) => {
353
- const hotkey =
354
- process.platform === 'linux' ? ['Control', 'Alt', 'f'] : ['Alt', 'f'];
355
- await Promise.all(hotkey.map((x) => page.keyboard.down(x)));
356
-
357
- expect(actionIsPerformed()).toBe(true);
358
- });
359
- ```
360
-
361
- Examples of **correct** code for this rule:
362
-
363
- ```js
364
- test.describe('my tests', () => {
365
- if (someCondition) {
366
- test('foo', async ({ page }) => {
367
- bar();
368
- });
369
- }
370
- });
371
-
372
- beforeEach(() => {
373
- switch (mode) {
374
- case 'single':
375
- generateOne();
376
- break;
377
- case 'double':
378
- generateTwo();
379
- break;
380
- case 'multiple':
381
- generateMany();
382
- break;
383
- }
384
- });
385
-
386
- test('bar', async ({ page }) => {
387
- await expect(page.locator('.my-image').count()).toBeGreaterThan(0);
388
- });
389
-
390
- const hotkey =
391
- process.platform === 'linux' ? ['Control', 'Alt', 'f'] : ['Alt', 'f'];
392
-
393
- test('baz', async ({ page }) => {
394
- await Promise.all(hotkey.map((x) => page.keyboard.down(x)));
395
-
396
- expect(actionIsPerformed()).toBe(true);
397
- });
398
- ```
44
+ ## List of Supported Rules
45
+
46
+ ✔: Enabled in the recommended configuration.\
47
+ 🔧: Some problems reported by this rule are automatically fixable by the [`--fix`](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix)
48
+ command line option.\
49
+ 💡: Some problems reported by this rule are manually fixable by editor
50
+ [suggestions](https://eslint.org/docs/latest/developer-guide/working-with-rules#providing-suggestions).
51
+
52
+ | ✔ | 🔧 | 💡 | Rule | Description |
53
+ | :-: | :-: | :-: | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
54
+ | ✔ | | | [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 |
55
+ | ✔ | 🔧 | | [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 |
56
+ | ✔ | | | [no-conditional-in-test](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-conditional-in-test.md) | Disallow conditional logic in tests |
57
+ | ✔ | | 💡 | [no-element-handle](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-element-handle.md) | Disallow usage of element handles |
58
+ | ✔ | | | [no-eval](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-eval.md) | Disallow usage of `page.$eval` and `page.$$eval` |
59
+ | ✔ | | 💡 | [no-focused-test](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-focused-test.md) | Disallow usage of `.only` annotation |
60
+ | ✔ | | | [no-force-option](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-force-option.md) | Disallow usage of the `{ force: true }` option |
61
+ | ✔ | | | [no-page-pause](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-page-pause.md) | Disallow using `page.pause` |
62
+ | | | | [no-restricted-matchers](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-restricted-matchers.md) | Disallow specific matchers & modifiers |
63
+ | ✔ | | 💡 | [no-skipped-test](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-skipped-test.md) | Disallow usage of the `.skip` annotation |
64
+ | ✔ | 🔧 | | [no-useless-not](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-useless-not.md) | Disallow usage of `not` matchers when a specific matcher exists |
65
+ | ✔ | | 💡 | [no-wait-for-timeout](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/no-wait-for-timeout.md) | Disallow usage of `page.waitForTimeout` |
66
+ | | 🔧 | | [prefer-lowercase-title](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-lowercase-title.md) | Enforce lowercase test names |
67
+ | | 🔧 | | [prefer-to-have-length](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-to-have-length.md) | Suggest using `toHaveLength()` |
68
+ | | | | [require-top-level-describe](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/require-top-level-describe.md) | Require test cases and hooks to be inside a `test.describe` block |
69
+ | ✔ | | | [valid-expect](https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/valid-expect.md) | Enforce valid `expect()` usage |
package/lib/index.js CHANGED
@@ -1,78 +1,92 @@
1
- const missingPlaywrightAwait = require('./rules/missing-playwright-await');
2
- const noPagePause = require('./rules/no-page-pause');
3
- const noElementHandle = require('./rules/no-element-handle');
4
- const noEval = require('./rules/no-eval');
5
- const noFocusedTest = require('./rules/no-focused-test');
6
- const noSkippedTest = require('./rules/no-skipped-test');
7
- const noWaitForTimeout = require('./rules/no-wait-for-timeout');
8
- const noForceOption = require('./rules/no-force-option');
9
- const maxNestedDescribe = require('./rules/max-nested-describe');
10
- const noConditionalInTest = require('./rules/no-conditional-in-test');
11
-
1
+ "use strict";
2
+ const missing_playwright_await_1 = require("./rules/missing-playwright-await");
3
+ const no_page_pause_1 = require("./rules/no-page-pause");
4
+ const no_element_handle_1 = require("./rules/no-element-handle");
5
+ const no_eval_1 = require("./rules/no-eval");
6
+ const no_focused_test_1 = require("./rules/no-focused-test");
7
+ const no_skipped_test_1 = require("./rules/no-skipped-test");
8
+ const no_wait_for_timeout_1 = require("./rules/no-wait-for-timeout");
9
+ const no_force_option_1 = require("./rules/no-force-option");
10
+ const max_nested_describe_1 = require("./rules/max-nested-describe");
11
+ const no_conditional_in_test_1 = require("./rules/no-conditional-in-test");
12
+ const no_restricted_matchers_1 = require("./rules/no-restricted-matchers");
13
+ const no_useless_not_1 = require("./rules/no-useless-not");
14
+ const prefer_lowercase_title_1 = require("./rules/prefer-lowercase-title");
15
+ const prefer_to_have_length_1 = require("./rules/prefer-to-have-length");
16
+ const require_top_level_describe_1 = require("./rules/require-top-level-describe");
17
+ const valid_expect_1 = require("./rules/valid-expect");
12
18
  module.exports = {
13
- configs: {
14
- 'playwright-test': {
15
- plugins: ['playwright'],
16
- env: {
17
- 'shared-node-browser': true,
18
- },
19
- rules: {
20
- 'no-empty-pattern': 'off',
21
- 'playwright/missing-playwright-await': 'error',
22
- 'playwright/no-page-pause': 'warn',
23
- 'playwright/no-element-handle': 'warn',
24
- 'playwright/no-eval': 'warn',
25
- 'playwright/no-focused-test': 'error',
26
- 'playwright/no-skipped-test': 'warn',
27
- 'playwright/no-wait-for-timeout': 'warn',
28
- 'playwright/no-force-option': 'warn',
29
- 'playwright/max-nested-describe': 'warn',
30
- 'playwright/no-conditional-in-test': 'warn',
31
- },
19
+ configs: {
20
+ 'playwright-test': {
21
+ plugins: ['playwright'],
22
+ env: {
23
+ 'shared-node-browser': true,
24
+ },
25
+ rules: {
26
+ 'no-empty-pattern': 'off',
27
+ 'playwright/missing-playwright-await': 'error',
28
+ 'playwright/no-page-pause': 'warn',
29
+ 'playwright/no-element-handle': 'warn',
30
+ 'playwright/no-eval': 'warn',
31
+ 'playwright/no-focused-test': 'error',
32
+ 'playwright/no-skipped-test': 'warn',
33
+ 'playwright/no-wait-for-timeout': 'warn',
34
+ 'playwright/no-force-option': 'warn',
35
+ 'playwright/max-nested-describe': 'warn',
36
+ 'playwright/no-conditional-in-test': 'warn',
37
+ 'playwright/no-useless-not': 'warn',
38
+ 'playwright/valid-expect': 'error',
39
+ },
40
+ },
41
+ 'jest-playwright': {
42
+ plugins: ['jest', 'playwright'],
43
+ env: {
44
+ 'shared-node-browser': true,
45
+ jest: true,
46
+ },
47
+ rules: {
48
+ 'playwright/missing-playwright-await': 'error',
49
+ 'playwright/no-page-pause': 'warn',
50
+ 'jest/no-standalone-expect': [
51
+ 'error',
52
+ {
53
+ additionalTestBlockFunctions: [
54
+ 'test.jestPlaywrightDebug',
55
+ 'it.jestPlaywrightDebug',
56
+ 'test.jestPlaywrightSkip',
57
+ 'it.jestPlaywrightSkip',
58
+ 'test.jestPlaywrightConfig',
59
+ 'it.jestPlaywrightConfig',
60
+ ],
61
+ },
62
+ ],
63
+ },
64
+ globals: {
65
+ browserName: true,
66
+ deviceName: true,
67
+ browser: true,
68
+ context: true,
69
+ page: true,
70
+ jestPlaywright: true,
71
+ },
72
+ },
32
73
  },
33
- 'jest-playwright': {
34
- plugins: ['jest', 'playwright'],
35
- env: {
36
- 'shared-node-browser': true,
37
- jest: true,
38
- },
39
- rules: {
40
- 'playwright/missing-playwright-await': 'error',
41
- 'playwright/no-page-pause': 'warn',
42
- 'jest/no-standalone-expect': [
43
- 'error',
44
- {
45
- additionalTestBlockFunctions: [
46
- 'test.jestPlaywrightDebug',
47
- 'it.jestPlaywrightDebug',
48
- 'test.jestPlaywrightSkip',
49
- 'it.jestPlaywrightSkip',
50
- 'test.jestPlaywrightConfig',
51
- 'it.jestPlaywrightConfig',
52
- ],
53
- },
54
- ],
55
- },
56
- globals: {
57
- browserName: true,
58
- deviceName: true,
59
- browser: true,
60
- context: true,
61
- page: true,
62
- jestPlaywright: true,
63
- },
74
+ rules: {
75
+ 'missing-playwright-await': missing_playwright_await_1.default,
76
+ 'no-page-pause': no_page_pause_1.default,
77
+ 'no-element-handle': no_element_handle_1.default,
78
+ 'no-eval': no_eval_1.default,
79
+ 'no-focused-test': no_focused_test_1.default,
80
+ 'no-skipped-test': no_skipped_test_1.default,
81
+ 'no-wait-for-timeout': no_wait_for_timeout_1.default,
82
+ 'no-force-option': no_force_option_1.default,
83
+ 'max-nested-describe': max_nested_describe_1.default,
84
+ 'no-conditional-in-test': no_conditional_in_test_1.default,
85
+ 'no-useless-not': no_useless_not_1.default,
86
+ 'no-restricted-matchers': no_restricted_matchers_1.default,
87
+ 'prefer-lowercase-title': prefer_lowercase_title_1.default,
88
+ 'prefer-to-have-length': prefer_to_have_length_1.default,
89
+ 'require-top-level-describe': require_top_level_describe_1.default,
90
+ 'valid-expect': valid_expect_1.default,
64
91
  },
65
- },
66
- rules: {
67
- 'missing-playwright-await': missingPlaywrightAwait,
68
- 'no-page-pause': noPagePause,
69
- 'no-element-handle': noElementHandle,
70
- 'no-eval': noEval,
71
- 'no-focused-test': noFocusedTest,
72
- 'no-skipped-test': noSkippedTest,
73
- 'no-wait-for-timeout': noWaitForTimeout,
74
- 'no-force-option': noForceOption,
75
- 'max-nested-describe': maxNestedDescribe,
76
- 'no-conditional-in-test': noConditionalInTest,
77
- },
78
92
  };