Home

Awesome

ESLint Plugin Playwright

Test 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

This plugin bundles two configurations to work with both @playwright/test or jest-playwright. 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.

With Playwright test runner

Flat config (eslint.config.js)

import playwright from 'eslint-plugin-playwright'

export default [
  {
    ...playwright.configs['flat/recommended'],
    files: ['tests/**'],
  },
  {
    files: ['tests/**'],
    rules: {
      // Customize Playwright rules
      // ...
    },
  },
]

Legacy config (.eslintrc)

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

With Jest Playwright

Flat config (eslint.config.js)

import playwright from 'eslint-plugin-playwright'
import jest from 'eslint-plugin-jest'

export default [
  {
    ...playwright.configs['flat/jest-playwright'],
    files: ['tests/**'],
  },
  {
    files: ['tests/**'],
    plugins: { jest },
    rules: {
      // Customize Playwright rules
      // ...
    },
  },
]

Legacy config (.eslintrc)

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

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": ["myTest"],
        "expect": ["myExpect"]
      }
    }
  }
}

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🔧💡
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-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-matchersDisallow specific matchers & modifiers
no-skipped-testDisallow usage of the .skip annotation💡
no-standalone-expectDisallow using expect outside of test blocks
no-unsafe-referencesPrevent unsafe variable references in page.evaluate()🔧
no-useless-awaitDisallow unnecessary awaits for Playwright methods🔧
no-useless-notDisallow usage of not matchers when a specific matcher exists🔧
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-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-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🔧