Parameterized tests should not contain duplicate test cases. Each row in a parameterized test dataset should describe a distinct scenario.
Parameterized tests execute their test body once for every row in the dataset. Repeating a row therefore runs the same parameterized test case more than once. This increases test execution time and makes the intended test matrix harder to understand.
This rule reports duplicate rows in the Jest, Vitest, and Bun parameterized test and suite declarations that use .each, including
test.each, it.each, describe.each, and Vitest’s suite.each. Rows are compared as complete abstract
syntax tree expressions, so the rule covers identifiers and function calls in addition to primitive literals.
The comparison is structural and does not evaluate expressions. For example, two calls to createUser('Alice') are considered
duplicates even if the function returns a new object each time. For each structurally repeated case, the rule raises one issue on the first duplicate.
Secondary locations identify the original case and any additional duplicates. A quick fix is available to remove the redundant cases.
Repeated rows can be intentional when the test body mutates a shared object or relies on mutable global state. Review the test before applying the quick fix because removing a repeated execution is not always safe.
import { test } from '@jest/globals';
test.each([
1,
2,
1, // Noncompliant: this duplicates the first case
])('calculates square of %i', (num) => {
expect(square(num)).toBe(num * num);
});
import { test } from '@jest/globals';
test.each([
1,
2,
3,
])('calculates square of %i', (num) => {
expect(square(num)).toBe(num * num);
});
import { test } from 'vitest';
const alice = { name: 'Alice', role: 'admin' };
const bob = { name: 'Bob', role: 'user' };
test.each([
[alice, 'admin'],
[bob, 'user'],
[alice, 'admin'], // Noncompliant: this duplicates the first case
])('accepts %s with the %s role', (user, role) => {
expect(user.role).toBe(role);
});
import { test } from 'vitest';
const alice = { name: 'Alice', role: 'admin' };
const bob = { name: 'Bob', role: 'user' };
const carol = { name: 'Carol', role: 'editor' };
test.each([
[alice, 'admin'],
[bob, 'user'],
[carol, 'editor'],
])('accepts %s with the %s role', (user, role) => {
expect(user.role).toBe(role);
});
import { test } from 'bun:test';
const makeGreeting = name => `Hello, ${name}!`;
test.each([
[makeGreeting('Alice'), 'Hello, Alice!'],
[makeGreeting('Bob'), 'Hello, Bob!'],
[makeGreeting('Alice'), 'Hello, Alice!'], // Noncompliant: this duplicates the first case
])('creates the expected greeting', (greeting, expected) => {
expect(greeting).toBe(expected);
});
import { test } from 'bun:test';
const makeGreeting = name => `Hello, ${name}!`;
test.each([
[makeGreeting('Alice'), 'Hello, Alice!'],
[makeGreeting('Bob'), 'Hello, Bob!'],
[makeGreeting('Carol'), 'Hello, Carol!'],
])('creates the expected greeting', (greeting, expected) => {
expect(greeting).toBe(expected);
});
test.each(table)(name, fn, timeout)describe.each(table)(name, fn,
timeout)test.eachdescribe.eachtest.each and
describe.each