When writing tests, repeating the same test logic with different inputs can be tedious and lead to unnecessary duplication.

Lukcily, Vitest provides test.each, which allows us to run the same test with multiple sets of parameters.

Instead of writing multiple test cases like this:

import { test, expect } from 'vitest';

function add(a: number, b: number) {
  return a + b;
}

test('adds 1 + 2 to equal 3', () => {
  expect(add(1, 2)).toBe(3);
});

test('adds 2 + 3 to equal 5', () => {
  expect(add(2, 3)).toBe(5);
});

We can simplify it using test.each:

import { test, expect } from 'vitest';

function add(a: number, b: number) {
  return a + b;
}

test.each([
  [1, 2, 3],
  [2, 3, 5],
  [5, 7, 12],
])('adds %d + %d to equal %d', (a, b, expected) => {
  expect(add(a, b)).toBe(expected);
});

How It Works

  • The first argument of test.each is an array of test cases.
  • Each test case is an array where values are passed to the test function.
  • The placeholders (%d) in the test title are replaced with actual values.
  • Vitest runs each test with the given parameters automatically.

For better readability, you can use an array of objects:

const cases = [
  { a: 1, b: 2, expected: 3 },
  { a: 2, b: 3, expected: 5 },
  { a: 5, b: 7, expected: 12 },
];

test.each(cases)('adds $a + $b to equal $expected', ({ a, b, expected }) => {
  expect(add(a, b)).toBe(expected);
});

This makes it easier to extend or modify test cases later.

Using test.each in Vitest helps keep tests clean, avoids repetition, and makes it easy to test multiple inputs efficiently. Next time you find yourself writing similar test cases, consider test.each to keep things DRY.

source