Skip to content

Repo: rule-tester: Can I use the output of the snapshot test rules? #7449

Closed as not planned
@u3u

Description

@u3u

Motivation

When a rule contains an auto-fix program, I want to test if the output of the fix meets my expectations. The simplest way is to use snapshot testing and check if the snapshot matches the expected result.

However, now I need to manually maintain strict formatting for indentation, spaces, and other formatting-related outputs.

I also need to use dedent to ensure consistent indentation. This is too troublesome.

If I want to optimize the auto-fixing process, I also need to manually synchronize the output of the tests (sometimes it may be just one extra or missing space, which should not matter because it will eventually be formatted by Prettier).

Example

https://github.com/u3u/eslint-plugin-arrow-return-style/blob/bfa3cc81f15526aa76fe1b043d0a394ffe3be2ba/src/rules/arrow-return-style.test.ts

import { RuleTester } from '@typescript-eslint/rule-tester';
import dedent from 'dedent';
import { afterAll, describe, it } from 'vitest';
import { arrowReturnStyleRule, RULE_NAME } from './arrow-return-style';

RuleTester.afterAll = afterAll;
RuleTester.describe = describe;
RuleTester.it = it;

const ruleTester = new RuleTester({
  parser: '@typescript-eslint/parser',

  parserOptions: {
    ecmaFeatures: { jsx: true },
  },
});

ruleTester.run(RULE_NAME, arrowReturnStyleRule, {
  invalid: [
    {
      code: dedent`
        const delay = () =>
          new Promise((resolve) => {
            setTimeout(resolve, 1000)
          })
      `,

      errors: [{ messageId: 'useExplicitReturn' }],

      output: dedent`
        const delay = () =>
          { return new Promise((resolve) => {
            setTimeout(resolve, 1000)
          }) }
      `,
    },

    {
      code: dedent`
        const foo = () => {
          return 'foo'
        }
      `,

      errors: [{ messageId: 'useImplicitReturn' }],

      output: dedent`
        const foo = () => 
          'foo'\n
      `,
    },

    {
      code: dedent`
        Array.from({ length: 10 }).map((_, i) => {
          return i + 1
        })
      `,

      errors: [{ messageId: 'useImplicitReturn' }],

      output: dedent`
        Array.from({ length: 10 }).map((_, i) => 
          i + 1
        )
      `,
    },

    {
      code: dedent`
        const obj = () => {
          return { name: '' }
        }
      `,

      errors: [{ messageId: 'useImplicitReturn' }],

      output: dedent`
        const obj = () => 
          ({ name: '' })\n
      `,
    },

    {
      code: dedent`
        const data = () => ({
          name: ''
        })
      `,

      errors: [{ messageId: 'useExplicitReturn' }],

      output: dedent`
        const data = () => { return {
          name: ''
        } }
      `,
    },

    {
      code: 'export const defineConfig = <T extends Linter.Config>(config: T) => config',
      errors: [{ messageId: 'useExplicitReturn' }],
      output: 'export const defineConfig = <T extends Linter.Config>(config: T) => { return config }',
    },

    {
      code: 'const Div = () => <><div /></>',
      errors: [{ messageId: 'useExplicitReturn' }],
      options: [{ jsxAlwaysUseExplicitReturn: true }],
      output: 'const Div = () => { return <><div /></> }',
    },

    {
      code: dedent`
        const FC = () =>
          <Foo
          // d=""
          z
          // test={{}}
          data-ignore=""
          bar={[]}
        />
      `,

      errors: [{ messageId: 'useExplicitReturn' }],

      output: dedent`
        const FC = () =>
          { return <Foo
          // d=""
          z
          // test={{}}
          data-ignore=""
          bar={[]}
        /> }
      `,
    },

    {
      code: dedent`
        export const createRule = ESLintUtils.RuleCreator(
          (rule) => \`https://github.com/u3u/eslint-plugin-arrow-return-style/tree/v\${version}/docs/rules/\${rule}.md\`
        )
      `,

      errors: [{ messageId: 'useExplicitReturn' }],

      output: dedent`
        export const createRule = ESLintUtils.RuleCreator(
          (rule) => { return \`https://github.com/u3u/eslint-plugin-arrow-return-style/tree/v\${version}/docs/rules/\${rule}.md\` }
        )
      `,
    },

    {
      code: 'const render = () => (<div />)',
      errors: [{ messageId: 'useExplicitReturn' }],
      options: [{ jsxAlwaysUseExplicitReturn: true }],
      output: 'const render = () => { return <div /> }',
    },

    {
      code: dedent`
        const fn = () =>
          /* block comment */
          1
      `,

      errors: [{ messageId: 'useExplicitReturn' }],

      output: dedent`
        const fn = () => {
          /* block comment */
          return 1
        }
      `,
    },

    {
      code: dedent`
        const test = () =>
          // line comment
          ({ name: 'test' })
      `,

      errors: [{ messageId: 'useExplicitReturn' }],

      output: dedent`
        const test = () => {
          // line comment
          return { name: 'test' }
        }
      `,
    },
  ],

  valid: [
    'const t = () => Date.now()',
    'const fn = () => { return }',

    'Array.from({ length: 10 }).map((_, i) => i + 1)',

    {
      code: 'const Div = () => <><div /></>',
      options: [{ jsxAlwaysUseExplicitReturn: false }],
    },

    dedent`
      const bar = () => {
        // line comment
        return 'bar'
      }
    `,

    dedent`
      const fn = async () => {
        await delay(300)
        return 'fn'
      }
    `,

    dedent`
      export const getUser = async () => {
        return {}
      }
    `,
  ],
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionQuestions! (i.e. not a bug / enhancment / documentation)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions