Introduction to Cypress: Simplifying Front-End Testing

Harness the Power of Cypress for Efficient and Reliable Web Testing

Tolgahan Dayanikli
8 min readMay 24, 2024

Table of Contents

· Introduction
·
What is Cypress?
·
Why choose Cypress?
·
Getting Started with Cypress
·
Writing High-Quality Tests
·
Conclusion

Introduction

Front-end testing is critical to ensuring the quality and reliability of web applications. In this Medium post, we will examine Cypress, a powerful and user-friendly front-end testing tool. To get you started, we will discuss its key features and benefits and provide some practical code examples for better approaches.

What is Cypress?

Cypress is an end-to-end testing framework created especially for web applications. Cypress offers an accurate and reliable testing environment because it operates in the same run-loop as your application, in contrast to traditional testing tools.

Workflow Summary:

Cypress Architecture Diagram

Initialization:

  • Cypress starts by launching the proxy server and establishing a WebSocket connection with the browser.

Test Execution:

  • The test scripts, written in JavaScript, are executed by the Cypress process.
  • Cypress sends commands to the browser via WebSocket to interact with the web application. These commands can include actions like clicking buttons, filling out forms, and navigating through pages.

Network Interception:

  • The proxy server intercepts HTTP requests from the browser to the web application and HTTP responses back from the server. This allows Cypress to manipulate these requests and responses for testing purposes (e.g., simulating network errors or modifying response data).

Result Reporting:

  • The results of each test step are sent back to the Cypress process via WebSocket. Cypress logs these results and provides real-time feedback to the user.

Because of this architecture, Cypress can offer a reliable and consistent testing environment in which tests are run in an actual browser, simulating user interactions with the application. Cypress can fully control and monitor the testing process thanks to the use of a proxy server and WebSocket connection, which facilitates problem identification and debugging.

Why choose Cypress?

1. Developer-Friendly:

Cypress uses its test runner, which provides the following features:

Watch mode: Reruns the tests once the file is saved. (Can be changed)

Saved screenshots: Application snapshots are saved before and after each operation, which allows you to view exactly what happened throughout the test runs.

Videos: Tests run in headless mode automatically record videos that can be used as proof of bugs.

Development Tools: The browser’s console log elements returned by CSS selectors, queries made, and more can be found here.

Screenshots: Cypress automatically captures a screenshot of a failed test as proof of the test, which facilitates understanding and problem-solving.

2. Low Learning Curve:

Cypress is very easy to learn and use and provides detailed documentation support. However, knowledge of JavaScript (or TypeScript) and CSS selectors is essential.

3. All-in-one pack:

Several well-known tools, already well-known to the JavaScript community, are packed for usage with Cypress. These include the popular assertion libraries Mocha and Chai, the Sinon mock library, and Lodash, which has a tonne of features like jQuery, Moment, and more.

4. No Configurations to Get Started:

After installing and initializing Cypress, everything is ready to go without any configuration.

5. Control of Network Traffic:

Robust tests may be created by using capabilities likecy.intercept(), which allows you to intercept HTTP requests, give them an alias, and wait for them to complete before continuing.

6. Range of Testing Kinds

Apart from end-to-end testing, Cypress allows you to create and execute tests for components, APIs, front ends, visual regression, accessibility, and, if desired, a combination of all.

Getting Started with Cypress

Installation

First, let’s install Cypress. You can add it to your project using npm or yarn.

npm install cypress --save-dev
# or
yarn add cypress --dev

Initial Setup

After installation, you can open Cypress for the first time to set up the initial configuration. This command opens the Cypress Test Runner.

npx cypress open

Selecting the Test Scope

Cypress environment setup: Selecting the test scope
Cypress Configuration: Selecting the test scope

The website will be launched automatically, and here we will select whether we want to do end-to-end testing or component testing. We will proceed with E2E Testing.

Choosing a Browser

Cypress Configuration: Selecting the testing browser

In this step, we will select the browser that we desire. (It supports more browsers; I just don’t have them installed on my laptop.). We will go with Google Chrome.

Creating a New Spec File:

Cypress Configuration: Creating a test file (part 1)

Now, we can see our dashboard. Here, we will create a new spec file using the option on the right.

Cypress Configuration: Creating a test file (part 2)

You can name the file however you like. After the following selections, we will be navigated to the page where we can see our test results.

Running the Tests

The commands we used before created a new folder called cypress under the root directory. The folder has sub-folders such asdownloads, e2e,fixtures, andsupport.

  1. Downloads:
  • Purpose: This folder is used by Cypress to store files that are downloaded during the tests.
  • Usage: When your tests involve downloading files, you can verify the contents of these files by checking the downloads folder. This folder helps in managing file downloads and ensuring they work as expected during your end-to-end tests.

2. E2E:

  • Purpose: The e2e (end-to-end) folder contains your test specifications.
  • Usage: This is where you write your test cases. By default, Cypress places example spec files here to help you get started. You can create new files in this directory for each of your test suites.

3. Fixtures:

  • Purpose: Fixtures are static files used as external pieces of data for your tests.
  • Usage: You can store JSON files, images, or other static resources in this folder and use them within your tests. This is useful for mocking data that your application might fetch from an API.

4. Support:

  • Purpose: The support folder contains files for custom commands and global configurations or behaviors that modify Cypress.
  • Usage: This is where you can extend Cypress’s functionality by adding custom commands and setting up global behaviors. By default, there is a commands.ts file where you can define custom commands and an e2e.ts file for configuring settings that apply to all tests.

Writing Your First Tests

Let’s write a simple test to check if a webpage loads correctly. We will use the google.com for this purpose:

describe('Google Page', () => {
it('should load successfully', () => {
cy.visit('https://google.com');
});
});
Running your first test

As you can see, the test has passed because the webpage is loaded successfully. Now, let’s take it one step further. Let’s click the button “Accetta Tutto” (Accept All in English). To achieve this, we have to use the Selector Playground button at the left of the URL preview on the test website. Click the button and click the element to get its CSS selector.

Using selectors

As you can see, when I click the button with the help of the Selector Playground button, the CSS selector becomes visible. Copy that and paste it into your code as follows:

describe('Google Page', () => {
it('found the button', () => {
cy.visit('https://google.com');
cy.get('#L2AGLb > .QS5gu').click();
});
});

As a result, you can see that the test has passed by loading, and clicking the button. To not keep this blog post any longer, I am not going to deep dive into the complex examples. You can find a list of possible actions you may take in the official documentation.

Writing High-Quality Tests

Organize Your Test

  • Folder Structure: Organize your tests in a logical folder structure, typically under a cypress/integration directory. You can create subfolders based on features, pages, or components.
  • Test Files: Name your test files descriptively so it’s easy to understand what each test file covers.

Write Clear and Descriptive Tests

Use meaningful and descriptive names for your test cases. This makes it easier to understand what the test is doing without having to read the entire test code.

Use Page Objects Pattern

Page Objects: Encapsulate the interactions with page elements in separate files. This helps to keep your tests clean and DRY (Don’t Repeat Yourself).

// cypress/support/pageObjects/loginPage.js
class LoginPage {
visit() {
cy.visit('/login');
}

enterUsername(username) {
cy.get('input[name="username"]').type(username);
}

enterPassword(password) {
cy.get('input[name="password"]').type(password);
}

submit() {
cy.get('form').submit();
}
}

export const loginPage = new LoginPage();

Use Assertions Effectively

To verify the predicted behavior, make explicit assertions. Steer clear of general claims that might pass without confirming the right action. Tests for unexpected inputs and edge cases should be included. This makes your application more robust and aids in spotting possible problems.

describe('Form Validation', () => {
it('should display error for empty required fields', () => {
cy.visit('/form');
cy.get('#submitButton').click();
cy.get('#nameError').should('contain', 'Name is required');
});
});

Mock Network Requests

Make use of Cypress’s network request stub and intercepting capabilities. This makes it possible to test different situations without depending on real network responses. Moreover, examine how your program responds to various inputs, including failures, timeouts, and inconsistent data by simulating different responses.

describe('Network Requests', () => {
beforeEach(() => {
cy.server();
cy.route('POST', '/api/login', { success: true }).as('loginRequest');
});

it('should login successfully', () => {
cy.visit('/login');
cy.get('#username').type('validUser');
cy.get('#password').type('validPassword');
cy.get('#loginButton').click();
cy.wait('@loginRequest').its('response.body').should('have.property', 'success', true);
});
});

Use Fixtures and Data-driven Tests

Store and use test data in fixtures. This separates test data from test logic, making it easier to manage and update. Write tests that run multiple times with different data sets. This helps in verifying how your application handles various inputs.

describe('User Registration', () => {
beforeEach(() => {
cy.fixture('user').as('userData');
});

it('should register a new user', function() {
cy.visit('/register');
cy.get('#username').type(this.userData.username);
cy.get('#email').type(this.userData.email);
cy.get('#password').type(this.userData.password);
cy.get('#registerButton').click();
cy.get('.welcome').should('contain', 'Welcome, ' + this.userData.username);
});

it('should handle multiple users', function() {
cy.fixture('users').then((users) => {
users.forEach((user) => {
cy.visit('/register');
cy.get('#username').type(user.username);
cy.get('#email').type(user.email);
cy.get('#password').type(user.password);
cy.get('#registerButton').click();
cy.get('.welcome').should('contain', 'Welcome, ' + user.username);
});
});
});
});

Continues Integration (CI)

Set up your Cypress tests to run automatically in your CI/CD pipeline. This ensures that tests are executed regularly and consistently. Regularly review and monitor test results. Address any test failures promptly to maintain the health of your test suite.

name: CI

on: [push]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: '14'
- run: npm install
- run: npm run test

Conclusion

In this post, we discussed Cypress’s architecture, and its importance in front-end testing, and shared best practices for writing high-quality tests. Cypress stands out with its developer-friendly features, low learning curve, and powerful capabilities, making it an essential tool for ensuring web application quality. Thank you for reading, and happy testing!

Enjoyed this Article? Buy Me a Coffee ☕️

Hey there! 👋 If you found this post useful or enjoyable, consider buying me a coffee to help support my writing. It takes time and effort to craft these articles, and a little support goes a long way!

Whether it’s just a one-time coffee or a subscription, every bit counts and shows me that you value my work. Plus, it’s a great way to keep the creative juices flowing!

--

--

Tolgahan Dayanikli

Software Engineer at ManyDesigns srl & M.Sc. of Computer Engineering student in Genova, Italy