1 Cypress for beginners
A beginner-friendly guide to end-to-end testing with Cypress โ from installation to writing your first test, complete with commands, tips, and real-world examples.
- ๐ What is Cypress?
- โ๏ธ Installation
- ๐ Your First Test
- ๐ Common Cypress Commands
- ๐ป Cypress In-Depth Commands Guide
- ๐ก Tips & Best Practices
- ๐ Complete Test Example
- ๐ Quick Command Reference
- ๐ Learning Resources
- โ๏ธ Useful Configuration
- โ๏ธ CI/CD Integration
๐ What is Cypress?
Cypress allows you to write tests that run directly in the browser, mimicking how a real user interacts with your site. Unlike Selenium, it operates in the same run-loop as your application, making debugging much easier.
โ๏ธ Installation
In your JavaScript project, run the following command to add Cypress (works with any framework like Frappe, ReactJS, NextJS, etc.):
npm install cypress --save-dev
Initial Setup
- Run
npx cypress opento launch Cypress - Once opened, Cypress will create a folder named
cypress/with:e2e/โ for your test filessupport/โ custom commands and support logicfixtures/โ test datacypress.config.jsโ configuration file
- To run tests in headless mode, use
npx cypress run
๐ Your First Test
Create a test file at:
cypress/e2e/sample_test.cy.js
describe('My First Test', () => {
it('Visits the Portfolio website', () => {
cy.visit('https://kunj.pages.dev')
cy.contains('Kunj').should('exist')
})
})
Run Your Test
npx cypress open # Opens Cypress UI
npx cypress run # Headless mode
๐ Common Cypress Commands
| Command | Description |
|---|---|
cy.visit() |
Opens a webpage |
cy.get() |
Selects an element (like jQuery) |
cy.contains() |
Finds elements by text |
cy.click() |
Clicks an element |
cy.type() |
Types into input fields |
cy.should() |
Asserts something (like .should('be.visible')) |
๐ป Cypress In-Depth Commands Guide
1. Visiting Pages
cy.visit(url, options?)
Loads a web page in the browser.
Basic usage:
cy.visit('https://kunj.me')
With options:
cy.visit('/login', {
timeout: 10000,
onBeforeLoad: (win) => {
// stub or modify window object
}
})
2. Querying Elements
cy.get(selector)
Gets one or more DOM elements.
cy.get('button') // All buttons
cy.get('.btn-primary') // Class selector
cy.get('[data-cy=login-button]') // Best practice!
cy.contains(text)
Find element with specific text.
cy.contains('Submit') // Finds "Submit" text
cy.contains('button', 'Save') // Finds button with text "Save"
cy.find(selector)
Chained version of .get() used with parent element.
cy.get('.form').find('input[type="text"]')
3. Interactions
cy.click()
Clicks on an element.
cy.get('[data-cy=submit-button]').click()
cy.type(text)
Types text into an input.
cy.get('[data-cy=email]').type('kunj@gmail.com')
cy.get('[data-cy=password]').type('Secret123', { log: false }) // hides logs
cy.select(value)
Selects a value from a <select> dropdown.
cy.get('select').select('India')
cy.check() / cy.uncheck()
Checks or unchecks a checkbox or radio input.
cy.get('#terms').check()
cy.get('#subscribe').uncheck()
4. Assertions
should()
Used for assertions.
cy.get('h1').should('contain', 'Welcome')
cy.get('[data-cy=error]').should('not.exist')
cy.url().should('include', '/dashboard')
Common assertions:
.should('be.visible')
.should('be.enabled')
.should('have.value', 'Kunj')
.should('have.length', 3)
5. Waiting & Timing
cy.wait(time)
Pauses test execution for specified ms (not recommended unless needed).
cy.wait(2000) // waits for 2 seconds
cy.wait('@alias')
Waits for a specific network request.
cy.intercept('POST', '/api/login').as('login')
cy.get('form').submit()
cy.wait('@login').its('response.statusCode').should('eq', 200)
6. Network Requests
cy.intercept(method, url)
Intercepts (mocks or spies) a network request.
Example: Spying on login API
cy.intercept('POST', '/api/login').as('login')
cy.get('[data-cy=submit]').click()
cy.wait('@login').its('response.statusCode').should('eq', 200)
Example: Mocking (stubbing) a GET response
cy.intercept('GET', '/api/user', {
statusCode: 200,
body: { name: 'Kunj', role: 'Admin' },
}).as('getUser')
7. Custom Commands
You can write reusable commands in cypress/support/commands.js:
Cypress.Commands.add('login', (email, password) => {
cy.get('[data-cy=email]').type(email)
cy.get('[data-cy=password]').type(password)
cy.get('[data-cy=submit]').click()
})
Usage:
cy.login('kunj@gmail.com', 'Password123')
8. Fixtures (Mock Data)
Fixtures help you load external static JSON.
Create: cypress/fixtures/user.json
{
"email": "kunj@gmail.com",
"password": "secret123"
}
Use in test:
cy.fixture('user').then((user) => {
cy.get('[data-cy=email]').type(user.email)
cy.get('[data-cy=password]').type(user.password)
})
9. Aliases
as() to create aliases for reuse
cy.get('[data-cy=email]').as('emailInput')
cy.get('@emailInput').type('kunj@gmail.com')
10. State Management
Common state management commands:
cy.reload() // Reloads the page
cy.clearCookies() // Clears cookies
cy.clearLocalStorage() // Clears local storage
cy.scrollTo() // Scrolls element or window
Examples:
cy.scrollTo('bottom')
cy.get('.chat-box').scrollTo('top')
11. Test Structure & Hooks
describe('Login Flow', () => {
before(() => {
// Runs once before all tests
})
beforeEach(() => {
// Runs before each test
cy.visit('/login')
})
it('Should login with valid credentials', () => {
// Test case
})
afterEach(() => {
// Cleanup if needed
})
after(() => {
// Runs once after all tests
})
})
๐ก Tips & Best Practices
| Tip | Why |
|---|---|
Use data-cy attributes |
More stable than CSS or IDs |
Avoid .wait() unless necessary |
Use cy.intercept() instead |
| Write atomic, independent tests | Easier to debug and maintain |
Use beforeEach() to reset state |
Ensures clean start |
| Don't test implementation details | Test user behavior |
๐ Complete Test Example
describe('User Login Flow', () => {
beforeEach(() => {
cy.visit('/login')
cy.clearCookies()
cy.clearLocalStorage()
})
it('Should login successfully with valid credentials', () => {
// Intercept login API
cy.intercept('POST', '/api/login').as('loginRequest')
// Fill in credentials
cy.get('[data-cy=email]').type('kunj@gmail.com')
cy.get('[data-cy=password]').type('Password123', { log: false })
// Submit form
cy.get('[data-cy=submit-button]').click()
// Wait for API response
cy.wait('@loginRequest').its('response.statusCode').should('eq', 200)
// Verify redirect
cy.url().should('include', '/dashboard')
cy.contains('Welcome, Kunj').should('be.visible')
})
it('Should show error with invalid credentials', () => {
cy.get('[data-cy=email]').type('invalid@gmail.com')
cy.get('[data-cy=password]').type('WrongPass')
cy.get('[data-cy=submit-button]').click()
cy.get('[data-cy=error-message]')
.should('be.visible')
.and('contain', 'Invalid credentials')
})
})
๐ Quick Command Reference
// Navigation
cy.visit(url)
cy.go('back')
cy.reload()
// Querying
cy.get(selector)
cy.contains(text)
cy.find(selector)
// Interactions
cy.click()
cy.type(text)
cy.select(value)
cy.check() / cy.uncheck()
// Assertions
.should('be.visible')
.should('exist')
.should('have.value', value)
// Network
cy.intercept(method, url)
cy.wait('@alias')
// State
cy.clearCookies()
cy.clearLocalStorage()
cy.scrollTo(position)
// Utilities
cy.fixture(file)
.as('alias')
cy.wait(time)
๐ Learning Resources
- Cypress Docs: https://docs.cypress.io
- Real-world Examples: https://github.com/cypress-io/cypress-realworld-app
- Best Practices: https://docs.cypress.io/guides/references/best-practices
โ๏ธ Useful Configuration
cypress.config.js:
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:3000',
viewportWidth: 1280,
viewportHeight: 720,
video: false,
screenshotOnRunFailure: true,
defaultCommandTimeout: 10000,
},
})
โ๏ธ CI/CD Integration
Example GitHub Actions workflow:
name: Cypress Tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Cypress run
uses: cypress-io/github-action@v5
with:
start: npm start
wait-on: 'http://localhost:3000'