jest-community / eslint-plugin-jest

ESLint plugin for Jest
MIT License
1.14k stars 236 forks source link

Rule for alternative describe method name #1662

Open kvernon opened 1 month ago

kvernon commented 1 month ago

Hi all,

Recently we've done some work where we have a method called getTest(run:boolean) => it and we can apply this update with thejest/no-standalone-expect rule using its additionalTestBlockFunctions property. The method above would either return an it or an it.skip method.

However, we've started to move the idea higher up for describe in a similar manor. getDescribe(run:boolean) => describe behaves like the one above where it will either return the describe or describe.skip method.

In the jest world, having a way to supply this update would help for the eslint engine to understand that we don't have an identical title, or jest rule: jest/no-identical-title

Is there something like this today in eslint? I feel like I haven't found anything.

G-Rath commented 1 month ago

Can you provide a proper code example of what you're meaning? I suspect the answer is going to be along the lines of "too bespoke for us to support", but it's hard to say without seeing some actual code 😅

kvernon commented 1 month ago

@G-Rath I can and also thank you for reviewing this.

In a config for it would be something like:

{
 /* ... */
 rules: {
   'jest/no-standalone-expect': ['error', { additionalTestBlockFunctions: ['getTest'] }],
   'jest/no-identical-title': 'warn',
 }
 /* ... */
}

In code we have the following:

export function getTest(shouldRun: boolean): jest.It {
  if (!shouldRun) {
    return it.skip;
  }

  return it;
}

/**
  this is new and the ask of getting a way to have this as word check too like `additionalTestBlockFunctions`
*/
export function getDescribe(shouldRun: boolean): jest.describe {
  if (!shouldRun) {
    return describe.skip;
  }

  return describe;
}
// some examples

// this example show how `jest/no-standalone-expect` works today, which is great!
describe('when testing the universe', () => {
   describe('and galaxy', () => {
     test('we should get stars', () => {
       // ...
       expect(actual).toEqual(expected);
      });

     getTest(process.env.IS_QA_ENV)('we should get planets', () => {
       // ... 
       // note, because of the rule and supplying the alternative test name, this expect passes
       expect(actual).toEqual(expected);
      });
  });
});

// this example shows how 'jest/no-identical-title' behaves today
describe('when testing the universe', () => {
   describe('and galaxy is near', () => {
     test('we should get stars', () => {
       // ...
       expect(actual).toEqual(expected);
      });
   });
   describe('and galaxy is far', () => {
     // this will pass because describe or describe.skip is written directly in code
     test('we should get stars', () => {
       // ...
       expect(actual).toEqual(expected);
      });
   });
});

// this example of 'jest/no-identical-title' what happens when we try to use our similar method strategy as getTest with describing the results today
describe('when testing the universe', () => {
   getDescribe(process.env.IS_QA_ENV)('and galaxy is near', () => {
     test('we should get stars', () => {
       // ...
       expect(actual).toEqual(expected);
      });
   });
   getDescribe(process.env.IS_QA_ENV)('and galaxy is far', () => {
     // this will throw a warning because it is named the same thing, which is due to getDescribe method not being a describe or describe.skip written directly in code. What we'd like is for the title to understand that getDescribe is a describe method just like how we configured getTest.
     test('we should get stars', () => {
       // ...
       expect(actual).toEqual(expected);
      });
   });
});

To recap, the ask here is a way to have 'jest/no-identical-title' be able to understand alternative describe method names similarly as jest/no-standalone-expect does for test names

G-Rath commented 3 weeks ago

hmm yeah ok I think that could be useful - I'm not sure off the top of my head if additionalTestBlockFunctions would solve the problem by itself, but I'm happy for someone to do a PR exploring this.

You can get close using our global alias settings if you rewrite the helper to be describeIf(condition: unknown, name: string, fn: () => void), but that requires you specifically to make it available as a global i.e. if you import it, it no longer gets considered a Jest function

(this makes me think it could be nice if we supported inspecting types too when available i.e. we should be able to "see" that the helper returns jest.It and jest.describe...)