1

I am using a jest it.each block to reduce the repetitiveness of the test case for same scenario, but i could not able to dynamically update the it block description. how to do that?

example test case

const testData = [
    {
      module: 'test_module',
      entityName: 'test_entity'
    },
    {
      module: 'test_module1',
      entityName: 'test_entity1'
    },
  ];

 it.each(testData)(`should perform get respose - ${entityName}`, async (entityDetails: any) => {
       
         const url = `${entityDetails.module}/${entityDetails.entityName}/all/`;
        // Executing
        const response = await request(server).get(url);
        // Verifying
        expect(response.status).toBe(200);

});

In this provided example, i need entity name to be in it block description dynamically. something like
should perform get respose - test_entity
should perform get respose - test_entity1
how to achieve this?

karel
  • 5,489
  • 46
  • 45
  • 50
muthu
  • 723
  • 10
  • 27
  • 1
    Check [this answer](https://stackoverflow.com/questions/63590852/in-jest-whats-the-best-way-to-loop-through-an-array-of-inputs-and-expected-outp/63596686#63596686) – Teneff Sep 03 '20 at 13:16

2 Answers2

3

I realize this is an old question, but it might help future googlers.

it.each supports dynamic "descriptions" (it's called name in the docs) in multiple ways:

Using an array of arrays. This gives us positional arguments in the description.

it.each([
  [1, 1, 2],
  [1, 2, 3],
])('%i plus %i returns %i', (a, b, expected) => {
  expect(a + b).toBe(expected);
});

You can also use an array of objects. This gives us named arguments. This is also better for TypeScript because arguments can have different types.

it.each([
  {a: 1, b: 1, expected: 2},
  {a: 1, b: 2, expected: 3},
])('returns $expected for $a plus $b', ({ a, b, expected }) => {
  expect(a + b).toBe(expected);
});

Finally, there is the template string method:

it.each`
  a    | b    | expected
  ${1} | ${1} | ${2}
  ${1} | ${2} | ${3}
`('returns $expected for $a plus $b', ({ a, b, expected }) => {
  expect(a + b).toBe(expected);
});

The description also supports printf-style formatting options. See the docs for more info.

zord
  • 4,538
  • 2
  • 25
  • 30
2

it.each expects an array of arrays and provides them in description and function parameters in the order they were specified. The only convenience it offers is that description string is formatted and doesn't need string literals:

const testData = [
  ['test_entity', 'test_module'],
  ...
];

it.each(testData)('should perform get respose - %s', (_entityName, entityDetails) => ...)

For more flexible use that doesn't have these limitations, JavaScript loops can be used:

const testData = [
  {
    module: 'test_module',
    entityName: 'test_entity'
  },
  ...
];

testData.forEach(({ module, entityName }) => {
  it(`should perform get respose - ${entityName}`, () => ...)
});
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Thanks for your efforts. but I cant change my logic. it should be array of object and should achieve it using `it.each`, is there any alternative solutions. or its impossible? – muthu Sep 03 '20 at 14:59
  • If you can modify `it.each` line somehow this means you can replace it with `forEach` that suits your case better. Check `each` docs, everything it's capable of is there, https://github.com/facebook/jest/tree/master/packages/jest-each . If it's not an array of arrays, it needs to be converted to it, `it.each(testData.map(o => [...Object.values(o)].reverse())(...)`. `reverse` is needed because entityName should go first to be used as `%s` in test title. – Estus Flask Sep 03 '20 at 15:49
  • 1
    @muthu if you need an object within the test case [this is how you can create it](https://repl.it/repls/IllMessyInternalcommand) – Teneff Sep 03 '20 at 22:08
  • @Teneff, I have updated the process inside the test case, In what way your suggestion will work for me? please suggest. – muthu Sep 04 '20 at 05:48