1. Equivalence Partitioning
Group inputs into classes where any member behaves identically. Test one per class β not ten.
When to reach for it
Input validation, range checks, categorical dropdowns, state-dependent behaviour.
How many tests
One representative per class. 3 classes β 3 tests. Resist the urge to 'just add a few more'.
Sign-up age field (accepts 18-100):
Invalid below β age < 18 β reject
Valid β 18 β€ age β€ 100 β accept
Invalid above β age > 100 β reject
Malformed β non-numeric β reject
4 partitions β 4 tests (one per class).
NOT 40 tests with ages 1, 2, 3β¦ 100.// One test per equivalence class
test.each([
{ age: 10, expected: 'reject', class: 'invalid-below' },
{ age: 25, expected: 'accept', class: 'valid' },
{ age: 150, expected: 'reject', class: 'invalid-above' },
{ age: 'x', expected: 'reject', class: 'malformed' },
])('age=$age ($class) β $expected', async ({ age, expected }) => {
await page.getByLabel(/age/i).fill(String(age));
await page.getByRole('button', { name: /submit/i }).click();
if (expected === 'accept') {
await expect(page.getByText(/welcome/i)).toBeVisible();
} else {
await expect(page.getByRole('alert')).toBeVisible();
}
});Common pitfall: Equivalence partitioning assumes homogeneity WITHIN a class. Always pair with BVA β the boundary is where partitions lie, and classes rarely behave the same at edges.