testing-library / eslint-plugin-testing-library

ESLint plugin to follow best practices and anticipate common mistakes when writing tests with Testing Library
https://npm.im/eslint-plugin-testing-library
MIT License
992 stars 142 forks source link

Internal: generate tests for all supported frameworks per rule #589

Open Belco90 opened 2 years ago

Belco90 commented 2 years ago

Plugin version

v5

What problem do you want to solve?

Quoting myself from #588:

Thinking about all the changes we did to test all rules for the corresponding Testing Library frameworks, I think it makes sense to add some improvements to our TestingLibraryRuleMeta and createRuleTester to automatically generate the test cases variations for indicated frameworks.

Your take on the correct solution?

In my mind, it could look like this:


// rules/foo.js
export default createTestingLibraryRule({
  // ...
  meta: {
    // ...
    supportedFrameworks: ['react', 'vue']
    // ^ we extend our TestingLibraryRuleMeta so it has this new required property,
    // which can be used also to autogenerate a table of compatible frameworks for each rule doc
  }
})

// test/lib/rules/foo.js
ruleTester.run(RULE_NAME, rule, {
  valid: [
    {
      code: `
      import { fireEvent } from '{TESTING_LIBRARY_FRAMEWORK}'
      //                                          ^ this placeholder gets replaced automatically,
      //                                             iterating over each value from supportedFrameworks

      await fireEvent.click(element)
      `
    }
  ]
})

Anything else?

No response

Do you want to submit a pull request to implement this change?

Yes

Belco90 commented 2 years ago

We could even derive supportedFrameworks from the recommendedConfig meta.

@MichaelDeBoey when the rules are enabled in a recommended config yes, but I'm afraid we can't rely on this when the rule isn't enabled in any shareable config (e.g. no-manual-cleanup, or prefer-explicit-assert). So we would need this new supportedFrameworks.

We should even be able to run all rules on all testing frameworks though. I currently only did this when the rule is available in the config for that specific testing framework.

That made me think about my approach might not be right, actually. For example, in no-manual-cleanup there are different outputs depending on the testing framework. This is a scenario we couldn't reach with my proposal, so perhaps it has to be a callback, receiving the framework being tested to do things conditionally when needed, rather than just a placeholder replaced. Something like:

// test/lib/rules/foo.js
ruleTester.run(RULE_NAME, rule, ({ testingFramework }) => ({
  valid: [
    {
      code: `
      import { fireEvent } from ${testingFramework}
      await fireEvent.click(element)
      `
      output: testingFramework.startsWith('@marko') ? 'foo' : 'bar'
    }
  ]
}))