### Correct: Conditional setup with beforeEach Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-conditional-in-test.md This example demonstrates the correct approach of using a 'switch' statement within a 'beforeEach' hook for conditional setup. ```javascript beforeEach(() => { switch (mode) { case 'single': generateOne() break case 'double': generateTwo() break case 'multiple': generateMany() break } }) ``` -------------------------------- ### Install Dependencies with Yarn Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/CONTRIBUTING.md Installs the necessary project dependencies using yarn. This should be run before making any code changes. ```bash yarn install ``` -------------------------------- ### Rule Configuration Example Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-lowercase-title.md Example configuration for the `prefer-lowercase-title` rule, including options for allowed prefixes, ignored functions, and top-level describe behavior. ```json { "playwright/prefer-lowercase-title": [ "error", { "allowedPrefixes": ["GET", "POST"], "ignore": ["test.describe", "test"], "ignoreTopLevelDescribe": true } ] } ``` -------------------------------- ### Correct code examples Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-skipped-test.md Examples of code that adheres to the rule, showing standard test and describe blocks without skipping. ```javascript test('this test', async ({ page }) => {}) ``` ```javascript test.describe('two tests', () => { test('one', async ({ page }) => {}) test('two', async ({ page }) => {}) }) ``` -------------------------------- ### Install ESLint Plugin Playwright with pnpm Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/README.md Install the plugin as a development dependency using pnpm. ```bash pnpm add -D eslint-plugin-playwright ``` -------------------------------- ### Correct: Allowed API endpoint prefix Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-lowercase-title.md Shows correct usage with the `allowedPrefixes` option set to `["GET"]`, permitting titles that start with 'GET '. ```javascript test.describe('GET /live') ``` -------------------------------- ### Correct `mustMatch` Usage Examples Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md These examples demonstrate correct usage of the `mustMatch` option, showing titles that adhere to the specified regular expressions. ```javascript // with mustMatch: '^that' test.describe('that thing that needs to be done', () => {}) test('that this there!', () => {}) ``` ```javascript // with mustMatch: { test: '^that' } test.describe('the tests will be run', () => {}) test('that the stuff works', () => {}) ``` -------------------------------- ### Corrected Code: Using Playwright Hooks Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/require-hook.md This example demonstrates the same scenarios as the flagged version but correctly places setup and teardown logic within `test.beforeEach` and `test.afterEach` hooks. ```javascript const initializeCityDatabase = () => { database.addCity('Vienna') database.addCity('San Juan') database.addCity('Wellington') } const clearCityDatabase = () => { database.clear() } test.beforeEach(() => { initializeCityDatabase() }) test('that persists cities', () => { expect(database.cities.length).toHaveLength(3) }) test('city database has Vienna', () => { expect(isCity('Vienna')).toBeTruthy() }) test('city database has San Juan', () => { expect(isCity('San Juan')).toBeTruthy() }) test.describe('when loading cities from the api', () => { test.beforeEach(() => { clearCityDatabase() }) test('does not duplicate cities', async () => { await database.loadCities() expect(database.cities).toHaveLength(4) }) }) test.afterEach(() => { clearCityDatabase() }) ``` -------------------------------- ### Install ESLint Plugin Playwright with Yarn Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/README.md Install the plugin as a development dependency using Yarn. ```bash yarn add -D eslint-plugin-playwright ``` -------------------------------- ### Correct titles without duplicate prefixes Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md Examples of correct code where test or describe block titles do not start with a duplicate prefix. ```javascript test('foo', () => {}) test.describe('foo', () => { test('bar', () => {}) }) ``` -------------------------------- ### Install ESLint Plugin Playwright with npm Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/README.md Install the plugin as a development dependency using npm. ```bash npm install -D eslint-plugin-playwright ``` -------------------------------- ### Custom Matchers Configuration Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/missing-playwright-await.md Configuration example for specifying custom async matchers that the rule should also warn about. ```json { "playwright/missing-playwright-await": ["error", { "customMatchers": ["toBeCustomThing"] }] } ``` -------------------------------- ### Configuration: Using assertFunctionPatterns Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/expect-expect.md Regular expression patterns for assertion function names can be specified with 'assertFunctionPatterns'. This example uses patterns to match functions starting with 'assert' or 'verify'. ```javascript /* eslint playwright/expect-expect: ["error", { "assertFunctionPatterns": ["^assert.*", "^verify.*"] }] */ function assertScrolledToBottom(page) { // ... } function verifyPageLoaded(page) { // ... } test('should scroll', async ({ page }) => { await assertScrolledToBottom(page) await verifyPageLoaded(page) }) ``` -------------------------------- ### Valid locator usage examples Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-locator.md These examples demonstrate correct usage of locators and their associated methods, which do not trigger the rule. Prefer these patterns for element interaction. ```javascript const locator = page.locator('css=button') ``` ```javascript await page.getByRole('password').fill('password') ``` ```javascript await page.getByLabel('User Name').fill('John') ``` ```javascript await page.getByRole('button', { name: 'Sign in' }).click() ``` ```javascript await page.locator('input[type="password"]').fill('password') ``` ```javascript await page.locator('css=button').click() ``` ```javascript await page.locator('xpath=//button').dblclick() ``` ```javascript await page.frameLocator('#my-iframe').getByText('Submit').click() ``` -------------------------------- ### Correct expect() calls Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-expect.md Examples of valid expect() calls that adhere to the rule, demonstrating proper usage with matchers. ```javascript expect(locator).toHaveText('howdy') expect('something').toBe('something') expect(true).toBeDefined() ``` -------------------------------- ### Allow alternative waiting strategies Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-wait-for-selector.md These are examples of correct code that adhere to the rule. They demonstrate alternative, more robust waiting methods. ```javascript await page.waitForLoadState() ``` ```javascript await page.waitForURL('/home') ``` ```javascript await page.waitForFunction(() => window.innerWidth < 100) ``` -------------------------------- ### Allow standard tests Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-slowed-test.md Examples of correct usage, demonstrating standard test definitions without the `.slow` annotation. ```javascript test('this test', async ({ page }) => {}) test.describe('two tests', () => { test('one', async ({ page }) => {}) test('two', async ({ page }) => {}) }) ``` -------------------------------- ### Correct: Sequential test.step() Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-nested-step.md This example demonstrates the correct usage with sequential test.step() calls, avoiding nesting. ```javascript test('foo', async () => { await test.step('step1', async () => { await expect(true).toBe(true) }) await test.step('step2', async () => { await expect(true).toBe(true) }) }) ``` -------------------------------- ### Include Page and Locator Methods Configuration Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/missing-playwright-await.md Configuration example to enable broader detection for page and locator methods like page.goto() and locator.click(). ```json { "playwright/missing-playwright-await": ["error", { "includePageLocatorMethods": true }] } ``` -------------------------------- ### Incorrect duplicate prefixes Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md Examples of incorrect code where test or describe block titles start with a duplicate prefix. ```javascript test('test foo', () => {}) test.describe('foo', () => { test('test bar', () => {}) }) test.describe('describe foo', () => { test('bar', () => {}) }) ``` -------------------------------- ### Incorrect code examples for no-restricted-matchers Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-restricted-matchers.md These examples demonstrate code that violates the `no-restricted-matchers` rule with the provided configuration. ```javascript test('is false', () => { expect(a).toBeFalsy() }) ``` ```javascript test('not', () => { expect(a).not.toBe(true) }) ``` ```javascript test('chain', async () => { await expect(foo).not.toHaveText('bar') }) ``` -------------------------------- ### Correct: Single beforeEach hook Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-duplicate-hooks.md This example shows a correctly structured describe block with only one beforeEach hook. ```javascript /* eslint playwright/no-duplicate-hooks: "error" */ test.describe('foo', () => { test.beforeEach(() => { // some setup }) test('foo_test', () => { // some test }) }) ``` -------------------------------- ### Correct: Standard describe block Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-focused-test.md Example of a standard `describe` block without `.only`. ```javascript test.describe('two tests', () => { test('one', async ({ page }) => {}) test('two', async ({ page }) => {}) }) ``` -------------------------------- ### Correct: Standard describe block in parallel mode Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-focused-test.md Example of a standard `describe.parallel` block without `.only`. ```javascript test.describe.parallel('two tests in parallel mode', () => { test('one', async ({ page }) => {}) test('two', async ({ page }) => {}) }) ``` -------------------------------- ### Correct: Standard test Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-focused-test.md Example of a standard test without `.only`. ```javascript test('this test', async ({ page }) => {}) ``` -------------------------------- ### Configuration for no-slowed-test rule Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-slowed-test.md Example ESLint configuration for the `no-slowed-test` rule, including the `allowConditional` option. ```json { "playwright/no-slowed-test": [ "error", { "allowConditional": false } ] } ``` -------------------------------- ### Incorrect: Focused describe block Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-focused-test.md Example of a `describe` block marked with `.only`. ```javascript test.describe.only('focus two tests', () => { test('one', async ({ page }) => {}) test('two', async ({ page }) => {}) }) ``` -------------------------------- ### Correct code with allowed `afterEach` hook Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-hooks.md This example is correct because it only uses the allowed `test.afterEach` hook and sets up test-specific state within the test. ```javascript /* eslint playwright/no-hooks: ["error", { "allow": ["afterEach"] }] */ function setupFoo(options) { /* ... */ } test.afterEach(() => { playwright.resetModules() }) test('foo does this', () => { const foo = setupFoo() // ... }) test('foo does that', () => { const foo = setupFoo() // ... }) ``` -------------------------------- ### Correct: Standard describe block in serial mode Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-focused-test.md Example of a standard `describe.serial` block without `.only`. ```javascript test.describe.serial('two tests in serial mode', () => { test('one', async ({ page }) => {}) test('two', async ({ page }) => {}) }) ``` -------------------------------- ### Correct: Using getByRole locator Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-raw-locators.md This example demonstrates the correct usage of `page.getByRole()` to select a button, which is more robust than a raw locator. ```javascript await page.getByRole('button').click() ``` -------------------------------- ### Correct conditional skipping with allowConditional option Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-skipped-test.md Example of correct code when `allowConditional` is true, demonstrating allowed conditional skips. ```javascript test('foo', ({ browserName }) => { test.skip(browserName === 'firefox', 'Still working on it') expect(1).toBe(1) }) ``` -------------------------------- ### Correct spacing with beforeEach and test.step Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/consistent-spacing-between-blocks.md This example illustrates correct spacing in a test file with a beforeEach hook and nested test steps. A blank line is present between the hook and the test, and between the test steps. ```javascript test.beforeEach(() => {}) test('example 3', () => { await test.step('first', async () => { expect(true).toBe(true) }) await test.step('second', async () => { expect(true).toBe(true) }) }) ``` -------------------------------- ### Incorrect: Using raw locator Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-raw-locators.md This example shows the incorrect usage of a raw CSS selector with `page.locator()`. Prefer using user-facing locators. ```javascript await page.locator('button').click() ``` -------------------------------- ### Correct string titles Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md Examples of correct code where test or describe block titles are strings. ```javascript test('is a string', () => {}) test.describe('is a string', () => {}) const title = 'is a string' test(title, () => {}) ``` -------------------------------- ### Incorrect: Focused describe block in serial mode Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-focused-test.md Example of a `describe.serial` block marked with `.only`. ```javascript test.describe.serial.only('focus two tests in serial mode', () => { test('one', async ({ page }) => {}) test('two', async ({ page }) => {}) }) ``` -------------------------------- ### Valid Describe Callback Example Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-describe-callback.md This demonstrates a correctly structured `describe()` callback function, which is asynchronous and does not contain parameters or return statements. ```javascript test.describe('myFunction()', () => { test('returns a truthy value', () => { expect(myFunction()).toBeTruthy() }) }) ``` -------------------------------- ### Commented Out Test Patterns Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-commented-out-tests.md These examples demonstrate patterns that the `no-commented-out-tests` rule will flag as warnings. ```javascript // describe('foo', () => {}); // test.describe('foo', () => {}); // test('foo', () => {}); // test.describe.skip('foo', () => {}); // test.skip('foo', () => {}); // test.describe['skip']('bar', () => {}); // test['skip']('bar', () => {}); /* test.describe('foo', () => {}); */ ``` -------------------------------- ### Correct nested describe calls (default max) Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/max-nested-describe.md This example demonstrates correct usage with nesting depth within the default limit of 5 describe blocks. ```javascript test.describe('foo', () => { test.describe('bar', () => { test('this test', async ({ page }) => {}) }) }) ``` -------------------------------- ### Incorrect `mustMatch` Usage Examples Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md These examples demonstrate incorrect usage of the `mustMatch` option, showing titles that violate the specified regular expressions. ```javascript // with mustMatch: '^that' test.describe('the correct way to do things', () => {}) test('this there!', () => {}) ``` ```javascript // with mustMatch: { test: '^that' } test.describe('the tests that will be run', () => {}) test('the stuff works', () => {}) test('errors that are thrown have messages', () => {}) ``` -------------------------------- ### Incorrect: Focused test Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-focused-test.md Example of a single test marked with `.only`. ```javascript test.only('focus this test', async ({ page }) => {}) ``` -------------------------------- ### Correct non-empty titles Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md Examples of correct code where test or describe block titles are non-empty strings. ```javascript test.describe('foo', () => {}) test.describe('foo', () => { test('bar', () => {}) }) test('foo', () => {}) ``` -------------------------------- ### Incorrect: Focused describe block in parallel mode Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-focused-test.md Example of a `describe.parallel` block marked with `.only`. ```javascript test.describe.parallel.only('focus two tests in parallel mode', () => { test('one', async ({ page }) => {}) test('two', async ({ page }) => {}) }) ``` -------------------------------- ### Correct Code: Using Allowed Locators Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-restricted-locators.md These examples show correct usage of locators when 'getByTestId' and 'getByTitle' are restricted. ```javascript test('find button', async () => { await page.getByRole('button', { name: 'Submit' }) }) ``` ```javascript test('find tooltip', async () => { await page.getByLabel('Additional info') }) ``` -------------------------------- ### Correct Playwright actions without force: true Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-force-option.md These examples show the correct way to use Playwright actions without the disallowed `{ force: true }` option. ```javascript await page.locator('button').click() await page.locator('check').check() await page.locator('input').fill('something') ``` -------------------------------- ### Correct: expect within it block Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-standalone-expect.md This example shows a valid use of `expect` within an `it` (or `test`) block. ```javascript test.describe('a test', () => { test('an it', () => { expect(1).toBe(1) }) }) ``` -------------------------------- ### Incorrect code with allowed `afterEach` hook Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-hooks.md This example is incorrect because it uses `test.beforeEach` but `afterEach` is allowed by the rule configuration. ```javascript /* eslint playwright/no-hooks: ["error", { "allow": ["afterEach"] }] */ function setupFoo(options) { /* ... */ } let foo test.beforeEach(() => { foo = setupFoo() }) test.afterEach(() => { playwright.resetModules() }) test('foo does this', () => { // ... }) test('foo does that', () => { // ... }) ``` -------------------------------- ### Disallow .skip() and .fixme() annotations Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-skipped-test.md Examples of incorrect code that violates the rule by using `.skip()` or `.describe.skip()`. ```javascript test.skip('skip this test', async ({ page }) => {}) ``` ```javascript test.describe.skip('skip two tests', () => { test('one', async ({ page }) => {}) test('two', async ({ page }) => {}) }) ``` ```javascript test.describe('skip test inside describe', () => { test.skip() }) ``` ```javascript test.describe('skip test conditionally', async ({ browserName }) => { test.skip(browserName === 'firefox', 'Working on it') }) ``` -------------------------------- ### Correct: Hooks Before Tests Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-hooks-on-top.md This example demonstrates the correct usage where all hooks are defined before any test cases within the `test.describe` block. This adheres to the `prefer-hooks-on-top` rule. ```javascript /* eslint playwright/prefer-hooks-on-top: "error" */ test.describe('foo', () => { test.beforeAll(() => { createMyDatabase() }) test.beforeEach(() => { seedMyDatabase() }) test.afterAll(() => { clearMyDatabase() }) test('accepts this input', () => { // ... }) test('returns that value', () => { // ... }) test.describe('when the database has specific values', () => { const specificValue = '...' beforeEach(() => { seedMyDatabase(specificValue) }) beforeEach(() => { mockLogger() }) afterEach(() => { clearLogger() }) test('accepts that input', () => { // ... }) test('throws an error', () => { // ... }) test('logs a message', () => { // ... }) }) }) ``` -------------------------------- ### Incorrect empty titles Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md Examples of incorrect code where test or describe block titles are empty strings. ```javascript test.describe('', () => {}) test.describe('foo', () => { test('', () => {}) }) test('', () => {}) ``` -------------------------------- ### Correct usage of Playwright locators and methods Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-useless-await.md These examples show the correct way to use Playwright locator methods and other methods like `page.$` or `page.goto` which might return Promises. `expect` assertions are also shown correctly when they do not wrap asynchronous operations. ```javascript page.locator('.my-element') page.getByRole('.my-element') await page.$('.my-element') await page.goto('.my-element') expect(1).toBe(1) expect(true).toBeTruthy() await expect(page.locator('.foo')).toBeVisible() await expect(page.locator('.foo')).toHaveText('bar') ``` -------------------------------- ### Correct usage of page locators Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-unused-locators.md These examples demonstrate valid uses of page locators: assigning to a variable, performing an action, or making an assertion. ```javascript const btn = page.getByRole('button', { name: 'Sign in' }) ``` ```javascript await page.getByRole('button', { name: 'Sign in' }).click() ``` ```javascript await expect(page.getByRole('button', { name: 'Sign in' })).toBeVisible() ``` -------------------------------- ### Incorrect: Duplicate beforeEach hooks Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-duplicate-hooks.md This example shows a describe block with two identical beforeEach hooks, which violates the rule. ```javascript /* eslint playwright/no-duplicate-hooks: "error" */ test.describe('foo', () => { test.beforeEach(() => { // some setup }) test.beforeEach(() => { // some setup }) test('foo_test', () => { // some test }) }) ``` -------------------------------- ### Configure ESLint Plugin Playwright with Flat Config Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/README.md Recommended setup for flat ESLint configuration. Targets Playwright test files and extends the recommended Playwright configuration. ```javascript import { defineConfig } from '@eslint/config' import playwright from 'eslint-plugin-playwright' export default defineConfig([ { files: ['tests/**'], extends: [playwright.configs['flat/recommended']], rules: { // Customize Playwright rules // ... }, }, ]) ``` -------------------------------- ### Incorrect: expect in describe block Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-standalone-expect.md This example shows an `expect` statement directly within a `test.describe` block, which is disallowed. ```javascript test.describe('a test', () => { expect(1).toBe(1) }) ``` -------------------------------- ### Incorrect usage of a page locator Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-unused-locators.md This example shows a locator being defined without any subsequent action or assertion, which will be flagged by the rule. ```javascript page.getByRole('button', { name: 'Sign in' }) ``` -------------------------------- ### Configure ESLint Plugin Playwright with Legacy Config Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/README.md Setup for legacy ESLint configuration. Overrides configurations to apply Playwright rules to specified files. ```json { "overrides": [ { "files": "tests/**", "extends": "plugin:playwright/recommended" } ] } ``` -------------------------------- ### Invalid Test Tag Examples Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-test-tags.md Illustrates common invalid test tag formats, specifically highlighting the missing '@' prefix. ```typescript test('my test', { tag: 'e2e' }, async ({ page }) => {}) // Missing @ prefix test('my test', { tag: ['e2e', 'login'] }, async ({ page }) => {}) // Missing @ prefix ``` -------------------------------- ### Incorrect: Using Instance Methods for Assertions Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-web-first-assertions.md These examples show the incorrect usage of instance methods like isVisible(), isEnabled(), and innerText() for assertions. These methods do not automatically wait for conditions, leading to less resilient tests. ```javascript expect(await page.locator('.tweet').isVisible()).toBe(true) expect(await page.locator('.tweet').isEnabled()).toBe(true) expect(await page.locator('.tweet').innerText()).toBe('bar') ``` -------------------------------- ### Valid Test Patterns Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-commented-out-tests.md These examples show valid test code patterns that are not flagged by the `no-commented-out-tests` rule. ```javascript describe('foo', () => {}) test.describe('foo', () => {}) test('foo', () => {}) test.describe.only('bar', () => {}) test.only('bar', () => {}) // foo('bar', () => {}); ``` -------------------------------- ### Disallow .fixme() annotations with disallowFixme option Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-skipped-test.md Examples of incorrect code when the `disallowFixme` option is enabled, disallowing `.fixme()` annotations. ```javascript test.fixme('temporarily disabled', async ({ page }) => {}) ``` ```javascript test.fixme() // marks all tests in the file as fixme ``` ```javascript test.describe.fixme('skip this describe', () => {}) ``` -------------------------------- ### Allow conditional .slow annotation with allowConditional: true Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-slowed-test.md Example of correct usage when `allowConditional` is `true`, demonstrating a conditionally applied `.slow` annotation based on `browserName`. ```javascript test('foo', ({ browserName }) => { test.slow(browserName === 'firefox', 'Still working on it') expect(1).toBe(1) }) ``` -------------------------------- ### Incorrect spacing with beforeEach and test.step Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/consistent-spacing-between-blocks.md This example demonstrates incorrect spacing within a test file that includes a beforeEach hook and nested test steps. The spacing between the hook and the test, and between the test steps, is inconsistent. ```javascript test.beforeEach(() => {}) test('example 3', () => { await test.step('first', async () => { expect(true).toBe(true) }) await test.step('second', async () => { expect(true).toBe(true) }) }) ``` -------------------------------- ### Configuration: Using assertFunctionNames Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/expect-expect.md Custom assertion function names can be configured using the 'assertFunctionNames' option. This example shows how to include 'assertScrolledToBottom' as a valid assertion. ```javascript /* eslint playwright/expect-expect: ["error", { "assertFunctionNames": ["assertScrolledToBottom"] }] */ function assertScrolledToBottom(page) { // ... } test('should scroll', async ({ page }) => { await assertScrolledToBottom(page) }) ``` -------------------------------- ### Correct spacing between test blocks Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/consistent-spacing-between-blocks.md This example shows the correct spacing where a blank line separates two distinct test blocks, adhering to the rule's requirements. ```javascript test('example 1', () => { expect(true).toBe(true) }) test('example 2', () => { expect(true).toBe(true) }) ``` -------------------------------- ### Correct usage of page.locator().evaluate and page.locator().evaluateAll Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-eval.md These examples show the recommended alternative methods for evaluating JavaScript within Playwright tests using `page.locator().evaluate()` and `page.locator().evaluateAll()`. ```javascript await page.locator('button').evaluate((node) => node.innerText) ``` ```javascript await page.locator('div').evaluateAll((divs, min) => divs.length >= min, 10) ``` -------------------------------- ### Correct: Using an allowed raw locator with allowed option Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-raw-locators.md This example shows the correct usage when the 'allowed' option is configured. The raw locator '[aria-busy="false"]' is permitted because it is included in the 'allowed' array in the rule's configuration. ```javascript page.getByRole('navigation').and(page.locator('[aria-busy="false"]')) ``` -------------------------------- ### Correct Use of Equality Matchers Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-equality-matcher.md Examples of code that correctly use Playwright's built-in equality matchers. ```javascript expect(x).toBe(5) expect(name).not.toEqual('Carl') expect(myObj).toStrictEqual(thatObj) ``` -------------------------------- ### Incorrect: Using an unallowed raw locator with allowed option Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-raw-locators.md This example demonstrates incorrect usage when the 'allowed' option is configured. The `page.locator('iframe')` is used in conjunction with `getByRole`, but 'iframe' is not explicitly allowed in this specific configuration context. ```javascript page.getByRole('navigation').and(page.locator('iframe')) ``` -------------------------------- ### Allow conditional skipping with allowConditional option Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-skipped-test.md Examples of incorrect code when `allowConditional` is true, showing disallowed conditional skips. ```javascript test.skip('foo', ({}) => { expect(1).toBe(1) }) ``` ```javascript test('foo', ({}) => { test.skip() expect(1).toBe(1) }) ``` -------------------------------- ### Correct titles with ignoreTypeOfDescribeName enabled Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md Examples of correct code when ignoreTypeOfDescribeName is true, allowing non-string describe block titles. ```javascript test('is a string', () => {}) test.describe('is a string', () => {}) test.describe(String(/.+/), () => {}) test.describe(myFunction, () => {}) test.describe(6, function () {}) ``` -------------------------------- ### Configure minArgs and maxArgs for expect() Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-expect.md Demonstrates how to configure the minArgs and maxArgs options for the valid-expect rule to enforce specific argument counts for expect() calls. ```json { "minArgs": 1, "maxArgs": 2 } ``` -------------------------------- ### Incorrect: Conditional logic with switch statement Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-conditional-in-test.md This example demonstrates an incorrect use of a 'switch' statement within a test function. ```javascript test('bar', async ({ page }) => { switch (mode) { case 'single': generateOne() break case 'double': generateTwo() break case 'multiple': generateMany() break } await expect(page.locator('.my-image').count()).toBeGreaterThan(0) }) ``` -------------------------------- ### Incorrect Code: Using Restricted Locators Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-restricted-locators.md These examples demonstrate incorrect usage of locators restricted by the 'no-restricted-locators' rule. ```javascript test('find button', async () => { await page.getByTestId('submit-button') }) ``` ```javascript test('find tooltip', async () => { await page.getByTitle('Additional info') }) ``` -------------------------------- ### Incorrect expect() calls Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-expect.md Examples of code that violates the valid-expect rule, showing calls to expect() without a matcher or with incorrect arguments. ```javascript expect() expect('something') expect(true).toBeDefined ``` -------------------------------- ### Incorrect: expect after test block Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-standalone-expect.md This example demonstrates an `expect` statement placed after a `test` block within the same `describe` block, which is also disallowed. ```javascript test.describe('a test', () => { test('an it', () => { expect(1).toBe(1) }) expect(1).toBe(1) }) ``` -------------------------------- ### Use alternative waiting mechanisms Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-wait-for-timeout.md This snippet demonstrates correct alternatives to `page.waitForTimeout`, such as waiting for load states, URLs, or function conditions. ```javascript // Use signals such as network events, selectors becoming visible and others instead. await page.waitForLoadState() ``` ```javascript await page.waitForURL('/home') ``` ```javascript await page.waitForFunction(() => window.innerWidth < 100) ``` -------------------------------- ### Correct: expect within a helper function Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-standalone-expect.md This example illustrates the allowed use of `expect` within a helper function that is called from a `test` block. ```javascript test.describe('a test', () => { const helper = () => { expect(1).toBe(1) } test('an it', () => { helper() }) }) ``` -------------------------------- ### Correct: Using getByRole with name option Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-raw-locators.md This example shows how to use `page.getByRole()` with an options object to specify the accessible name, further improving locator specificity and robustness. ```javascript await page.getByRole('button', { name: 'Submit', }) ``` -------------------------------- ### Page methods triggering warnings Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-locator.md These examples show direct usage of page methods with selectors that violate the rule. Use locators instead. ```javascript page.click('css=button') ``` ```javascript await page.click('css=button') ``` ```javascript await page.dblclick('xpath=//button') ``` ```javascript await page.fill('input[type="password"]', 'password') ``` ```javascript await page.frame('frame-name').click('css=button') ``` -------------------------------- ### Incorrect: Intermixed Hooks and Tests Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-hooks-on-top.md This example shows incorrect usage where hooks are placed after test cases, leading to potential confusion. It violates the `prefer-hooks-on-top` rule. ```javascript /* eslint playwright/prefer-hooks-on-top: "error" */ test.describe('foo', () => { test.beforeEach(() => { seedMyDatabase() }) test('accepts this input', () => { // ... }) test.beforeAll(() => { createMyDatabase() }) test('returns that value', () => { // ... }) test.describe('when the database has specific values', () => { const specificValue = '...' test.beforeEach(() => { seedMyDatabase(specificValue) }) test('accepts that input', () => { // ... }) test('throws an error', () => { // ... }) test.afterEach(() => { clearLogger() }) test.beforeEach(() => { mockLogger() }) test('logs a message', () => { // ... }) }) test.afterAll(() => { removeMyDatabase() }) }) ``` -------------------------------- ### Correct: Using Web First Assertions Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-web-first-assertions.md These examples demonstrate the correct usage of Playwright's web-first assertions like toBeVisible(), toBeEnabled(), and toHaveText(). These assertions automatically wait for the specified conditions, improving test resilience. ```javascript await expect(page.locator('.tweet')).toBeVisible() await expect(page.locator('.tweet')).toBeEnabled() await expect(page.locator('.tweet')).toHaveText('bar') ``` -------------------------------- ### Correct: Conditional test definition Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-conditional-in-test.md This example shows the correct way to conditionally define a test using 'test.describe' and an 'if' statement outside the test body. ```javascript test.describe('my tests', () => { if (someCondition) { test('foo', async ({ page }) => { bar() }) } }) ``` -------------------------------- ### Corrected Code with Allowed Function Calls Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/require-hook.md This example demonstrates correct usage when the `allowedFunctionCalls` option is configured, showing `enableAutoDestroy` being called outside a hook. ```javascript /* eslint playwright/require-hook: ["error", { "allowedFunctionCalls": ["enableAutoDestroy"] }] */ enableAutoDestroy(test.afterEach) test.beforeEach(initDatabase) test.afterEach(tearDownDatabase) test.describe('Foo', () => { test('always returns 42', () => { expect(global.getAnswer()).toBe(42) }) }) ``` -------------------------------- ### Correct Hook Order Example Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-hooks-in-order.md Illustrates the correct ordering of Playwright hooks, adhering to the `beforeAll`, `beforeEach`, `afterEach`, `afterAll` sequence within `test.describe` blocks and nested structures. This code passes the `prefer-hooks-in-order` rule. ```javascript /* eslint playwright/prefer-hooks-in-order: "error" */ test.describe('foo', () => { test.beforeAll(() => { createMyDatabase() }) test.beforeEach(() => { seedMyDatabase() }) test('accepts this input', () => { // ... }) test('returns that value', () => { // ... }) test.describe('when the database has specific values', () => { const specificValue = '...' test.beforeEach(() => { seedMyDatabase(specificValue) }) test('accepts that input', () => { // ... }) test('throws an error', () => { // ... }) test.beforeEach(() => { mockLogger() }) test.afterEach(() => { clearLogger() }) test('logs a message', () => { // ... }) }) test.afterAll(() => { removeMyDatabase() }) }) ``` -------------------------------- ### Incorrect number comparisons Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-comparison-matcher.md Examples of test code that violate the prefer-comparison-matcher rule. ```javascript expect(x > 5).toBe(true) expect(x < 7).not.toEqual(true) expect(x <= y).toStrictEqual(true) ``` -------------------------------- ### Run Tests Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/CONTRIBUTING.md Executes the project's test suite. This is essential for verifying changes to lint rules. ```bash yarn test ``` -------------------------------- ### Incorrect nested describe calls Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/max-nested-describe.md This example shows code that violates the rule with more than the default maximum of 5 nested describe blocks. ```javascript test.describe('foo', () => { test.describe('bar', () => { test.describe('baz', () => { test.describe('qux', () => { test.describe('quxx', () => { test.describe('too many', () => { test('this test', async ({ page }) => {}) }) }) }) }) }) }) ``` -------------------------------- ### Incorrect Playwright actions with force: true Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-force-option.md These examples demonstrate incorrect usage of Playwright actions by including the `{ force: true }` option, which is disallowed by the rule. ```javascript await page.locator('button').click({ force: true }) await page.locator('check').check({ force: true }) await page.locator('input').fill('something', { force: true }) ``` -------------------------------- ### Correct usage avoiding restricted roles Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-restricted-roles.md Examples of code that adheres to the `no-restricted-roles` rule by using alternative selectors or asserting on specific content instead of restricted roles. ```javascript test('wait for loading', async () => { // Assert on the actual content that should appear after loading await expect(page.getByRole('table')).toBeVisible() }) ``` ```javascript test('check alert', async () => { // Assert on the specific alert text await expect(page.getByText('Operation completed')).toBeVisible() }) ``` -------------------------------- ### Disallow page.waitForSelector Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-wait-for-selector.md This is an example of incorrect code that violates the rule. It directly uses `page.waitForSelector`. ```javascript await page.waitForSelector('#foo') ``` -------------------------------- ### Incorrect usage of page.$eval and page.$$eval Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-eval.md These examples demonstrate incorrect usage of `page.$eval` and `page.$$eval` which are disallowed by the rule. ```javascript const searchValue = await page.$eval('#search', (el) => el.value) ``` ```javascript const divCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10) ``` ```javascript await page.$eval('#search', (el) => el.value) await page.$$eval('#search', (el) => el.value) ``` -------------------------------- ### Configuring `valid-title` with Custom Messages Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md This example shows how to configure the `valid-title` rule with custom messages for `mustNotMatch` and `mustMatch` rules, including specific regular expressions for `describe` and `test` blocks. ```javascript const prefixes = ['when', 'with', 'without', 'if', 'unless', 'for'] const prefixesList = prefixes.join(' - \n') module.exports = { rules: { 'playwright/valid-title': [ 'error', { mustNotMatch: ['\\.$', 'Titles should not end with a full-stop'], mustMatch: { describe: [ new RegExp(`^(?:[A-Z]|\b(${prefixes.join('|')})\b`, 'u').source, `Describe titles should either start with a capital letter or one of the following prefixes: ${prefixesList}`, ], test: /[^A-Z]/u.source, }, }, ], }, } ``` -------------------------------- ### Disallow .slow annotation Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-slowed-test.md Examples of incorrect usage of the `.slow` annotation in Playwright tests. ```javascript test.slow('slow this test', async ({ page }) => {}) test.describe('slow test inside describe', () => { test.slow() }) test.describe('slow test conditionally', async ({ browserName }) => { test.slow(browserName === 'firefox', 'Working on it') }) ``` -------------------------------- ### Examples of Valid Expect Counts Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/max-expects.md These code snippets illustrate tests that do not exceed the default maximum of 5 expect() calls and are therefore not considered warnings by the max-expects rule. ```javascript test('shout pass') test('shout pass', () => {}) ``` ```javascript test.skip('shout pass', () => {}) ``` ```javascript test('should pass', function () { expect(true).toBeDefined() }) ``` ```javascript test('should pass', () => { expect(true).toBeDefined() expect(true).toBeDefined() expect(true).toBeDefined() expect(true).toBeDefined() expect(true).toBeDefined() }) ``` -------------------------------- ### Incorrect: Duplicate afterAll hooks in nested describe Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-duplicate-hooks.md This example demonstrates duplicate afterAll hooks within a nested describe block, which is also flagged by the rule. ```javascript /* eslint playwright/no-duplicate-hooks: "error" */ // Nested describe scenario test.describe('foo', () => { test.beforeEach(() => { // some setup }) test('foo_test', () => { // some test }) test.describe('bar', () => { test('bar_test', () => { test.afterAll(() => { // some teardown }) test.afterAll(() => { // some teardown }) }) }) }) ``` -------------------------------- ### Example of Exceeding Max Expects Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/max-expects.md This code snippet demonstrates a test that exceeds the default maximum of 5 expect() calls, which would be flagged as a warning by the max-expects rule. ```javascript test('should not pass', () => { expect(true).toBeDefined() expect(true).toBeDefined() expect(true).toBeDefined() expect(true).toBeDefined() expect(true).toBeDefined() expect(true).toBeDefined() }) ``` -------------------------------- ### Disallow networkidle in waitForLoadState, waitForURL, and goto Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-networkidle.md Examples of incorrect code that use the `networkidle` option. This rule aims to prevent its usage in favor of web-first assertions. ```javascript await page.waitForLoadState('networkidle') await page.waitForURL('...', { waitUntil: 'networkidle' }) await page.goto('...', { waitUntil: 'networkidle' }) ``` -------------------------------- ### Disallow .slow annotation with allowConditional: true Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-slowed-test.md Examples of incorrect usage when `allowConditional` is set to `true`, specifically when `.slow()` is used directly or conditionally without a valid condition. ```javascript test.slow('foo', ({}) => { expect(1).toBe(1) }) test('foo', ({}) => { test.slow() expect(1).toBe(1) }) ``` -------------------------------- ### Incorrect non-string titles Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md Examples of incorrect code where test or describe block titles are not strings. ```javascript test(123, () => {}) test.describe(String(/.+/), () => {}) test.describe(myFunction, () => {}) test.describe(6, function () {}) const title = 123 test(title, () => {}) ``` -------------------------------- ### Incorrect: Standard Assertions Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/require-soft-assertions.md Examples of standard Playwright assertions that do not use the soft assertion API. ```javascript await expect(page.locator('foo')).toHaveText('bar') await expect(page).toHaveTitle('baz') ``` -------------------------------- ### Correct code avoiding Playwright hooks Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-hooks.md This example shows the correct way to structure tests without using `beforeEach` or `afterEach` hooks, ensuring test isolation. ```javascript /* eslint playwright/no-hooks: "error" */ function setupFoo(options) { /* ... */ } function setupBar(options) { /* ... */ } test.describe('foo', () => { test('does something', () => { const foo = setupFoo() expect(foo.doesSomething()).toBe(true) }) test('does something with bar', () => { const foo = setupFoo() const bar = setupBar() expect(foo.doesSomething(bar)).toBe(true) }) }) ``` -------------------------------- ### Configuration for max-expects Rule Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/max-expects.md This JSON configuration shows how to enable the max-expects rule and set a custom maximum number of expect() calls to 5. ```json { "playwright/max-expects": [ "error", { "max": 5 } ] } ``` -------------------------------- ### Correct: Test without conditional logic Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-conditional-in-test.md This is a correct example of a test that does not contain any conditional logic. ```javascript test('bar', async ({ page }) => { await expect(page.locator('.my-image').count()).toBeGreaterThan(0) }) ``` -------------------------------- ### Configuration for allowing specific hooks Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-hooks.md This JSON configuration shows how to allow `afterEach` hooks while still enforcing the rule for other hooks. ```json { "playwright/no-hooks": [ "error", { "allow": ["afterEach", "afterAll"] } ] } ``` -------------------------------- ### Valid Test Tag Examples Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-test-tags.md Demonstrates various valid ways to apply test tags in Playwright tests, including single tags, arrays of tags, and usage with test.skip, test.fixme, and test.only. ```typescript test('my test', { tag: '@e2e' }, async ({ page }) => {}) test('my test', { tag: ['@e2e', '@login'] }, async ({ page }) => {}) test.describe('my suite', { tag: '@regression' }, () => {}) test.step('my step', { tag: '@critical' }, async () => {}) ``` ```typescript test.skip('my test', { tag: '@e2e' }, async ({ page }) => {}) test.fixme('my test', { tag: '@e2e' }, async ({ page }) => {}) test.only('my test', { tag: '@e2e' }, async ({ page }) => {}) ``` ```typescript test( 'my test', { tag: '@e2e', annotation: { type: 'issue', description: 'BUG-123' }, }, async ({ page }) => {}, ) ``` ```typescript test( 'my test', { tag: '@e2e', annotation: [{ type: 'issue', description: 'BUG-123' }, { type: 'flaky' }], }, async ({ page }) => {}, ) ``` -------------------------------- ### Configuration: Allowing specific raw locators Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-raw-locators.md This JSON configuration shows how to allow specific raw locators, such as 'iframe' or '[aria-busy=\'false\']', which might be necessary when no suitable ARIA role exists. ```json { "playwright/no-raw-locators": [ "error", { "allowed": ["iframe", "[aria-busy='false']"] } ] } ``` -------------------------------- ### Correct: Soft Assertions Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/require-soft-assertions.md Examples of Playwright assertions using the soft assertion API, as enforced by the rule. ```javascript await expect.soft(page.locator('foo')).toHaveText('bar') await expect.soft(page).toHaveTitle('baz') ``` -------------------------------- ### Correct Usage with `page.locator()` Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-element-handle.md Shows the recommended way to interact with elements using `page.locator()`, which provides auto-waiting and improves test stability. ```javascript const buttonLocator = page.locator('button') await buttonLocator.click() ``` -------------------------------- ### Incorrect: Nested test.step() Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-nested-step.md This example shows a violation of the rule where a test.step() is nested inside another test.step(). ```javascript test('foo', async () => { await test.step('step1', async () => { await test.step('nest step', async () => { await expect(true).toBe(true) }) }) }) ``` -------------------------------- ### Correct: Lowercase test description Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-lowercase-title.md This pattern is considered correct as the test description starts with a lowercase letter. ```javascript test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3) }) ``` -------------------------------- ### Warning: Uppercase test description Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/prefer-lowercase-title.md This pattern triggers a warning because the test description starts with an uppercase letter. ```javascript test('Adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3) }) ``` -------------------------------- ### Correct titles with disallowed words Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md Examples of correct code where test titles avoid words from the disallowedWords list. ```javascript // with disallowedWords: ['correct', 'all', 'every', 'properly'] test('correctly sets the value', () => {}) test('that everything is as it should be', () => {}) test.describe('the proper way to handle things', () => {}) ``` -------------------------------- ### Incorrect titles with disallowed words Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/valid-title.md Examples of incorrect code where test titles contain words from the disallowedWords list. ```javascript // with disallowedWords: ['correct', 'all', 'every', 'properly'] test.describe('the correct way to do things', () => {}) test.describe('every single one of them', () => {}) test('has ALL the things', () => {}) test(`that the value is set properly`, () => {}) ``` -------------------------------- ### Configuration: String Format for Restricted Locators Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-restricted-locators.md This JSON configuration restricts locators using only their method names as strings. ```json { "playwright/no-restricted-locators": ["error", ["getByTestId", "getByTitle"]] } ``` -------------------------------- ### Incorrect: Conditional logic with if statement Source: https://github.com/mskelton/eslint-plugin-playwright/blob/main/docs/rules/no-conditional-in-test.md This example shows an incorrect use of an 'if' statement within a test function. ```javascript test('foo', async ({ page }) => { if (someCondition) { bar() } }) ```