eslint-vitest-rule-tester

Help users test ESLint rules with Vitest, supporting snapshot testing and custom assertions

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "eslint-vitest-rule-tester" with this command: npx skills add antfu-collective/eslint-vitest-rule-tester/antfu-collective-eslint-vitest-rule-tester-eslint-vitest-rule-tester

Instructions

You are helping users work with eslint-vitest-rule-tester, a library that provides ESLint rule testing with Vitest integration.

Core APIs

Two testing approaches:

  1. run({ name, rule, valid, invalid, ...config }) - All-in-one object style (config directly in object)
  2. createRuleTester({ name, rule, configs }) - Returns { valid, invalid } for explicit Vitest describe/it blocks (note: configs key, not languageOptions)

Key extensions:

  • output and errors fields can be functions for custom assertions and snapshots
  • onResult hook for full result object validation
  • No globals: true required in Vitest config

When Helping Users

Identify testing style first:

  • Check if they have existing tests to match their pattern
  • Default to run() for simplicity (see Pattern 1 below)
  • Use createRuleTester() for explicit Vitest test blocks with individual it() tests (Pattern 3)

Configuration:

  • Use languageOptions.parser: tsParser for TypeScript (import from @typescript-eslint/parser)
  • Use languageOptions.parserOptions for JS options (ecmaVersion, sourceType)
  • Put shared config in tester initialization, not in every test case
  • Note: In createRuleTester, config goes under configs key, not at top level

Type safety:

  • Use satisfies TestCasesOptions['valid'] for valid test arrays
  • Use satisfies TestCasesOptions['invalid'] for invalid test arrays
  • Extract test cases as constants before passing to run() (see Pattern 1)

Snapshots:

  • Use onResult hook with toMatchSnapshot() for all invalid cases (Pattern 1)
  • Use function-based output/errors with toMatchInlineSnapshot() for inline snapshots (Pattern 2)
  • Recommend toMatchInlineSnapshot() over toMatchSnapshot() when possible for better visibility

Common patterns:

// Pattern 1: run() with extracted test cases (from top-level-function.test.ts)
import type { TestCasesOptions } from 'eslint-vitest-rule-tester'
import { run } from 'eslint-vitest-rule-tester'
import { expect } from 'vitest'
import * as tsParser from '@typescript-eslint/parser'

const valids = [
  'function foo() {}',
  // allow arrow function inside function
  'function foo() { const bar = () => {} }',
] satisfies TestCasesOptions['valid']

const invalids = [
  {
    code: 'const foo = () => {}',
    output: 'function foo () {}',
    errors: [{ messageId: 'topLevelFunctionDeclaration' }],
  },
] satisfies TestCasesOptions['invalid']

run({
  name: 'top-level-function',
  rule,
  languageOptions: { parser: tsParser },
  valid: valids,
  invalid: invalids,
  onResult(_case, result) {
    if (_case.type === 'invalid')
      expect(result.output).toMatchSnapshot()
  },
})

// Pattern 2: Function-based output/errors (from README)
run({
  name: 'rule-name',
  rule,
  invalid: [
    {
      code: 'let foo = 1',
      output(output) {
        expect(output.slice(0, 3)).toBe('let')
        expect(output).toMatchInlineSnapshot(`"const foo = 1;"`)
      },
      errors(errors) {
        expect(errors).toHaveLength(1)
        expect(errors.map(e => e.messageId))
          .toMatchInlineSnapshot(`["preferConst"]`)
      },
    },
  ],
})

// Pattern 3: Explicit test suites (from README)
import { createRuleTester } from 'eslint-vitest-rule-tester'
import { describe, it } from 'vitest'

describe('rule-name', () => {
  const { valid, invalid } = createRuleTester({
    name: 'rule-name',
    rule,
    configs: {
      languageOptions: {
        parserOptions: { ecmaVersion: 2020, sourceType: 'module' },
      },
    },
  })

  it('valid case 1', () => {
    valid('const foo = 1')
  })

  it('invalid case 1 with snapshot', async () => {
    const { result } = await invalid({
      code: 'const foo = 1',
      errors: ['error-message-id'],
    })
    expect(result.output).toMatchSnapshot()
  })
})

Troubleshooting

  • Version errors: Requires ESLint v9.10+, check package.json
  • Snapshot failures: Run vitest -u to update snapshots
  • Parser issues: Add languageOptions.parser for TypeScript/JSX
  • Type errors: Import from eslint-vitest-rule-tester, not eslint

Best Practices

  • Match existing patterns - Check existing test files in the project first
  • Extract test cases - Define valids and invalids as constants with satisfies for type safety
  • Add comments - Use inline comments to explain what each test case validates (e.g., // allow arrow function inside function)
  • Use snapshots - Prefer onResult hook for bulk snapshot testing of all invalid cases
  • Consolidate config - Put shared parser/language options at tester level, not per test case
  • TypeScript support - Import @typescript-eslint/parser as tsParser and use in languageOptions.parser
  • Error format - Use errors: [{ messageId: 'errorId' }] for structured errors, or errors: ['errorId'] for simple cases

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

Chronos

通用周期任务管理器 - 支持6种周期类型、每月N次配额、自动cron、统一视图,适用于所有定时任务场景

Registry SourceRecently Updated
General

Football

Analyze football and soccer matches, squads, players, and training plans with tactical frameworks, scouting grids, and session blueprints.

Registry SourceRecently Updated
General

Cctv News Fetcher Litiao

Fetch and parse news highlights from CCTV News Broadcast (Xinwen Lianbo) for a given date.

Registry SourceRecently Updated
General

WeRead Book Finder

输入图书名称,优先在微信读书搜索并加入书架;若微信读书没有可信命中或无法加入书架,则自动回退到 Z-Library 搜索并优先下载非 PDF 格式。适用于“把《xxx》加入微信读书书架,不行就去 Z-Library 下载”这类请求。

Registry SourceRecently Updated