UNPKG

eslint-vitest-rule-tester

Version:
148 lines (122 loc) 5.12 kB
--- name: eslint-vitest-rule-tester description: Help users test ESLint rules with Vitest, supporting snapshot testing and custom assertions meta: version: 3.0.1 author: Anthony Fu --- # 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:** ```ts // 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