An ESLint runner for Jest that integrates ESLint into the Jest testing framework for unified code testing and quality checks
npx @tessl/cli install tessl/npm-jest-runner-eslint@2.3.0jest-runner-eslint is a Jest runner that integrates ESLint into the Jest testing framework, allowing developers to run ESLint as part of their Jest test suite. It enables linting to be treated as tests, providing a unified interface for both code testing and code quality checks with seamless integration for JavaScript and TypeScript projects.
npm install jest-runner-eslint// Main Jest runner (CommonJS only)
const jestRunner = require("jest-runner-eslint");
// Watch plugin
const ESLintWatchFixPlugin = require("jest-runner-eslint/watch-fix");// jest.config.js
module.exports = {
runner: 'jest-runner-eslint',
displayName: 'lint',
testMatch: ['<rootDir>/src/**/*.js'],
};// jest.config.js
module.exports = {
projects: [
{
displayName: 'test',
// your regular Jest test configuration
},
{
runner: 'jest-runner-eslint',
displayName: 'lint',
testMatch: ['<rootDir>/src/**/*.js'],
},
],
};// jest-runner-eslint.config.js
module.exports = {
cliOptions: {
fix: true,
cache: true,
format: 'codeframe',
maxWarnings: 0,
},
};jest-runner-eslint is built around several key components:
The runner automatically detects and handles different ESLint versions and configuration formats:
loadESLint() function to detect flat config vs legacy config automaticallyESLint and FlatESLint constructorsThe primary Jest runner that integrates ESLint into Jest testing workflow, supporting all ESLint configurations and providing Jest-formatted output.
const runner = require("jest-runner-eslint");Interactive Jest watch plugin that allows toggling ESLint's --fix option during development without restarting the watch process.
class ESLintWatchFixPlugin {
constructor(options: WatchPluginOptions);
run(): Promise<boolean>;
getUsageInfo(): WatchPluginUsageInfo;
}
interface WatchPluginOptions {
stdout: NodeJS.WriteStream;
config: { key?: string };
}
interface WatchPluginUsageInfo {
key: string;
prompt: string;
}Comprehensive configuration system supporting all ESLint CLI options with automatic detection of ESLint configuration type (legacy vs flat config).
interface JestRunnerESLintConfig {
cliOptions?: ESLintCliOptions;
}
interface ESLintCliOptions {
// Basic options
cache?: boolean;
cacheLocation?: string;
config?: string;
fix?: boolean;
fixDryRun?: boolean;
format?: string;
maxWarnings?: number;
quiet?: boolean;
// Legacy config options (ESLint <8.57.0)
ext?: string | string[];
env?: string | string[];
global?: string | string[];
ignorePath?: string;
ignorePattern?: string[];
noEslintrc?: boolean;
noIgnore?: boolean;
noInlineConfig?: boolean;
parser?: string;
parserOptions?: object;
plugin?: string | string[];
reportUnusedDisableDirectives?: boolean;
resolvePluginsRelativeTo?: string;
rules?: object;
rulesdir?: string | string[];
}Internal utilities for configuration management and normalization across different ESLint versions and configuration formats.
/**
* Configuration override management for watch mode
*/
class ConfigOverrides {
setFix(fix: boolean): void;
getFix(): boolean | undefined;
}
/**
* Configuration normalization for ESLint options
* @param configType - ESLint configuration type ('flat' | 'legacy')
* @param config - Raw configuration object
* @returns Normalized configuration with cliOptions
*/
function normalizeConfig(
configType: 'flat' | 'legacy',
config: object
): { cliOptions: ESLintCliOptions };interface ESLintResult {
filePath: string;
messages: ESLintMessage[];
errorCount: number;
fatalErrorCount?: number;
warningCount: number;
fixableErrorCount: number;
fixableWarningCount: number;
source?: string;
usedDeprecatedRules?: Array<{ ruleId: string; replacedBy: string[] }>;
}
interface ESLintMessage {
ruleId: string | null;
severity: 1 | 2;
message: string;
line: number;
column: number;
nodeType?: string;
messageId?: string;
endLine?: number;
endColumn?: number;
fix?: ESLintFix;
suggestions?: ESLintSuggestion[];
}
interface ESLintFix {
range: [number, number];
text: string;
}
interface ESLintSuggestion {
desc: string;
messageId?: string;
fix: ESLintFix;
}
interface TestResult {
failureMessage: string;
leaks: boolean;
numFailingTests: number;
numPassingTests: number;
numPendingTests: number;
numTodoTests: number;
openHandles: any[];
perfStats: {
start: number;
end: number;
duration: number;
runtime: number;
slow: boolean;
};
skipped: boolean;
snapshot: {
added: number;
fileDeleted: boolean;
matched: number;
unchecked: number;
uncheckedKeys: any[];
unmatched: number;
updated: number;
};
testFilePath: string;
testResults: TestAssertionResult[];
cliOptions?: ESLintCliOptions;
}
interface TestAssertionResult {
duration: number;
ancestorTitles: string[];
failureDetails: any[];
failureMessages: string[];
fullName: string;
location?: {
column: number;
line: number;
};
testFilePath: string;
numPassingAsserts: number;
status: 'passed' | 'failed' | 'skipped';
title: string;
}