Writing tests

March 27, 2026 · View on GitHub

Tests are in the /test directory.

A rule test file should look like this:

import {getTester} from './utils/test.js';

const {test} = getTester(import.meta);

test.snapshot({
	valid: [
		// Valid test cases goes here
	],
	invalid: [
		// Valid test cases goes here
	],
});

test.snapshot()

This runs SnapshotRuleTester, which auto-generates the snapshot for test results, including error messages, error locations, autofix result, and suggestions. All you have to do is check the snapshot and make sure the results are expected before committing.

It's recommended to use this approach as it simplifies test writing.

import {getTester} from './utils/test.js';

const {test} = getTester(import.meta);

test.snapshot({
	valid: [
		'valid.code',
	],
	invalid: [
		'invalid.code',
	],
});

Focus on one rule

We use AVA to run tests. To focus on a specific rule test, you can:

npx ava test/rule-name.js

To update snapshots, run the command above with --update-snapshots or -u.

npx ava test/rule-name.js -u

Focus on one test case

To focus on a single test case, you can:

test.snapshot({
	valid: [],
	invalid: [
		// Tagged template with `test.only`
		test.only`code`,

		// Wrap code with `test.only`
		test.only('code'),

		// Wrap test case with `test.only`
		test.only({
			code: 'code',
			options: [{checkFoo: true}],
		}),

		// Use `only: true`
		{
			code: 'code',
			options: [{checkFoo: true}],
			only: true,
		},
	],
})

Please remove test.only and only: true before committing.

test()

This runs eslint-ava-rule-tester:

import {getTester} from './utils/test.js';

const {test} = getTester(import.meta);

test({
	valid: [
		'valid.code',
	],
	invalid: [
		{
			code: 'invalid.code',
			errors: [{ message: 'invalid.code is not allowed', column: 1, line: 1 }],
			output: 'fixed.code',
		}
	],
});

test.typescript()

Same as test(), but uses @typescript-eslint/parser as parser.

test.vue()

Same as test(), but uses vue-eslint-parser as parser.

testerOptions

test and test.*() accepts testerOptions, which lets you specify common parseOptions to all test cases.

test.snapshot({
	testerOptions: {
		languageOptions: {
			parserOptions: {
				ecmaFeatures: {
					jsx: true,
				},
			},
		},
	},
	valid: [],
	invalid: [],
})

parsers

utils/test.js also exposes a parsers object, which can be used in testerOptions or parser for a single test case.

import {getTester, parsers} from './utils/test.js';

const {test} = getTester(import.meta);

test.snapshot({
	testerOptions: {
		languageOptions: {
			parser: parsers.typescript,
		},
	},
	valid: [],
	invalid: [],
})
import {getTester, parsers} from './utils/test.js';

const {test} = getTester(import.meta);

test.snapshot({
	valid: [],
	invalid: [
		{
			code: 'const foo = 1 as const;',
			languageOptions: {
				parser: parsers.typescript,
			},
		},
	],
})

Why use parser: parsers.typescript instead of parser: '@typescript-eslint/parser'?

Using parsers.typescript will make the parserOptions merge with useful default options. See parsers.js for details.