paint-brush
Setup, Run and Debug Cypress Tests: A Quick Guide To Get You Startedby@urmilla
303 reads
303 reads

Setup, Run and Debug Cypress Tests: A Quick Guide To Get You Started

by Urmilla KannuswamyMay 1st, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Cypress is a test automation tool that is free and open-source. The framework assists in end-to-end testing and component testing. This article contains information about installing, setting up, writing, and debugging tests in Cypress. A React application is used here as an example.
featured image - Setup, Run and Debug Cypress Tests: A Quick Guide To Get You Started
Urmilla Kannuswamy HackerNoon profile picture


Cypress is a test automation tool that is free and open-source. It is easy to set up Cypress and write, run, and debug tests. Cypress tests run inside the browser, making it known for its speed. It provides cross-browser testing capabilities. It can also be integrated into the CI/CD pipeline.


The first step in using Cypress would be to create a simple React application that has an image, some buttons, and text. These elements are then interacted with in Cypress. We can explore topics like the components in the Cypress Test Runner, how to debug a failing test, and more.


Create a React Application

To create a react app, run:

npx create-react-app react-cypress


To run the app, navigate into the folder and run the following command:

npm start


The simple application:

import { React, useState } from 'react'
import logo from './logo.svg';
import './App.css';

export default function App() {
  const [counter, setCounter] = useState(0);
 
  const resetCounter = () =>{
    setCounter(0)
  };
 
  const increaseCounter = () => {
    setCounter(count => count + 1);
  };
  const decreaseCounter = () => {
    setCounter(count => count - 1);
  };

  return (
    <div className="app">
      <header className="header">
        <img src={logo} data-cy="logo" className="logo" alt="logo" />
        <h3 data-cy="title">React and Cypress</h3>
        <p>Count: <span className="counter" data-cy="counter">{counter}</span> </p>
        <div className="counter-buttons-wrapper">
          <button className="counter-buttons" data-cy="increase" onClick={increaseCounter}>Increase Count</button>
          <button className="counter-buttons" data-cy="decrease" onClick={decreaseCounter}>Decrease Count</button>
        </div>
        <div className="counter-buttons-wrapper reset-button-wrapper">
          <button className="counter-buttons reset-button" data-cy="reset" onClick={resetCounter}>Reset</button>
        </div>
      </header>
    </div>
  );
}



Install and Setup Cypress

To install Cypress, run:

npm install cypress --save-dev


Cypress can be started with the open command or by adding a script in package.json.

//terminal command
npx cypress open

// script in package.json
"scripts": {
  "cytest": "cypress open"
}
npm run cytest


The first step in setting up Cypress is to choose between E2E and component testing. Choose E2E for this example.


The next window lists the configuration files that are generated automatically.



Tests can be run in Chrome, Electron, and Firefox. This selection is not set in stone. It can be changed later in the Test Runner screen.



Click ‘Create new spec’ to create a test file.



The next steps show the path where the new spec file is created and what the sample test looks like.



The automatically generated spec file can be run to see what the test runner looks like and what options it has.



Test Runner Components



Test Status & Log

The test status component shows a variety of information like:

  • Current status of the test suite
  • The number of tests in the current suite that passed or failed
  • A button to stop or reload the test suite
  • Duration of the test suite
  • Information about the test suite and the individual tests
  • Logs of the Cypress commands that were used
  • Stacktrace when a test fails


Live Preview

As the tests are executed, Cypress shows a live preview of the app.


URL

This field shows the current URL of the app shown in the live preview section.


Selector Finder

  • The crosshairs icon toggles the Selector Playground
  • Clicking on an element in the live preview section will show the selector information along with the number of matches for that particular element. In this case, there is only one button with such a selector.




The ‘print to console’ icon will print out the information of the selector, how many elements are available, and which element was found.



Browser & Viewport Size

This dropdown box contains a list of the browsers available for testing. Choosing one will open a new Test Runner window.



Write and Run a Cypress Test


describe('Simple React App', () => {

  beforeEach(()=> {
    cy.visit('http://localhost:3000/');
  });

  it('renders a logo', () => {
    cy.get('[data-cy="logo"]').should('have.css', 'height', '250px');
  });

  it('renders three buttons', () => {
    cy.get('[data-cy="increase"]').should('exist');
    cy.get('[data-cy="decrease"]').should('exist');
    cy.get('[data-cy="reset"]').should('exist');
  });

  it('increases and decreases the counter', () => {
    const increaseNumberOfTimes = 10;
    // Cypress has lodash support
    // It can be used to click on a button multiple times
    Cypress._.times(increaseNumberOfTimes, () => {
      cy.get('[data-cy="increase"]').should('exist').click();
    });
    cy.get('[data-cy="counter"]').should('have.text', '10');

    const decreaseNumberOfTimes = 3;
    Cypress._.times(decreaseNumberOfTimes, () => {
      cy.get('[data-cy="decrease"]').should('exist').click();
    });
    cy.get('[data-cy="counter"]').should('have.text', '7');
  });

  it('resets the counter', () => {
    cy.get('[data-cy="reset"]').should('exist').click();
    cy.get('[data-cy="counter"]').should('have.text', '0');
  });
});


What does this test do?

  • Load the localhost on port 3000 before every test
  • Check if a logo is rendered with a specific height
  • Check if three buttons are rendered
  • Click on the buttons to increase/decrease the counter and check the counter value.
  • Click on the button to reset the counter and check the value.


Selectors

It is a good practice to look for a DOM element with a custom attribute instead of looking for an element with a tag name, class, or ID. This test uses the data-cy attribute.

// bad
<button id="button1">Button 1</button>
<button id="button2">Button 2</button>
cy.get('button').click();

// okay
<button id="button1">Button 1</button>
<button id="button2">Button 2</button>
cy.get('#button1').click();

// best
<button data-cy="button1">Button 1</button>
<button data-cy="button2">Button 2</button>
cy.get('[data-cy="button1"]').click();


Bad Practice

Consider the example of selecting an element by its tag name. There are three buttons with different text and different IDs.

<button id="button1">Button 1</button>
<button id="button2">Button 2</button>
<button id="button3">Button 3</button>
cy.get('button').click();


The get command uses the tag name ‘button’ to find the element and then click on it.



The test runner throws the following error:


The click command can only be called on a single element.


Cypress found three elements with the tag name ‘button,’ but the click command was not executed since only one element can be clicked. The cy.get command is not clear enough. It does not say which one of the three buttons to click. In such a situation, it is better to select the element by IDs.


If there is a use case for clicking all the buttons, then a key called multiple has to be passed to the click function. It takes in a boolean value.

cy.get('button').click({ multiple: true })



In this scenario, the test case will click all the buttons once, and the test will pass.


Best Practice

Cypress recommends using a data-* attribute so that the selector does not get affected when there are CSS changes to the code.


With the data-* attributes, the selectors will be very specific, and there will be no confusion about which element the ‘get’ command uses in the test.




Run Tests in Headless Mode

Cypress tests can be run without the Test Runner GUI. It is less resource-intensive and, therefore, faster.

To start cypress in headless mode:

npx cypress run --headless



The default browser in this mode is Electron. To change the browser to Chrome or Firefox, use the browser flag in the command.

npx cypress run --headless --browser --firefox




Failing Test - Logs, Screenshots & Videos

Logs

When a test fails, the test status panel displays descriptive logs.



In this example, Cypress was not able to find an element with the [data-cy=“log”] selector. The logs show:

  • Which test failed and why?
  • How long did the test runner try to find the element before timing out?
  • The exact location of the failure is in the spec file.


Screenshots

Screenshots will be saved for all failing tests. This is the default behavior in Cypress. If this feature has to be disabled, then it has to be mentioned in the config file.

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {},
  },
  screenshotOnRunFailure: false
});


If there is a use-case to save a screenshot from the test suite, then the cy.screenshot() command can be used.

it('renders three buttons', () => {
  cy.get('[data-cy="increase"]').should('exist');
  cy.get('[data-cy="decrease"]').should('exist');
  cy.get('[data-cy="reset"]').should('exist');
  cy.screenshot();
});


The test result will have information as to where the screenshot is saved. It is usually saved in the cypress folder inside the project by default.



Videos

Videos of failing tests will be saved only when it is specified in the cypress.config.js file.

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {},
  },
  video: true
});



Like the screenshots, the videos will be saved in the Cypress folder inside the project.



Cypress is an amazing tool for test automation. As someone who has tried and still tries to follow the TDD approach, Cypress has succeeded in making writing tests fun. It is very beginner-friendly, and it makes it easy to test user interactions, network requests, and much more for web applications.




Reference