ESLint Plugin Playwright

February 27, 2026 ยท View on GitHub

CI npm semantic-release

ESLint plugin for Playwright.

Installation

npm

npm install -D eslint-plugin-playwright

Yarn

yarn add -D eslint-plugin-playwright

pnpm

pnpm add -D eslint-plugin-playwright

Usage

The recommended setup is to use the files field to target only Playwright test files. In the examples below, this is done by targeting files in the tests directory and only applying the Playwright rules to those files. In your project, you may need to change the files field to match your Playwright test file patterns.

Flat config (eslint.config.js)

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
      // ...
    },
  },
])

Legacy config (.eslintrc)

{
  "overrides": [
    {
      "files": "tests/**",
      "extends": "plugin:playwright/recommended"
    }
  ]
}

Settings

Aliased Playwright Globals

If you import Playwright globals (e.g. test, expect) with a custom name, you can configure this plugin to be aware of these additional names.

{
  "settings": {
    "playwright": {
      "globalAliases": {
        "test": ["it"],
        "expect": ["assert"]
      }
    }
  }
}

Custom Messages

You can customize the error messages for rules using the settings.playwright.messages property. This is useful if you would like to increase the verbosity of error messages or provide additional context.

Only the message ids you define in this setting will be overridden, so any other messages will use the default message defined by the plugin.

{
  "settings": {
    "playwright": {
      "messages": {
        "conditionalExpect": "Avoid conditional expects as they can lead to false positives"
      }
    }
  }
}

Rules

โœ… Set in the recommended configuration
๐Ÿ”ง Automatically fixable by the --fix CLI option
๐Ÿ’ก Manually fixable by editor suggestions

RuleDescriptionโœ…๐Ÿ”ง๐Ÿ’ก
consistent-spacing-between-blocksEnforce consistent spacing between test blocksโœ…๐Ÿ”ง
expect-expectEnforce assertion to be made in a test bodyโœ…
max-expectsEnforces a maximum number assertion calls in a test body
max-nested-describeEnforces a maximum depth to nested describe callsโœ…
missing-playwright-awaitEnforce Playwright APIs to be awaitedโœ…๐Ÿ”ง
no-commented-out-testsDisallow commented out tests
no-conditional-expectDisallow calling expect conditionallyโœ…
no-conditional-in-testDisallow conditional logic in testsโœ…
no-duplicate-hooksDisallow duplicate setup and teardown hooksโœ…
no-duplicate-slowDisallow multiple test.slow() calls in the same testโœ…
no-element-handleDisallow usage of element handlesโœ…๐Ÿ’ก
no-evalDisallow usage of page.$eval() and page.$$eval()โœ…
no-focused-testDisallow usage of .only annotationโœ…๐Ÿ’ก
no-force-optionDisallow usage of the { force: true } optionโœ…
no-get-by-titleDisallow using getByTitle()
no-hooksDisallow setup and teardown hooks
no-nested-stepDisallow nested test.step() methodsโœ…
no-networkidleDisallow usage of the networkidle optionโœ…
no-nth-methodsDisallow usage of first(), last(), and nth() methods
no-page-pauseDisallow using page.pause()โœ…
no-raw-locatorsDisallow using raw locators
no-restricted-locatorsDisallow specific locator methods
no-restricted-matchersDisallow specific matchers & modifiers
no-restricted-rolesDisallow specific roles in getByRole()
no-skipped-testDisallow usage of the .skip annotationโœ…๐Ÿ’ก
no-slowed-testDisallow usage of the .slow annotation๐Ÿ’ก
no-standalone-expectDisallow using expect outside of test blocksโœ…๐Ÿ”ง
no-unsafe-referencesPrevent unsafe variable references in page.evaluate()โœ…๐Ÿ”ง
no-unused-locatorsDisallow usage of page locators that are not usedโœ…
no-useless-awaitDisallow unnecessary awaits for Playwright methodsโœ…๐Ÿ”ง
no-useless-notDisallow usage of not matchers when a specific matcher existsโœ…๐Ÿ”ง
no-wait-for-navigationDisallow usage of page.waitForNavigation()โœ…๐Ÿ’ก
no-wait-for-selectorDisallow usage of page.waitForSelector()โœ…๐Ÿ’ก
no-wait-for-timeoutDisallow usage of page.waitForTimeout()โœ…๐Ÿ’ก
prefer-comparison-matcherSuggest using the built-in comparison matchers๐Ÿ”ง
prefer-equality-matcherSuggest using the built-in equality matchers๐Ÿ’ก
prefer-hooks-in-orderPrefer having hooks in a consistent orderโœ…
prefer-hooks-on-topSuggest having hooks before any test casesโœ…
prefer-lowercase-titleEnforce lowercase test names๐Ÿ”ง
prefer-native-locatorsSuggest built-in locators over page.locator()๐Ÿ”ง
prefer-locatorSuggest locators over page methodsโœ…
prefer-strict-equalSuggest using toStrictEqual()๐Ÿ”ง๐Ÿ’ก
prefer-to-beSuggest using toBe()๐Ÿ”ง
prefer-to-containSuggest using toContain()๐Ÿ”ง
prefer-to-have-countSuggest using toHaveCount()โœ…๐Ÿ”ง
prefer-to-have-lengthSuggest using toHaveLength()โœ…๐Ÿ”ง
prefer-web-first-assertionsSuggest using web first assertionsโœ…๐Ÿ”ง
require-hookRequire setup and teardown code to be within a hook
require-soft-assertionsRequire assertions to use expect.soft()๐Ÿ”ง
require-tagsRequire test blocks to have tags
require-to-pass-timeoutRequire a timeout option for toPass()
require-to-throw-messageRequire a message for toThrow()
require-top-level-describeRequire test cases and hooks to be inside a test.describe block
valid-describe-callbackEnforce valid describe() callbackโœ…
valid-expect-in-promiseRequire promises that have expectations in their chain to be validโœ…
valid-expectEnforce valid expect() usageโœ…
valid-titleEnforce valid titlesโœ…๐Ÿ”ง
valid-test-tagsEnforce valid tag format in test blocksโœ