CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-typescript-eslint--rule-tester

Tooling to test ESLint rules with comprehensive TypeScript support and advanced testing capabilities

Pending
Overview
Eval results
Files

test-cases.mddocs/

Test Case Configuration

Comprehensive test case definition system with support for valid and invalid scenarios, autofix testing, and suggestion validation.

Capabilities

Test Suite Structure

Container for organizing valid and invalid test cases for rule testing.

/**
 * Container for test cases passed to the run method
 */
interface RunTests<MessageIds extends string, Options extends readonly unknown[]> {
  /** Array of valid test cases that should not trigger rule violations */
  readonly valid: readonly (string | ValidTestCase<Options>)[];
  /** Array of invalid test cases that should trigger rule violations */
  readonly invalid: readonly InvalidTestCase<MessageIds, Options>[];
}

Usage Examples:

import { RuleTester } from "@typescript-eslint/rule-tester";

const ruleTester = new RuleTester();

ruleTester.run("my-rule", myRule, {
  valid: [
    // Simple string cases
    "const x = 1;",
    "function foo() { return 'hello'; }",
    
    // Complex cases with configuration
    {
      code: "interface User { name: string; }",
      name: "interface declaration should be allowed",
    },
  ],
  invalid: [
    {
      code: "var x = 1;",
      errors: [{ messageId: "noVar" }],
      output: "const x = 1;",
    },
  ],
});

Valid Test Cases

Configuration for test cases that should not trigger any rule violations.

/**
 * Configuration for valid test cases that should not trigger rule violations
 */
interface ValidTestCase<Options extends readonly unknown[]> {
  /** Code for the test case */
  readonly code: string;
  /** Name for the test case for better test output */
  readonly name?: string;
  /** The fake filename for the test case (useful for rules that check filenames) */
  readonly filename?: string;
  /** Options for the rule being tested */
  readonly options?: Readonly<Options>;
  /** Language-specific options for the test case */
  readonly languageOptions?: TestLanguageOptions;
  /** Settings for the test case */
  readonly settings?: Readonly<SharedConfigurationSettings>;
  /** Constraints that must pass in the current environment for the test to run */
  readonly dependencyConstraints?: DependencyConstraint;
  /** Run this case exclusively for debugging in supported test frameworks */
  readonly only?: boolean;
  /** Skip this case in supported test frameworks */
  readonly skip?: boolean;
  /** Function to execute before testing the case */
  readonly before?: () => void;
  /** Function to execute after testing the case regardless of its result */
  readonly after?: () => void;
}

Usage Examples:

const validTestCases: ValidTestCase<[{ allowUnions: boolean }]>[] = [
  // Minimal test case
  {
    code: "const x = 1;",
  },
  
  // Test case with name and options
  {
    code: "type Status = 'active' | 'inactive';",
    name: "union types should be allowed when option is enabled",
    options: [{ allowUnions: true }],
  },
  
  // Test case with specific filename
  {
    code: "export default class Component {}",
    filename: "Component.tsx",
    languageOptions: {
      parserOptions: {
        ecmaFeatures: { jsx: true },
      },
    },
  },
  
  // Test case with environment constraints
  {
    code: "const promise: Promise<string> = Promise.resolve('hello');",
    dependencyConstraints: {
      typescript: ">=4.0.0",
    },
  },
  
  // Test case with setup and teardown
  {
    code: "console.log('test');",
    before: () => {
      jest.spyOn(console, 'log').mockImplementation(() => {});
    },
    after: () => {
      jest.restoreAllMocks();
    },
  },
  
  // Debugging specific test case
  {
    code: "function debug() { return 'debugging'; }",
    name: "debug function",
    only: true, // Run only this test case
  },
];

Invalid Test Cases

Configuration for test cases that should trigger rule violations with expected errors and fixes.

/**
 * Configuration for invalid test cases that should trigger rule violations
 */
interface InvalidTestCase<MessageIds extends string, Options extends readonly unknown[]> 
  extends ValidTestCase<Options> {
  /** Constraints that must pass in the current environment for the test to run */
  readonly dependencyConstraints?: DependencyConstraint;
  /** Expected errors that should be reported */
  readonly errors: readonly TestCaseError<MessageIds>[];
  /** Expected code after autofixes are applied */
  readonly output?: string | string[] | null;
}

Usage Examples:

const invalidTestCases: InvalidTestCase<"noVar" | "preferConst", []>[] = [
  // Basic invalid test case
  {
    code: "var x = 1;",
    errors: [{ messageId: "noVar" }],
    output: "const x = 1;",
  },
  
  // Test case with specific error location
  {
    code: "function foo() {\n  var x = 1;\n  return x;\n}",
    errors: [{
      messageId: "noVar",
      line: 2,
      column: 3,
      endLine: 2,
      endColumn: 6,
    }],
    output: "function foo() {\n  const x = 1;\n  return x;\n}",
  },
  
  // Test case with multiple errors
  {
    code: "var a = 1; var b = 2;",
    errors: [
      { messageId: "noVar", line: 1, column: 1 },
      { messageId: "noVar", line: 1, column: 12 },
    ],
    output: "const a = 1; const b = 2;",
  },
  
  // Multi-pass autofix (array of outputs)
  {
    code: "var a = 1; var b = a;",
    errors: [
      { messageId: "noVar" },
      { messageId: "preferConst" },
    ],
    output: [
      "let a = 1; var b = a;", // First pass
      "const a = 1; let b = a;", // Second pass
      "const a = 1; const b = a;", // Final pass
    ],
  },
  
  // Test case with no autofix
  {
    code: "eval('var x = 1');",
    errors: [{ messageId: "noEval" }],
    output: null, // Explicitly no autofix expected
  },
  
  // Test case with suggestions
  {
    code: "function foo(x: any) { return x; }",
    errors: [{
      messageId: "noAny",
      type: "TSAnyKeyword",
      suggestions: [
        {
          messageId: "useUnknown",
          output: "function foo(x: unknown) { return x; }",
        },
        {
          messageId: "useGeneric",
          output: "function foo<T>(x: T) { return x; }",
        },
      ],
    }],
  },
];

Test Case Errors

Expected error configuration for invalid test cases with detailed location and suggestion information.

/**
 * Expected error configuration for invalid test cases
 */
interface TestCaseError<MessageIds extends string> {
  /** Reported message ID (required) */
  readonly messageId: MessageIds;
  /** The 1-based line number of the reported start location */
  readonly line?: number;
  /** The 1-based column number of the reported start location */
  readonly column?: number;
  /** The 1-based line number of the reported end location */
  readonly endLine?: number;
  /** The 1-based column number of the reported end location */
  readonly endColumn?: number;
  /** The type of the reported AST node */
  readonly type?: AST_NODE_TYPES | AST_TOKEN_TYPES;
  /** The data used to fill the message template */
  readonly data?: ReportDescriptorMessageData;
  /** Expected suggestions for fixing the error */
  readonly suggestions?: readonly SuggestionOutput<MessageIds>[] | null;
}

Usage Examples:

// Minimal error expectation
const simpleError: TestCaseError<"noVar"> = {
  messageId: "noVar",
};

// Detailed error expectation with location
const detailedError: TestCaseError<"noVar"> = {
  messageId: "noVar",
  line: 1,
  column: 1,
  endLine: 1,
  endColumn: 4,
  type: "VariableDeclaration",
};

// Error with template data
const errorWithData: TestCaseError<"unexpectedType"> = {
  messageId: "unexpectedType",
  data: {
    expected: "string",
    actual: "number",
  },
};

// Error with suggestions
const errorWithSuggestions: TestCaseError<"noAny"> = {
  messageId: "noAny",
  suggestions: [
    {
      messageId: "useUnknown",
      output: "function foo(x: unknown) { return x; }",
    },
    {
      messageId: "useGeneric",
      output: "function foo<T>(x: T) { return x; }",
      data: { genericName: "T" },
    },
  ],
};

Suggestion Output

Expected suggestion configuration for rule suggestions with their expected outputs.

/**
 * Expected suggestion configuration for rule suggestions
 */
interface SuggestionOutput<MessageIds extends string> {
  /** Suggestion message ID (required) */
  readonly messageId: MessageIds;
  /** Expected output after applying the suggestion (required) */
  readonly output: string;
  /** The data used to fill the message template */
  readonly data?: ReportDescriptorMessageData;
}

Usage Examples:

const suggestions: SuggestionOutput<"useUnknown" | "useGeneric">[] = [
  // Simple suggestion
  {
    messageId: "useUnknown",
    output: "function foo(x: unknown) { return x; }",
  },
  
  // Suggestion with template data
  {
    messageId: "useGeneric",
    output: "function foo<T>(x: T) { return x; }",
    data: {
      genericName: "T",
      paramName: "x",
    },
  },
];

Language Options

/**
 * Language-specific options for individual test cases
 */
interface TestLanguageOptions {
  /** The absolute path for the parser */
  readonly parser?: Readonly<Parser.LooseParserModule>;
  /** Options for the parser */
  readonly parserOptions?: Readonly<ParserOptions>;
  /** The additional global variables */
  readonly globals?: Readonly<Linter.GlobalsConfig>;
  /** Environments for the test case */
  readonly env?: Readonly<Linter.EnvironmentConfig>;
}

Usage Examples:

// TypeScript with JSX support
const tsxLanguageOptions: TestLanguageOptions = {
  parserOptions: {
    ecmaVersion: 2022,
    sourceType: "module",
    ecmaFeatures: {
      jsx: true,
    },
    project: "./tsconfig.json",
  },
};

// Browser environment with globals
const browserLanguageOptions: TestLanguageOptions = {
  env: {
    browser: true,
    es2022: true,
  },
  globals: {
    window: "readonly",
    document: "readonly",
    console: "readonly",
  },
};

// Node.js environment
const nodeLanguageOptions: TestLanguageOptions = {
  env: {
    node: true,
    es2022: true,
  },
  globals: {
    process: "readonly",
    Buffer: "readonly",
  },
};

Install with Tessl CLI

npx tessl i tessl/npm-typescript-eslint--rule-tester

docs

dependency-constraints.md

global-configuration.md

index.md

rule-testing.md

test-cases.md

utilities.md

tile.json