Parameterize a test using vitest/jest

Both vitest and jest offer a test.each function for parameterizing a test like the following:

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

I found it’s more readable and flexible to use a loop in most cases:

for(const [a, b, expected] of [
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
]) {
  test(`add(${a}, ${b}) -> ${expected}`, () => {
    expect(a + b).toBe(expected)
  })
}

For example, if we are to test with the Cartesian product of two array parameters, we can simply use nested for loops to parameterize the tests, while it is verbose to use test.each:

for(const [a, b, expected] of [
  [1, 1, 2],
  [1, 2, 3],
  [2, 1, 3],
]) {
  for (const m of [1, 2]) {
    test(`add(${a} * ${m}, ${b} * ${m}) -> ${expected} * ${m}`, () => {
      expect(a * m + b * m).toBe(expected * m)
    })
  }
}

For another example, if we need a parameter to appear twice in the test name, with loops, it is straightforward with the template literals like the example above. Using test.each, it’ll be quite verbose: One likely has to define the parameter as an object and repeat the key names multiple times.