As your test suite grows, repetition accumulates. Cypress gives you two tools to fight it: fixtures for static test data, and custom commands for repeated interaction sequences.
Fixtures
Fixtures are JSON (or other) files stored in cypress/fixtures/. Load them with cy.fixture().
// cypress/fixtures/user.json
{
"email": "alice@example.com",
"password": "s3cr3t",
"name": "Alice"
}// Use in a test
cy.fixture('user').then((user) => {
cy.get('#email').type(user.email)
cy.get('#password').type(user.password)
})
// Or load as an alias
cy.fixture('user').as('currentUser')
cy.get('@currentUser').then((user) => {
cy.get('#name').should('contain', user.name)
})Custom Commands
Add reusable commands to cypress/support/commands.js:
// cypress/support/commands.js
Cypress.Commands.add('login', (email, password) => {
cy.session(
[email, password],
() => {
cy.visit('/login')
cy.get('#email').type(email)
cy.get('#password').type(password)
cy.get('[data-cy="submit"]').click()
cy.url().should('include', '/dashboard')
},
{
cacheAcrossPecs: true,
}
)
})
Cypress.Commands.add('loginAsAdmin', () => {
cy.fixture('admin-user').then((user) => {
cy.login(user.email, user.password)
})
})Now every test can call cy.login() instead of repeating the login flow:
describe('Dashboard', () => {
beforeEach(() => {
cy.login('alice@example.com', 's3cr3t')
})
it('shows user profile', () => {
cy.visit('/dashboard')
cy.get('[data-cy="username"]').should('contain', 'Alice')
})
})cy.session() — Session Caching
cy.session() caches the browser session (cookies, localStorage) after the first login and restores it on subsequent runs. This saves the round-trip to the login page on every test.
First test: cy.session() → runs login flow → caches session
Second test: cy.session() → restores cache → skips login (fast)Command Reuse Visualiser
Custom command flow
Ctrl+Enter
HTML
CSS
JS
Preview
TypeScript Declarations
If you use TypeScript, add your commands to the global Cypress interface:
// cypress/support/index.d.ts
declare namespace Cypress {
interface Chainable {
login(email: string, password: string): Chainable<void>
loginAsAdmin(): Chainable<void>
}
}
Now cy.login() gets autocomplete and type checking in your IDE.