How to Build E2E Tests with Cypress & BitBar

  February 07, 2023

Software testing has become increasingly complex thanks to the twin threat of growing complexity and higher user expectations. Fortunately, testing tools continue to evolve, becoming easier to use, more feature-full, and offering better test coverage. Cypress is a prime example of these improvements in end-to-end testing.

Let's look at what end-to-end testing involves and how you can use Cypress and BitBar to streamline the process.

Cypress has become one of the most popular tools for end-to-end testing of web applications – but there are some key limitations.

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

End-to-end (E2E) tests validate the functionality and performance of an application under product-like circumstances using realistic test data. For example, you might create an end-to-end test to validate that a signup form works by having an algorithm enter an email address and password, click a signup button, and verify the user appears in the database. 

Many test-driven development (TDD) workflows begin with creating end-to-end tests describing a workflow. Then, developers write the code necessary to pass the E2E tests. As a result, product managers can confidently deploy new features while ensuring that future code changes don't break any existing user workflows.

Despite these benefits, there are some challenges associated with end-to-end tests. For example, they are typically more time-consuming than unit and integration tests since they usually spin up a headless browser or simulator and hit multiple parts of an application. They may also be more brittle since they interact with UI components that frequently change.

How Cypress Supports E2E Tests

Cypress is a test automation framework focused exclusively on end-to-end tests. The framework enables you to write tests in JavaScript to test any front-end framework or website, from React to server-rendered apps. As a result, it has become one of the most flexible and powerful ways to build E2E test suites for web-based applications.

Cypress makes it quick and easy to start testing. Source: Cypress

Four key factors set Cypress apart:

  • All-in-One – Cypress provides multiple tools under a single roof, eliminating the need to use a patchwork of technologies to run end-to-end tests. In other words, you don't need to install Selenium, TestDouble, Expect.js, and Nightwatch just to run a test suite.
  • Performance – Most end-to-end test automation tools use Selenium, but Cypress built a new architecture from the ground up. Rather than executing remote commands through a network, Cypress runs in the same run-loop as the app under test.
  • Flexibility – Cypress runs in a Node.js server process, providing access to front and backend components. As a result, you can expose data stores to alter the state from test code, use third-party components programmatically, and more.
  • Debugging – Cypress provides a rich user interface for debugging applications, showing you network requests, page loads, command executions, and other data. You can also use Dev Tools to see every console message or network request during a test.

Getting started with Cypress is simple:

  1. In your project directory, run `npm install cypress --save-dev`.
  2. Launch Cypress by running `npx cypress open`.
  3. Follow the setup instructions to customize your project.

Cypress Studio also enables you to record tests while interacting with the application, making it easy for non-technical testers to build automated E2E tests. However, the feature remains experimental and may have a few rough edges.

Cypress UI Testing Challenges

Cypress tests are similar to many other test automation tools powering E2E tests. For example, you can identify UI elements in the DOM by type or class and use functions like `click()` or `type()` to interact with these elements. Then, you can verify the actions show the correct pages using functions like `contains()` and `should()`.

Here's an example of an E2E test for logging in a user:

``` describe('login', () => { 
 it('should sign in a user', () => { 
 cy.visit('/');
 cy.get('button').contains('Login').click(); 
cy.get('input[type="email"]').type('[email protected]');
 cy.get('input[type="password"]').type('test123'); 
 cy.get('button').contains('Sign in').click(); 
 cy.contains('button', 'Sign out').should('be.visible');
 }); 
}); 
``` 

Unfortunately, these tests may not always produce the most accurate results since they don't guarantee these elements appear on the screen. For instance, in our example above, the "Sign out" button might appear in the DOM, but it may not visibly appear on a mobile device if there's a malformatted CSS media query or a container is too wide for a screen.

Browsers may also behave differently than Cypress' custom-built engine. For instance, client-side JavaScript may display elements correctly in Chrome but not Safari or other browsers. As a result, you may have to configure Cypress tests to run on different browsers and ensure they’re all installed on the test machines you use.

Using BitBar to Enhance UI Tests

BitBar makes it easy to run Cypress end-to-end tests on real devices in the cloud. That way, you can easily ensure applications appear correctly and run on every device and browser combination. You can also run tests in parallel across many devices, enabling your team to scale up your test suites and run them faster than ever.