Q18 of 48 · Cypress
How do you parameterise a test across multiple datasets in Cypress?
Short answer
Short answer: Use a plain `forEach` over the dataset, generating an `it` per case. Cypress doesn't have built-in parametrisation like `it.each` (Jest), but the pattern is idiomatic JavaScript and works the same way. Datasets often come from `cy.fixture`.
Detail
Cypress doesn't ship a describe.each or it.each API like Jest/Vitest. The idiomatic pattern is to iterate over your dataset at the top of the spec and call it() inside the loop:
const cases = [
{ input: 'alice@x.com', valid: true },
{ input: 'no-at-symbol', valid: false },
{ input: '', valid: false },
];
cases.forEach(({ input, valid }) => {
it(`treats "${input}" as ${valid ? 'valid' : 'invalid'}`, () => {
cy.visit('/login');
cy.get('[data-test=email]').type(input);
cy.get('[data-test=submit]').click();
cy.get('[data-test=error]').should(valid ? 'not.exist' : 'be.visible');
});
});
Cypress sees N it calls and reports them individually. Each gets its own clean state under testIsolation: true.
For data loaded from a fixture, do the load synchronously at module level (avoid putting it inside before or you'll generate tests after the runner has fixed the list):
// Fails — tests aren't generated in time
before(() => {
cy.fixture('users').then((users) => {
users.forEach(...) // too late
});
});
// Works — load with require/import at the top
const users = require('../fixtures/users.json') as User[];
users.forEach((user) => {
it(`logs in as ${user.email}`, () => { ... });
});
For fully data-driven fixtures (not hard-coded), prefer importing the file as a module rather than cy.fixture — the latter is asynchronous and runs inside Cypress's queue, too late for test generation.