Skip to content

antfu/eslint-vitest-rule-tester

Repository files navigation

eslint-vitest-rule-tester

npm version npm downloads bundle JSDocs License

ESLint rule tester with Vitest.

Provides a better testing experience, supports snapshoting, and does not require globals: true in Vitest.

This module requires ESLint v9.0+.

Who is using?

Install

npm i -D eslint-vitest-rule-tester

Usage

Classical Usage

Simliar style to ESLint's RuleTester (test cases with implicit test suites)

import { run, runClassic } from 'eslint-vitest-rule-tester'
import { expect } from 'vitest'

// Classic RuleTester.run style
runClassic('rule-name', rule, {
  valid: [
    // ...
  ],
  invalid: [
    // ...
  ],
}, {
  parserOptions: {
    ecmaVersion: 2020,
    sourceType: 'module',
  },
})

// Or everyting-in-one-object style
run({
  name: 'rule-name',
  rule,
  parserOptions: {
    ecmaVersion: 2020,
    sourceType: 'module',
  },

  valid: [
    // test cases
  ],
  invalid: [
    // test cases
  ],
})
Feature Extensions

output

output field can be a function to do custom assertions. This would also be compatible with snapshot testing.

import { run, } from 'eslint-vitest-rule-tester'
import { expect } from 'vitest'

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;"`)
        // Any custom assertion...
      },
    },
  ],
})

errors

errors field can be a function to do custom assertion, same as output.

import { run } from 'eslint-vitest-rule-tester'
import { expect } from 'vitest'

run({
  name: 'rule-name',
  rule,
  invalid: [
    {
      code: 'let foo = 1',
      errors(errors) {
        expect(errors).toHaveLength(1)
        expect(errors.map(e => e.messageId))
          .toMatchInlineSnapshot(`["error-message-id"]`)
        // Any custom assertion...
      },
    },
  ],
})

onResult hook

onResult field can be a function to do custom assertions with the entire result object.

import { run } from 'eslint-vitest-rule-tester'
import { expect } from 'vitest'

run({
  name: 'rule-name',
  rule,
  invalid: [
    'let foo = 1',
  ],
  onResult(testCase, result) {
    if (testCase.type === 'invalid')
      expect(result).toMatchSnapshot()
    // here you can't use `toMatchInlineSnapshot` because it's not in the test case
  },
})

Explicit Test Suites

import { createRuleTester } from 'eslint-vitest-rule-tester'
import { describe, expect, it } from 'vitest'

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

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

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

    expect(result.output).toMatchSnapshot()
  })
})

Sponsors

License

MIT License © 2024-PRESENT Anthony Fu

About

ESLint rule tester with Vitest, with more powerful and friendly APIs.

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Contributors 8