If you’re looking for an end-to-end testing solution for your web application, you should certainly give Cypress a try. If you still need to support Internet Explorer, you’re probably better off with Selenium. If you need to support WebKit, checkout Playwright. However, if your userbase is primarily on Edge, Chrome or one of the other Chromium based browsers or on Mozilla Firefox, Cypress is well-worth a look.

What is End-to-End (e2e) Testing?

Before we look at Cypress, let’s level-set by defining what end-to-end testing is. In the context of a web-application, an end-to-end test is testing the application at the browser level – automating the interaction with your application via the browser, much like how your real users use (and test) your applications.

It can also be considered black-box testing as you can write end-to-end tests against any web application out there, not just the ones you own, without needing any special hooks into the backend. But in practice, having some hooks into the application can certainly make things easier by allowing you some shortcuts and thus help in the maintainability of your tests.

Getting Started

You can download the bits directly from the cypress.io website or load it into your frontend app through an npm install:

npm install --save-dev cypress

This downloads the Cypress test runner and related bits – Electron-based application which can run on Windows, Mac, and Linux machines. You can start it up by running cypress open. The application fires up and out-of-the-box, you get a rich set of sample tests that showcase the various capabilities of Cypress.

Cypress test-runner with example tests loaded.

Clicking on any of these files will open the selected test browser (Chrome 99 is selected in the screenshot above) and it will execute all the tests within it.

A run of one of the example suites in Cypress

The test runner arranges each test grouping and tests contained in the group (more on this below) in the left-panel. You can click on them, allowing you to drill down to each step that was executed in that test. Clicking on each step will give you a snapshot of the application at that given point in the execution of the step, in the right-hand panel.

What Does a Test Look Like?

The syntax, the fluent-API, was a great draw for me in adopting Cypress. The tests read very cleanly. And if you have any prior experience with the query selectors of jQuery, you’ll feel right at home with Cypress tests. You can target an element by its id using the # symbol, a css-class by using a period (dot) symbol, using the element name, using data- attributes, just like you do in jQuery. Each block begins with a describe statement and within it, you can nest one or more it statements.

describe('example to-do app', () => {
  beforeEach(() => {
    cy.visit('https://example.cypress.io/todo')
  })

  it('displays two todo items by default', () => {
     cy.get('.todo-list li').should('have.length', 2)
    cy.get('.todo-list li').first().should('have.text', 'Pay electric bill')
    cy.get('.todo-list li').last().should('have.text', 'Walk the dog')
  })

  it('can add new todo items', () => {
    const newItem = 'Feed the cat'
    cy.get('[data-test=new-todo]').type(`${newItem}{enter}`)

    cy.get('.todo-list li')
      .should('have.length', 3)
      .last()
      .should('have.text', newItem)
  })
})

You also get a few hooks that you can use to execute a set of statements prior to an entire group of tests, before each test, after each test or once after an entire group of tests are executed.

before(() => {
  // root-level hook
  // runs once before all tests
})

beforeEach(() => {
  // root-level hook
  // runs before every test block
})

afterEach(() => {
  // runs after each test block
})

after(() => {
  // runs once all tests are done
})

Why Cypress?

There are so many things to love about Cypress. Below, I’ll list a few that I find especially appealing:

Great Documentation: I love tech tools that have great documentation and Cypress documentation is awesome. They have several guides, rich examples, and detailed API reference material, as well. In addition to this, I also see that they have a great presence in the community, and you can hunt down a lot of talks and demos on YouTube and elsewhere, many with Cypress employees, themselves.

Great API: Writing Cypress test automation is a joy. The fluent API is well, fluent. It flows. The intent is crystal-clear. Your code reads very well.

No (Manual) Waiting: If you’ve done any Selenium testing in the olden days, you’ll probably remember all the arbitrary pauses that you had to pepper your tests with… to wait for network calls to come back, for animations to settle down, etc. Although I have run into the occasional flakiness or quirk with my Cypress tests, for the vast majority of things, Cypress will run your tests effectively without you having to specify any manual waits.

Snapshots: Every step that you took in your tests is listed out neatly in the test-runner. You can click on each of them and see what the application looked like at that very instance.

Hot Reload: After you get Cypress running, you can switch over to your code, make a couple of changes, save, and switch back to Cypress and you’ll see that it is automatically re-running your tests. May not seem like much at first glance but those little touches certainly sets them apart from the rest of the pack.

Closing Remarks

Although they don’t eliminate the need for unit-tests and integration tests, end-to-end tests are quite gratifying and often provide a very realistic picture of your application as they in many ways mimic the behaviors of a real user. If you have put off e2e testing in your apps due to perhaps bad prior experiences with poorer tools, or due to the effort it took to get going, give Cypress a shot.

Leave a Comment

Your email address will not be published. Required fields are marked *