A comprehensive JavaScript-based Cypress automation testing framework designed to take you from beginner to advanced testing hero. This repository contains complete examples, best practices, and practical guides for mastering Cypress testing.
- Overview
- Prerequisites
- Languages & Technologies
- File Structure
- Installation & Setup
- How to Use
- Cypress Methodologies Covered
- Key Features
- Getting Started
- npm Scripts
- Troubleshooting
- Contributing
- Resources
- License
- Support & Contact
This project is your complete guide to mastering Cypress for automated testing. Whether you're testing web applications or APIs, you'll learn everything from basic setup to advanced frameworks and real-world testing scenarios.
What You'll Learn:
- Cypress fundamentals and core concepts
- Web and API testing automation
- Advanced selector strategies
- Real-world testing scenarios
- CI/CD integration (Jenkins, GitHub Actions)
- Git and GitHub workflows
- Page Object Model patterns
- Data-driven testing approaches
Why Cypress?
- ⚡ Fast, reliable, and intuitive
- 🎯 Better debugging experience
- 📱 Responsive testing capabilities
- 🔄 Excellent CI/CD integration
- 💪 Strong community and support
Before you begin, ensure you have the following installed on your system:
- Node.js (v14.0 or higher) - Download
- npm (v6.0 or higher) - Comes with Node.js
- Git (v2.0 or higher) - Download
- Basic JavaScript fundamentals (variables, functions, arrays, objects)
- Understanding of HTML/CSS selectors
- Basic command line/terminal usage
- Familiarity with testing concepts
- Visual Studio Code or any preferred code editor - Download
- Chrome/Firefox/Edge browser (for testing)
- Git Bash (for Windows users)
- Jenkins (for CI/CD examples, optional)
- JavaScript (100%) - All test scripts and automation code
| Technology | Version | Purpose |
|---|---|---|
| Cypress | Latest | Web and API automation testing |
| Node.js | v14+ | JavaScript runtime environment |
| npm | v6+ | Package manager |
| Git | v2+ | Version control |
| Jenkins | Optional | CI/CD pipeline automation |
- Mocha - Test framework (built into Cypress)
- Chai - Assertion library (built into Cypress)
- Cypress Plugins - Extended functionality
Cypress-Automation-Testing-Hero-JavaScript/
│
├── README.md # This file
├── LICENSE # MIT License
├── package.json # Project dependencies and scripts
├── cypress.config.js # Cypress configuration file
│
├── cypress/
│ ├── e2e/ # End-to-end test files
│ │ ├── basic-tests/ # Basic Cypress tests
│ │ ├── advanced-tests/ # Advanced testing scenarios
│ │ └── api-tests/ # API testing examples
│ │
│ ├── support/ # Support files and utilities
│ │ ├── commands.js # Custom Cypress commands
│ │ ├── e2e.js # E2E test setup
│ │ └── helpers.js # Helper functions
│ │
│ ├── fixtures/ # Test data and mock responses
│ │ ├── test-data.json # Sample test data
│ │ └── mock-responses/ # API mock responses
│ │
│ └── pages/ # Page Object Model (POM)
│ ├── base.page.js # Base page class
│ ├── login.page.js # Login page object
│ ├── dashboard.page.js # Dashboard page object
│ └── common.page.js # Common page elements
│
├── config/
│ ├── cypress.env.json # Environment variables
│ ├── dev.config.js # Development configuration
│ └── prod.config.js # Production configuration
│
├── scripts/
│ ├── run-tests.js # Test runner script
│ └── generate-report.js # Report generation
│
├── reports/ # Test reports (generated)
│ └── screenshots/ # Failure screenshots
│
└── .gitignore # Git ignore file
cypress/e2e/ - Contains all test files organized by test type
cypress/support/ - Custom commands, hooks, and helper functions
cypress/fixtures/ - Test data files in JSON format
cypress/pages/ - Page Object Model classes for maintaining tests
config/ - Environment-specific configurations
reports/ - Generated test reports and screenshots
git clone https://github.com/BrianGator/Cypress-Automation-Testing-Hero-JavaScript.git
cd Cypress-Automation-Testing-Hero-JavaScriptnpm installThis installs:
- Cypress
- Required plugins
- Testing libraries and dependencies listed in
package.json
npx cypress --versionCreate a cypress.env.json file in the config/ directory:
{
"baseUrl": "https://example.com",
"apiUrl": "https://api.example.com",
"username": "testuser",
"password": "testpassword",
"env": "staging"
}npm run cypress:opennpm run cypress:openThis opens the Cypress Test Runner GUI where you can select and run tests interactively.
npm run cypress:runnpx cypress run --spec "cypress/e2e/basic-tests/login.cy.js"npx cypress run --browser chrome
npx cypress run --browser firefoxnpx cypress run --config baseUrl=https://staging.example.comnpm run report:generatedescribe('Login Functionality', () => {
beforeEach(() => {
cy.visit('/login');
});
it('should login with valid credentials', () => {
cy.get('[data-testid="username"]').type('testuser');
cy.get('[data-testid="password"]').type('password123');
cy.get('button[type="submit"]').click();
cy.url().should('include', '/dashboard');
});
it('should display error with invalid credentials', () => {
cy.get('[data-testid="username"]').type('invaliduser');
cy.get('[data-testid="password"]').type('wrongpassword');
cy.get('button[type="submit"]').click();
cy.get('.error-message').should('be.visible');
});
});Selecting elements efficiently is crucial for reliable tests. Cypress supports multiple selector strategies:
// By element type
cy.get('button');
// By class name
cy.get('.login-button');
// By ID
cy.get('#username');
// By attribute
cy.get('[data-testid="submit-button"]');
// By multiple selectors
cy.get('input[type="password"]');
cy.get('form .error-message');
// Descendant selector
cy.get('.login-form input[type="text"]');// XPath selectors
cy.xpath('//button[contains(text(), "Login")]');
cy.xpath('//input[@name="email"]');
cy.xpath('//div[@class="error"]//span');// Using data-testid (recommended approach)
cy.get('[data-testid="username"]').type('testuser');
cy.get('[data-testid="password"]').type('password123');
cy.get('[data-testid="submit-button"]').click();// ✅ GOOD: Specific, stable selectors
cy.get('[data-testid="login-button"]');
cy.get('#userId');
cy.get('.primary-button');
// ❌ AVOID: Too generic, fragile selectors
cy.get('div');
cy.get('.container .row .col .btn');
cy.xpath('//div[1]/div[2]/div[3]/button[1]');Cypress commands can be chained together for efficient test writing. Each command returns a Cypress object for the next command.
// Chaining multiple actions
cy.get('[data-testid="username"]')
.type('testuser')
.should('have.value', 'testuser')
.clear()
.type('newuser');// Perform action and verify result
cy.get('button')
.click()
.should('have.class', 'active')
.should('be.enabled');// Work with multiple elements
cy.get('li')
.should('have.length', 3)
.first()
.should('have.text', 'Item 1')
.last()
.should('have.text', 'Item 3');describe('Form Submission', () => {
it('should submit form successfully', () => {
cy.visit('/contact')
.get('[data-testid="name"]')
.type('John Doe')
.get('[data-testid="email"]')
.type('john@example.com')
.get('[data-testid="message"]')
.type('Hello World')
.get('button[type="submit"]')
.click()
.get('.success-message')
.should('contain', 'Form submitted successfully');
});
});Cypress automatically waits for elements and commands, but sometimes explicit waits are needed for asynchronous operations.
// Cypress waits automatically (default 4000ms)
cy.get('[data-testid="element"]'); // Waits up to 4 seconds
// Configure default timeout
cy.get('[data-testid="slow-element"]', { timeout: 10000 });// Wait for specific condition
cy.get('button[type="submit"]').click();
cy.get('.loader').should('not.exist');
cy.get('.success-message').should('be.visible');// Wait for API response
cy.intercept('GET', '/api/users').as('getUsers');
cy.visit('/users');
cy.wait('@getUsers').then((interception) => {
expect(interception.response.statusCode).to.equal(200);
});// Wait for element to be enabled
cy.get('button').should('be.enabled');
// Wait for element to be visible
cy.get('.modal').should('be.visible');
// Wait for text to appear
cy.get('.status').should('contain', 'Processing complete');
// Wait for attribute value
cy.get('input').should('have.value', 'expected-value');describe('Async Operations', () => {
it('should handle async data loading', () => {
cy.visit('/dashboard');
// Intercept the API call
cy.intercept('GET', '/api/dashboard').as('loadDashboard');
// Trigger action that makes API call
cy.get('[data-testid="refresh"]').click();
// Wait for the API response
cy.wait('@loadDashboard');
// Verify data is displayed
cy.get('.dashboard-content').should('be.visible');
cy.get('.card').should('have.length.greaterThan', 0);
});
});The Page Object Model is a design pattern for creating reusable, maintainable test code by encapsulating page elements and actions.
// cypress/pages/base.page.js
export class BasePage {
constructor() {
this.timeout = 10000;
}
visit(url) {
cy.visit(url);
return this;
}
getElement(selector) {
return cy.get(selector);
}
clickElement(selector) {
this.getElement(selector).click();
return this;
}
typeText(selector, text) {
this.getElement(selector).type(text);
return this;
}
verifyText(selector, text) {
this.getElement(selector).should('contain', text);
return this;
}
verifyElementVisible(selector) {
this.getElement(selector).should('be.visible');
return this;
}
verifyElementNotVisible(selector) {
cy.get(selector).should('not.be.visible');
return this;
}
}// cypress/pages/login.page.js
import { BasePage } from './base.page';
export class LoginPage extends BasePage {
constructor() {
super();
}
// Element selectors
usernameInput = '[data-testid="username"]';
passwordInput = '[data-testid="password"]';
loginButton = 'button[type="submit"]';
errorMessage = '.error-message';
rememberMeCheckbox = '[data-testid="remember-me"]';
// Page actions
navigate() {
this.visit('/login');
return this;
}
enterUsername(username) {
this.typeText(this.usernameInput, username);
return this;
}
enterPassword(password) {
this.typeText(this.passwordInput, password);
return this;
}
clickLoginButton() {
this.clickElement(this.loginButton);
return this;
}
toggleRememberMe() {
this.clickElement(this.rememberMeCheckbox);
return this;
}
login(username, password) {
this.enterUsername(username);
this.enterPassword(password);
this.clickLoginButton();
return this;
}
verifyErrorMessage(expectedMessage) {
this.getElement(this.errorMessage)
.should('be.visible')
.should('contain', expectedMessage);
return this;
}
verifySuccessfulLogin() {
cy.url().should('include', '/dashboard');
return this;
}
}// cypress/pages/dashboard.page.js
import { BasePage } from './base.page';
export class DashboardPage extends BasePage {
constructor() {
super();
}
// Element selectors
welcomeMessage = '.welcome-message';
userProfile = '[data-testid="user-profile"]';
logoutButton = '[data-testid="logout"]';
navigationMenu = '[data-testid="nav-menu"]';
dashboardTitle = '.dashboard-title';
// Page actions
verifyUserLoggedIn(username) {
this.verifyElementVisible(this.welcomeMessage);
this.getElement(this.welcomeMessage)
.should('contain', `Welcome, ${username}`);
return this;
}
navigateTo(menuItem) {
this.getElement(this.navigationMenu)
.contains(menuItem)
.click();
return this;
}
logout() {
this.clickElement(this.logoutButton);
return this;
}
verifyDashboardLoaded() {
this.verifyElementVisible(this.dashboardTitle);
return this;
}
}// cypress/e2e/basic-tests/login.cy.js
import { LoginPage } from '../../pages/login.page';
import { DashboardPage } from '../../pages/dashboard.page';
describe('Login Feature', () => {
let loginPage;
let dashboardPage;
beforeEach(() => {
loginPage = new LoginPage();
dashboardPage = new DashboardPage();
loginPage.navigate();
});
it('should login successfully with valid credentials', () => {
loginPage
.enterUsername('testuser')
.enterPassword('password123')
.clickLoginButton();
dashboardPage
.verifyUserLoggedIn('Test User')
.verifyDashboardLoaded();
});
it('should display error with invalid credentials', () => {
loginPage
.login('invaliduser', 'wrongpassword')
.verifyErrorMessage('Invalid username or password');
});
it('should remember user when checkbox is selected', () => {
loginPage
.toggleRememberMe()
.login('testuser', 'password123');
dashboardPage.verifyUserLoggedIn('Test User');
});
});Assertions verify that the application behaves as expected. Cypress uses Chai assertion library with BDD syntax.
// Equality assertions
cy.get('[data-testid="count"]').should('have.text', '5');
cy.get('input').should('have.value', 'expected-value');
cy.get('button').should('have.class', 'active');
// Visibility assertions
cy.get('.modal').should('be.visible');
cy.get('.hidden-element').should('not.be.visible');
// Enable/Disable assertions
cy.get('button').should('be.enabled');
cy.get('input[disabled]').should('be.disabled');// Exact text match
cy.get('h1').should('have.text', 'Dashboard');
// Partial text match
cy.get('h1').should('contain', 'Dashboard');
// Case-insensitive match
cy.get('h1').invoke('text').then(text => {
expect(text.toLowerCase()).to.include('dashboard');
});// Check number of elements
cy.get('li').should('have.length', 5);
cy.get('.item').should('have.length.greaterThan', 0);
// Check first/last elements
cy.get('li').first().should('contain', 'Item 1');
cy.get('li').last().should('contain', 'Item 5');
// Filter and check
cy.get('li').contains('Item 3').should('exist');// Check URL
cy.url().should('include', '/dashboard');
cy.url().should('eq', 'https://example.com/dashboard');
// Check location pathname
cy.location('pathname').should('eq', '/dashboard');// Chain multiple assertions
cy.get('[data-testid="error"]')
.should('be.visible')
.should('have.class', 'error-message')
.should('contain', 'Error occurred');
// Assertion with callback
cy.get('.count').then($el => {
expect(parseInt($el.text())).to.be.greaterThan(0);
});describe('Advanced Assertions', () => {
it('should validate form submission', () => {
// Submit form
cy.get('form').submit();
// Multiple assertions
cy.url().should('include', '/success');
cy.get('.success-message')
.should('be.visible')
.should('contain', 'Form submitted successfully');
cy.get('.confirmation-number').should('exist');
});
it('should validate API response data', () => {
cy.intercept('GET', '/api/users').as('getUsers');
cy.visit('/users');
cy.wait('@getUsers').then((interception) => {
// Validate response structure
expect(interception.response.statusCode).to.equal(200);
expect(interception.response.body).to.have.property('data');
expect(interception.response.body.data).to.be.an('array');
});
});
});Test APIs directly using Cypress's cy.request() and cy.intercept() commands.
// GET request
cy.request('GET', '/api/users').then((response) => {
expect(response.status).to.equal(200);
expect(response.body).to.have.property('data');
});
// POST request
cy.request('POST', '/api/users', {
name: 'John Doe',
email: 'john@example.com'
}).then((response) => {
expect(response.status).to.equal(201);
expect(response.body).to.have.property('id');
});
// PUT request
cy.request('PUT', '/api/users/1', {
name: 'Jane Doe'
}).then((response) => {
expect(response.status).to.equal(200);
});
// DELETE request
cy.request('DELETE', '/api/users/1').then((response) => {
expect(response.status).to.equal(204);
});cy.request({
method: 'GET',
url: '/api/protected-resource',
headers: {
'Authorization': 'Bearer token123',
'Content-Type': 'application/json'
}
}).then((response) => {
expect(response.status).to.equal(200);
});// Expect error response
cy.request({
method: 'POST',
url: '/api/users',
body: { email: 'invalid-email' },
failOnStatusCode: false
}).then((response) => {
expect(response.status).to.equal(400);
expect(response.body).to.have.property('error');
});// Intercept and mock API response
cy.intercept('GET', '/api/users', {
statusCode: 200,
body: {
data: [
{ id: 1, name: 'User 1' },
{ id: 2, name: 'User 2' }
]
}
}).as('getUsers');
cy.visit('/users');
cy.wait('@getUsers');
cy.get('.user-item').should('have.length', 2);describe('API Testing', () => {
beforeEach(() => {
cy.visit('/api-test');
});
it('should fetch users list', () => {
cy.intercept('GET', '/api/users').as('getUsers');
cy.get('[data-testid="load-users"]').click();
cy.wait('@getUsers').then((interception) => {
expect(interception.response.statusCode).to.equal(200);
expect(interception.response.body).to.be.an('array');
});
});
it('should create user via API', () => {
const newUser = {
name: 'John Doe',
email: 'john@example.com',
role: 'user'
};
cy.request('POST', '/api/users', newUser).then((response) => {
expect(response.status).to.equal(201);
expect(response.body.id).to.exist;
expect(response.body.name).to.equal('John Doe');
});
});
it('should validate API error handling', () => {
cy.request({
method: 'POST',
url: '/api/users',
body: { email: 'invalid' },
failOnStatusCode: false
}).then((response) => {
expect(response.status).to.equal(400);
expect(response.body.errors).to.exist;
});
});
});Use fixtures to load test data from JSON files for data-driven testing.
// cypress/fixtures/users.json
{
"validUser": {
"username": "testuser",
"password": "password123",
"email": "test@example.com"
},
"invalidUser": {
"username": "invaliduser",
"password": "wrongpassword"
},
"users": [
{ "id": 1, "name": "User 1", "email": "user1@example.com" },
{ "id": 2, "name": "User 2", "email": "user2@example.com" }
]
}describe('Using Fixtures', () => {
beforeEach(() => {
// Load fixture before each test
cy.fixture('users.json').as('userData');
});
it('should login with fixture data', function() {
cy.visit('/login');
cy.get('[data-testid="username"]').type(this.userData.validUser.username);
cy.get('[data-testid="password"]').type(this.userData.validUser.password);
cy.get('button[type="submit"]').click();
cy.url().should('include', '/dashboard');
});
it('should display error with invalid fixture user', function() {
cy.visit('/login');
cy.get('[data-testid="username"]').type(this.userData.invalidUser.username);
cy.get('[data-testid="password"]').type(this.userData.invalidUser.password);
cy.get('button[type="submit"]').click();
cy.get('.error-message').should('be.visible');
});
});describe('Data-Driven Testing', () => {
const testCases = [
{ username: 'user1', password: 'pass1', expected: 'success' },
{ username: 'user2', password: 'pass2', expected: 'success' },
{ username: 'invalid', password: 'wrong', expected: 'error' }
];
testCases.forEach(testCase => {
it(`should handle login for ${testCase.username}`, () => {
cy.visit('/login');
cy.get('[data-testid="username"]').type(testCase.username);
cy.get('[data-testid="password"]').type(testCase.password);
cy.get('button[type="submit"]').click();
if (testCase.expected === 'success') {
cy.url().should('include', '/dashboard');
} else {
cy.get('.error-message').should('be.visible');
}
});
});
});Configure environment-specific settings for different environments (dev, staging, production).
// config/cypress.env.json
{
"baseUrl": "https://example.com",
"apiUrl": "https://api.example.com",
"username": "testuser",
"password": "testpassword",
"env": "staging"
}// cypress.config.js
import { defineConfig } from 'cypress';
export default defineConfig({
e2e: {
baseUrl: process.env.CYPRESS_BASE_URL || 'https://example.com',
apiUrl: process.env.CYPRESS_API_URL || 'https://api.example.com',
env: {
environment: process.env.CYPRESS_ENV || 'staging',
username: process.env.CYPRESS_USERNAME || 'testuser',
password: process.env.CYPRESS_PASSWORD || 'testpassword'
}
}
});describe('Environment Configuration', () => {
it('should use environment variables', () => {
// Access via cy.config()
const baseUrl = Cypress.config('baseUrl');
const apiUrl = Cypress.env('apiUrl');
expect(baseUrl).to.include('example.com');
expect(apiUrl).to.include('api');
});
it('should login to correct environment', () => {
const username = Cypress.env('username');
const password = Cypress.env('password');
cy.visit('/login');
cy.get('[data-testid="username"]').type(username);
cy.get('[data-testid="password"]').type(password);
cy.get('button[type="submit"]').click();
});
});# Development environment
npx cypress run --env baseUrl=https://dev.example.com
# Staging environment
npx cypress run --env baseUrl=https://staging.example.com
# Production environment (for smoke tests)
npx cypress run --env baseUrl=https://example.comLearn various techniques for debugging and troubleshooting Cypress tests.
describe('Debugging Techniques', () => {
it('should debug test execution', () => {
cy.visit('/dashboard');
// Pause execution for inspection
cy.pause();
cy.get('[data-testid="user-profile"]')
// Output to browser console
.debug()
.click();
// Step through execution
cy.step('Check dashboard content');
});
});it('should leverage browser devtools', () => {
cy.visit('/dashboard');
// Open DevTools (in headed mode)
cy.get('body').then(() => {
debugger; // This pauses in Chrome DevTools
});
});describe('Screenshots and Videos', () => {
it('should capture screenshots', () => {
cy.visit('/dashboard');
cy.get('.important-element').screenshot('dashboard-view');
cy.screenshot('full-page-screenshot');
});
afterEach(function() {
// Automatically capture screenshot on failure
if (this.currentTest.state === 'failed') {
cy.screenshot('failure-screenshot');
}
});
});describe('Console Logging', () => {
it('should log information', () => {
cy.visit('/dashboard');
cy.get('h1').then(($heading) => {
// Log to Cypress command log
cy.log('Heading text: ' + $heading.text());
// Log to browser console
console.log('Element found:', $heading);
});
});
});# Run tests with extended debugging
npm run cypress:run:debug
# Or with specific debug flags
DEBUG=cypress:* npm run cypress:runIntegrate Cypress tests into CI/CD pipelines for automated testing.
# .github/workflows/cypress-tests.yml
name: Cypress Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: npm install
- name: Run Cypress tests
run: npm run cypress:run
- name: Upload artifacts
if: always()
uses: actions/upload-artifact@v2
with:
name: cypress-screenshots
path: cypress/screenshotspipeline {
agent any
stages {
stage('Setup') {
steps {
sh 'npm install'
}
}
stage('Run Tests') {
steps {
sh 'npm run cypress:run'
}
}
stage('Generate Report') {
steps {
sh 'npm run report:generate'
}
}
}
post {
always {
junit 'cypress/results/*.xml'
archiveArtifacts artifacts: 'cypress/screenshots/**'
}
}
}FROM cypress/base:latest
WORKDIR /app
COPY . .
RUN npm install
CMD ["npm", "run", "cypress:run"]Explore advanced Cypress features for complex testing scenarios.
// cypress/support/commands.js
Cypress.Commands.add('login', (username, password) => {
cy.visit('/login');
cy.get('[data-testid="username"]').type(username);
cy.get('[data-testid="password"]').type(password);
cy.get('button[type="submit"]').click();
cy.url().should('include', '/dashboard');
});
Cypress.Commands.add('selectDropdown', (selector, value) => {
cy.get(selector).click();
cy.contains(value).click();
});
// Usage in tests
describe('Custom Commands', () => {
it('should use custom commands', () => {
cy.login('testuser', 'password123');
cy.selectDropdown('[data-testid="role-dropdown"]', 'Admin');
});
});describe('iframe Handling', () => {
it('should interact with iframe content', () => {
cy.visit('/page-with-iframe');
// Get iframe element
cy.get('iframe[id="myFrame"]')
.then($iframe => {
const $body = $iframe.contents().find('body');
cy.wrap($body).find('[data-testid="button"]').click();
});
});
});describe('Shadow DOM Testing', () => {
it('should interact with shadow DOM elements', () => {
cy.get('custom-element')
.shadow()
.find('button')
.click();
});
});describe('File Operations', () => {
it('should upload file', () => {
cy.visit('/upload');
cy.get('input[type="file"]')
.selectFile('cypress/fixtures/test-file.csv');
cy.get('[data-testid="upload-btn"]').click();
cy.get('.success-message').should('be.visible');
});
it('should verify file download', () => {
cy.visit('/download');
cy.get('[data-testid="download-btn"]').click();
cy.readFile('cypress/downloads/report.pdf')
.should('exist');
});
});Follow these best practices for writing maintainable, reliable tests.
// ✅ GOOD: Well-organized test structure
describe('Login Feature', () => {
beforeEach(() => {
cy.visit('/login');
});
describe('Valid Credentials', () => {
it('should login successfully', () => {
// Test implementation
});
it('should remember user when checkbox is selected', () => {
// Test implementation
});
});
describe('Invalid Credentials', () => {
it('should display error message', () => {
// Test implementation
});
it('should not navigate to dashboard', () => {
// Test implementation
});
});
});// ❌ AVOID: Flaky test with arbitrary waits
it('should load data', () => {
cy.get('button').click();
cy.wait(2000); // Arbitrary wait - unreliable
cy.get('.data').should('be.visible');
});
// ✅ GOOD: Explicit wait for specific condition
it('should load data', () => {
cy.get('button').click();
cy.get('.loader').should('not.exist'); // Wait for loader to disappear
cy.get('.data').should('be.visible');
});// ✅ GOOD: Efficient selector usage
cy.get('[data-testid="submit"]').click();
// ❌ AVOID: Inefficient selectors
cy.get('div').get('.container').get('form').get('button').click();// ✅ GOOD: Use environment variables for sensitive data
const username = Cypress.env('testUsername');
const password = Cypress.env('testPassword');
// ❌ AVOID: Hardcoding credentials
const username = 'admin';
const password = 'admin123';// ✅ GOOD: Extract common logic
const loginSteps = (username, password) => {
cy.get('[data-testid="username"]').type(username);
cy.get('[data-testid="password"]').type(password);
cy.get('button[type="submit"]').click();
};
describe('Login Tests', () => {
it('should login successfully', () => {
cy.visit('/login');
loginSteps('testuser', 'password123');
cy.url().should('include', '/dashboard');
});
it('should show error with invalid credentials', () => {
cy.visit('/login');
loginSteps('invalid', 'wrong');
cy.get('.error-message').should('be.visible');
});
});✅ Comprehensive Examples - From basic to advanced testing scenarios
✅ Page Object Model - Well-structured, maintainable tests
✅ API Testing - Complete guide to testing APIs with Cypress
✅ CI/CD Ready - Jenkins and GitHub Actions configurations
✅ Environment Configuration - Easy switching between dev, staging, production
✅ Real-World Scenarios - Practical examples you can use immediately
✅ Custom Commands - Reusable test utilities
✅ Data-Driven Tests - Parameterized testing with fixtures
✅ Detailed Reports - Comprehensive test reporting
✅ Best Practices - Industry-standard patterns and conventions
✅ Advanced Features - iframes, Shadow DOM, file operations
-
Clone the repository
git clone https://github.com/BrianGator/Cypress-Automation-Testing-Hero-JavaScript.git cd Cypress-Automation-Testing-Hero-JavaScript -
Install dependencies
npm install
-
Open Cypress
npm run cypress:open
-
Run your first test
- Select a test file from the Test Runner
- Watch it execute in real-time
- Explore example tests in
cypress/e2e/ - Learn the Page Object Model in Page Object Model section
- Customize
cypress.env.jsonwith your test URLs - Write your first custom test!
- Review Best Practices section for code quality tips
{
"scripts": {
"cypress:open": "cypress open",
"cypress:run": "cypress run",
"cypress:run:headed": "cypress run --headed",
"cypress:run:debug": "cypress run --headed --browser chrome --no-exit",
"report:generate": "cypress run && node scripts/generate-report.js",
"test": "cypress run"
}
}# Clear npm cache and reinstall
npm cache clean --force
npm install- Increase timeout in
cypress.config.js:defaultCommandTimeout: 10000 - Use explicit waits:
cy.get('selector', { timeout: 15000 }) - Check Waiting & Synchronization section
- Use Cypress Selector Playground (highlighted in Test Runner)
- Verify element exists and is visible
- Check for dynamic IDs or class names
- Review Selector Strategies section
- Check network tab in Chrome DevTools
- Verify baseUrl and API endpoints in Environment Variables
- Check for CORS issues
- Review API Testing section
- Enable debug mode:
npm run cypress:run:debug - Check Debugging & Troubleshooting section
- Review test videos and screenshots in
cypress/screenshots/
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Copyright © 2024 Packt
For issues, questions, or feedback:
- Open an issue on GitHub
- Check existing issues for solutions
- Review the Cypress documentation
- Refer to troubleshooting section
Happy Testing! 🎉
Transform yourself into a Cypress Automation Testing Hero! Start with the basics and master advanced techniques step by step. Use the table of contents to navigate to specific topics and expand your testing expertise.