How to use Cypress for Vue E2E tests
End-to-end tests with Cypress verify complete user flows by running real browser interactions against your Vue application. As the creator of CoreUI with over 10 years of Vue.js experience since 2014, I’ve used Cypress to catch integration issues that unit tests miss, like broken API connections and routing bugs. The standard approach installs Cypress, writes specs using its chainable commands, and runs them against a local or staging server. This provides high confidence that users can actually complete their tasks.
Install Cypress and write your first spec.
npm install --save-dev cypress
npx cypress open
// cypress/e2e/login.cy.js
describe('Login flow', () => {
beforeEach(() => {
cy.visit('http://localhost:5173/login')
})
it('logs in with valid credentials', () => {
cy.get('input[name="email"]').type('[email protected]')
cy.get('input[name="password"]').type('password123')
cy.get('button[type="submit"]').click()
cy.url().should('include', '/dashboard')
cy.contains('Welcome, User').should('be.visible')
})
it('shows error with invalid credentials', () => {
cy.get('input[name="email"]').type('[email protected]')
cy.get('input[name="password"]').type('wrongpass')
cy.get('button[type="submit"]').click()
cy.contains('Invalid credentials').should('be.visible')
cy.url().should('include', '/login')
})
})
cy.visit() loads the URL in a real browser. cy.get() selects elements with CSS selectors. cy.type() simulates keyboard input. cy.click() triggers clicks. Assertions like should('be.visible') verify outcomes.
Testing a Todo List
Test CRUD operations on interactive UI.
// cypress/e2e/todos.cy.js
describe('Todo list', () => {
beforeEach(() => {
cy.visit('http://localhost:5173')
})
it('creates a new todo', () => {
cy.get('input[placeholder="Add a new todo..."]').type('Buy groceries')
cy.get('button').contains('Add').click()
cy.contains('Buy groceries').should('be.visible')
})
it('marks a todo as complete', () => {
cy.get('input[placeholder="Add a new todo..."]').type('Do laundry')
cy.get('button').contains('Add').click()
cy.contains('Do laundry')
.parent()
.find('input[type="checkbox"]')
.check()
cy.contains('Do laundry').should('have.css', 'text-decoration', 'line-through solid rgb(0, 0, 0)')
})
it('deletes a todo', () => {
cy.get('input[placeholder="Add a new todo..."]').type('Test todo')
cy.get('button').contains('Add').click()
cy.contains('Test todo')
.parent()
.find('button').contains('Delete')
.click()
cy.contains('Test todo').should('not.exist')
})
})
Each test creates its own data so tests are independent. The parent() traversal selects the containing element. check() checks checkboxes. not.exist verifies elements are removed from the DOM.
Intercepting API Calls
Mock API responses for reliable tests.
// cypress/e2e/users.cy.js
describe('User list', () => {
it('displays users from API', () => {
cy.intercept('GET', '/api/users', {
statusCode: 200,
body: [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' }
]
}).as('getUsers')
cy.visit('http://localhost:5173/users')
cy.wait('@getUsers')
cy.contains('Alice').should('be.visible')
cy.contains('Bob').should('be.visible')
})
it('shows error message on API failure', () => {
cy.intercept('GET', '/api/users', {
statusCode: 500,
body: { message: 'Server error' }
})
cy.visit('http://localhost:5173/users')
cy.contains('Failed to load users').should('be.visible')
})
})
cy.intercept() intercepts and stubs network requests. .as('getUsers') names the intercept for waiting. cy.wait('@getUsers') ensures the request completes before asserting. This makes tests deterministic without relying on real APIs.
Testing Forms with Validation
Verify form validation feedback.
describe('Registration form', () => {
beforeEach(() => {
cy.visit('http://localhost:5173/register')
})
it('shows validation errors on empty submit', () => {
cy.get('button[type="submit"]').click()
cy.contains('Name is required').should('be.visible')
cy.contains('Email is required').should('be.visible')
})
it('shows email format error', () => {
cy.get('input[name="email"]').type('not-an-email')
cy.get('button[type="submit"]').click()
cy.contains('Invalid email format').should('be.visible')
})
it('submits successfully with valid data', () => {
cy.intercept('POST', '/api/register', { statusCode: 201, body: { success: true } })
cy.get('input[name="name"]').type('John Doe')
cy.get('input[name="email"]').type('[email protected]')
cy.get('input[name="password"]').type('SecurePass123!')
cy.get('button[type="submit"]').click()
cy.url().should('include', '/dashboard')
})
})
Cypress tests validation messages directly in the UI. Empty submit reveals all required field errors. Intercepting the POST ensures the test doesn’t create real accounts.
Best Practice Note
This is the same Cypress testing approach we use for end-to-end testing of CoreUI templates. E2E tests are slower than unit tests - keep the suite focused on critical user journeys. Test the happy path and the most common error paths. Use cy.intercept() to control API responses rather than running against real backends. Add Cypress to your CI/CD pipeline to catch regressions automatically. Run E2E tests in parallel with cypress run --parallel for faster feedback. For component-level testing without a full server, use Cypress Component Testing.



