@vitest/eslint-plugin

repository·main·Indexed 19 days ago

https://github.com/vitest-dev/eslint-plugin-vitest

An ESLint plugin for Vitest (version 1.6.26) that provides rules to enforce testing best practices, improve test consistency, and catch common mistakes in Vitest test suites. It includes configurations for ESLint v9+ (Flat Config) and v8 or lower, support for type-testing, and rules covering consistency, expectations, structure, matchers, and snapshots.

Tokens
33.4K
Snippets
134
Records
144
Agent score
65%

What's inside @vitest/eslint-plugin

  1. Use Shareable Configurations: Recommended and All

    main

    The plugin provides two main pre-configured sets of rules:

    1. Recommended: Enforces good testing practices. Use vitest.configs.recommended.
    2. All: Enables every available rule in the plugin. Use vitest.configs.all.

    In ESLint Flat Config, you can spread these directly into your configuration object.

    // Recommended
    import vitest from '@vitest/eslint-plugin'
    export default defineConfig({
      ...vitest.configs.recommended,
    })
    
    // All
    import vitest from '@vitest/eslint-plugin'
    export default defineConfig({
      ...vitest.configs.all,
    })
  2. Use the vitest/prefer-called-once rule

    main

    The vitest/prefer-called-once rule enforces more semantic and readable Vitest assertions by requiring the use of toBeCalledOnce() or toHaveBeenCalledOnce() instead of passing 1 to toBeCalledTimes(1) or toHaveBeenCalledTimes(1) most common cases.

    This rule is automatically fixable using the ESLint --fix CLI option.

    // Incorrect
    test('foo', () => {
      const mock = vi.fn()
      mock('foo')
      expect(mock).toBeCalledTimes(1)
      expect(mock).toHaveBeenCalledTimes(1)
    })
    
    // Correct
    test('foo', () => {
      const mock = vi.fn()
      mock('foo')
      expect(mock).toBeCalledOnce()
      expect(mock).toHaveBeenCalledOnce()
    })
  3. Enable Type-Testing support

    main

    If you use Vitest's type-testing feature, you must enable typecheck: true in the plugin settings. This allows rules like expect-expect to correctly account for type-related assertions. This requires a TypeScript parser with projectService: true (or similar) configured in languageOptions.

    import { defineConfig } from 'eslint/config'
    import tseslint from 'typescript-eslint'
    import vitest from '@vitest/eslint-plugin'
    
    export default defineConfig(
      tseslint.configs.recommended,
      {
        languageOptions: {
          parserOptions: {
            projectService: true,
          },
        },
      },
      {
        files: ['tests/**'],
        plugins: {
          vitest,
        },
        rules: {
          ...vitest.configs.recommended.rules,
        },
        settings: {
          vitest: {
            typecheck: true,
          },
        },
        languageOptions: {
          globals: {
            ...vitest.environments.env.globals,
          },
        },
      },
    )
  4. Enable typechecking for vitest ESLint rules

    main

    If you want to use function or class names as parameters inside describe, test, or it blocks, you must enable Vitest's type checking in your ESLint configuration settings. This allows the rule to correctly resolve the types of the arguments.

    import vitest from 'eslint-plugin-vitest'
    
    export default [
      {
        files: ['tests/**'],
        plugins: {
          vitest,
        },
        rules: {
          ...vitest.configs.recommended.rules,
        },
        settings: {
          vitest: {
            typecheck: true,
          },
        },
      },
    ]
  5. Enforce valid titles with vitest/valid-title

    main

    The vitest/valid-title rule enforces valid string titles for describe, it, and test functions. This rule is included in the recommended configuration and is automatically fixable using the ESLint --fix option.

    This rule helps prevent empty, purely numeric, or poorly formatted test titles, and can be used to ban specific words (like skip or only) from being used in title strings.

    {
      "vitest/valid-title": [
        "error",
        {
          "ignoreTypeOfDescribeName": false,
          "allowArguments": false,
          "disallowedWords": ["skip", "only"],
          "mustNotMatch": ["^\\s+$", "^\\s*\\d+\\s*$"],
          "mustMatch": ["^\\s*\\w+\\s*$"]
        }
      ]
    }
  6. Configure @vitest/eslint-plugin with ESLint v9+

    main

    For ESLint version v9.0.0 or higher, use the Flat Config format (eslint.config.js). You can import the plugin and apply its recommended or all rules. You can also customize specific rule behaviors using the standard ESLint rule object format.

    import { defineConfig } from 'eslint/config'
    import vitest from '@vitest/eslint-plugin'
    
    export default defineConfig({
      files: ['tests/**'], // or any other pattern
      plugins: {
        vitest,
      },
      rules: {
        ...vitest.configs.recommended.rules, // or vitest.configs.all.rules
        'vitest/max-nested-describe': ['error', { max: 3 }],
      },
    })
  7. Configure @vitest/eslint-plugin with ESLint v8 or lower

    main

    For legacy ESLint configurations (version v8.57.0 or lower), add @vitest to your plugins array in your .eslintrc file and configure rules using the @vitest/ prefix. You can also use the legacy recommended configurations via the extends key.

    {
      "plugins": ["@vitest"],
      "rules": {
        "@vitest/max-nested-describe": [
          "error",
          {
            "max": 3
          }
        ]
      }
    }

    To use legacy recommended configurations:

    {
      "extends": ["plugin:@vitest/legacy-recommended"]
    }
  8. Use the vitest/unbound-method rule

    main

    The vitest/unbound-method rule enforces that unbound methods are called with their expected scope. It is an extension of the @typescript-eslint/unbound-method rule, specifically adding support for cases where it is acceptable to pass an unbound method to Vitest expect calls.

    Requirements:

    • You must have @typescript-eslint/eslint-plugin installed and configured.
    • This rule requires type information to function, so you must configure your ESLint parser with parserOptions.project pointing to your tsconfig.json.

    To avoid conflicts, it is recommended to turn off the base @typescript-eslint/unbound-method rule for your test files and enable vitest/unbound-method instead.

    {
      parser: '@typescript-eslint/parser',
      parserOptions: {
        project: 'tsconfig.json',
        ecmaVersion: 2020,
        sourceType: 'module',
      },
      overrides: [
        {
          files: ['test/**'],
          plugins: ['vitest'],
          rules: {
            '@typescript-eslint/unbound-method': 'off',
            'vitest/unbound-method': 'error',
          },
        },
      ],
      rules: {
        '@typescript-eslint/unbound-method': 'error',
      },
    }
  9. Use the vitest/prefer-comparison-matcher rule

    main

    The vitest/prefer-comparison-matcher rule enforces the use of Vitest's built-in comparison matchers instead of checking boolean results of comparison expressions. This improves test readability and provides better error messages when assertions fail.

    Supported Matchers:

    • toBeGreaterThan
    • toBeGreaterThanOrEqual
    • toBeLessThan
    • toBeLessThanOrEqual

    Note on Severity: This rule emits a warning when using the all shareable configuration.

    Auto-fixable: This rule can be automatically fixed using the ESLint --fix CLI option.

    // Incorrect
    expect(x > 5).toBe(true)
    expect(x < 7).not.toEqual(true)
    expect(x <= y).toStrictEqual(true)
    
    // Correct
    expect(x).toBeGreaterThan(5)
    expect(x).not.toBeLessThanOrEqual(7)
    expect(x).toBeLessThanOrEqual(y)