When several test cases follow the same pattern with different inputs and expected outputs, repeating nearly identical test() blocks becomes tedious and hard to maintain. This lesson covers test.each() and describe.each() for data-driven testing.
test.each() with an Array of Cases
test.each(table)(name, fn) runs the same test function once per row in table, substituting each row's values into both the callback's parameters and the test name (using %s, %i, %p, and similar placeholders). This turns many near-duplicate tests into one compact, easy-to-extend definition.
The table can be an array of arrays (positional arguments) or an array of objects (named properties, referenced with $propertyName in the test name).
Parameterized tests work best when the *shape* of the test is identical across cases and only the input/output values differ — validation rules, formatting functions, and edge-case boundary checks are classic candidates. If each case actually needs different setup or assertions, separate test() blocks are clearer.
Good fit: testing a validator against many valid/invalid input strings.
Good fit: boundary testing a function across a range of numeric inputs.
Poor fit: cases that need meaningfully different setup, mocks, or assertions each time.
Grouping Related Cases with describe.each()
describe.each() is useful when each row needs multiple related tests, not just one — for example, testing several properties of the same computed value for each input case.
Using test.each() for cases that actually need different setup or mocking per row.
Forgetting the placeholder order in the test name must match the row's argument order.
Making the test data table so large it becomes hard to scan and review meaningfully.
Not naming rows descriptively enough, producing confusing generated test names.
Key Takeaways
test.each() runs the same test logic once per row of a data table.
Rows can be arrays (positional) or objects (named, referenced with $property).
describe.each() groups multiple related tests per row instead of just one.
Reserve parameterization for cases where only input/output values differ, not setup logic.
Pro Tip
When a bug report mentions a specific edge case, add it as a new row to an existing test.each() table instead of writing a whole new test — it keeps related cases together and documents the bug fix directly in the test data.
You now know how to write parameterized tests. Next, learn how Jest's watch mode speeds up your development feedback loop.