Jest looping through dynamic test cases

61,513

Solution 1

There's an in-built way to do this: test.each(table)(name, fn, timeout)

e.g.

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

where each inner array in the 2D array is passed as args to the test function.

Solution 2

If one passes, they all will. So you only need one for a positive test. Ideally, you want 1 positive where the 2 numbers equal the sum, and a failure where you pass a string or something and throw an error.

TL/DR; You don't need 4 tests that all do the same thing. Also, you need to pull the looped test cases out of the parent test for the loop to work.

This will work just fine:

import jest from 'jest';
import { sumModule } from './';

const tests = [
  {x: 1, y: 2, r: 3}, 
  {x: 3, y: 4, r: 7}
];

describe('Adding method', () => { 
    for(let i = 0; i < tests.length; i++){
      it('should add its params', () => {
        const actual = sumModule(tests[i].x, tests[i].y);
        expect(actual).toBe(tests[i].r);
      });
    }
});

Solution 3

If anyone wondering how this can work for a single input function here is an example

const testData = [
      ['input1', 'output1'],
      ['input2', 'output2'],
      ['input3', 'output3'],
]

test.each(testData)('myFunc work correctly for %s',(input, output) =>{
        expect(yourFunc(input)).toBe(output)
})

https://jestjs.io/docs/en/api#testeachtablename-fn-timeout

Solution 4

You can use classic JS, it is more readable and with less code:

[
  { input: [2, 3], output: 5 },
  { input: [1, 2], output: 3 },
].forEach(({ input, output }) => {
  it(`works correctly for ${input}`, () => {
    // ...

    expect(...).toBe(output);
  });
})
Share:
61,513
mehari
Author by

mehari

Updated on September 08, 2021

Comments

  • mehari
    mehari over 2 years

    How do I loop through dynamic test cases in Jest?

    I have test cases like the following how do I dynamically create jest test case using it/test methods.

    Here is what I have tried , However it just passes without excuting the test cases in the loop.

        const mymodule = require('mymodule');
    
        const testCases = [
            {q: [2, 3],r: 5},
            {q: [1, 2],r: 3},
            {q: [7, 0],r: 7},
            {q: [4, 4],r: 8}
        ];
    
        describe("Test my Math module", () => {
            test("test add method", () => {
                for (let i = 0; i < testCases.length; i++) {
                    const { q,r } = testCases[i];
                    it(`should  add ${q[0]},${q[1]} to ${expected}`, () => {
                        const actual = mymodule.add(q[0] + q[1]);
                        expect(actual).toBe(expected);
                    });
                }
            });
        
        });
    
  • Kevin Farrugia
    Kevin Farrugia over 5 years
    Unfortunately the same is not possible when looping through dynamic test cases generated from an async operation. :( github.com/facebook/jest/issues/1619#issuecomment-358576732
  • Kevin Farrugia
    Kevin Farrugia over 5 years
    Yes. Doesn't work when iterating through async config, irrelevant of the method. :(
  • M.Abulsoud
    M.Abulsoud over 4 years
    I have a code block async in beforeAll, and I want to generate test cases based on the results of the code block in the beforeAll. It keep write Your test suite must contain at least one test.
  • justin
    justin almost 3 years
    @nickang yes it can be useful. I have also found use of expect(result).toMatchInlineSnapshot(<string>) to be useful if the output under test can be rendered to string (this doesn't have to be JSX, you can e.g. render a JSON data structure and snapshot match against it).
  • GhostBytes
    GhostBytes over 2 years
    This should be the answer. It's easier to write, read and work with. Being able to user interpolation on the test name is a huge advantage as well and enough for me not to use test.each.