Test Frontend and API Together with Cypress

Using Cypress in practice for combined test scenarios for improved productivity

Viduni Wickramarachchi
Bits and Pieces

--

Introduction

Software test automation is a mature area today. We can find various tools and practices that help us to automate testing for long-term maintainability.

Nowadays, we are also looking into different strategies to make test automation more productive.

Having front-end and API testing together is one such strategy that I found quite useful.

This article will focus on using Cypress for API and end-to-end testing while providing detailed insights on how to use it in your projects.

Pre-requisite: Basic knowledge about Cypress and how to write tests in Cypress.

What is end-to-end testing?

End-to-end testing (also known as E2E) checks whether an application is working as expected or not, by testing the user flow. It is the basic idea of testing an application from the start to finish.

Cypress is a JavaScript E2E testing framework that has been growing in popularity for the past few years.

I believe Cypress.io is a better replacement for Selenium.

Besides, it is built on top of Mocha and runs in the browser, enabling asynchronous testing.

How does Cypress support E2E testing?

  • Cypress test runner — Allows you to set up and write tests and watch them execute in real-time.
  • Cypress dashboard — This allows you to run tests, debug tests in CI and record CI test data, screenshots and video.

In a nutshell, if you have a form component in your application, using Cypress you can test whether the form works as expected by accepting the correct data for the inputs, test validations, and submitting the form data to receive the expected output. Each stage of the test follows the user flow of submitting the form.

Cypress even allows you to time travel and see what exactly happened at each step and also debug directly and find out why any tests are failing, if they are.

Especially since Cypress automatically waits for commands and assertions, a complete end-to-end test of submitting a form is possible without creating artificial waits or any async hell.

Further, cross-browser testing is not a problem anymore! 😃

Cypress runs tests within Firefox, Chrome family browsers, Edge, and Electron locally.

I believe most of you have a basic idea of setting up Cypress and writing a Cypress test. Therefore, I won’t go into detailed explanations about Cypress basics in this article. Just to get a head start, let’s look at a sample test for my form example mentioned previously.

If you look at the code, up to line 16, it tests the input data in the form for validations. This falls under frontend testing. Next with cy.intercept() , the test focuses on stubbing an XHR request in order to submit the form. That falls under API testing.

Likewise, a Cypress test can be used for both test scenarios where the entire user flow of a particular feature can be tested. However, it's important to note that cy.intercept was released with Cypress 4.x. Earlier releases of Cypress required cy.server() and cy.route() to stub an XHR request.

Besides, the XHR request is triggered by the Cypress Test Runner (in Node.js). Therefore, you won’t be able to see the request inside your Developer Tools.

With the use of Cypress, there are many benefits of having test automation for frontends and APIs together. Let’s look at a few.

Benefits of frontend and API testing together

  • All tests can be branched and versioned together.
  • Saves time as there will be less maintenance when everything is in one place.
  • Allows end-to-end user flow (functional) tests that assure the stability of the application.
  • Enables faster execution of tests as there is only one test suite for both frontend and APIs.
  • Allows testing the application in a specific state with the use of API caching before e2e testing.
  • Since Cypress runs on the browser, all the tests are run very close to the application. Therefore, Cypress is even able to cache APIs and reuse them in order to make navigation to components faster in e2e testing. This improves the testing performance drastically.

Special features available when using Cypress in practice

Test Debugging

Knowing only how to write a test isn’t sufficient if you are using a tool like Cypress. The beauty lies in the extra features it provides. One such crucial feature — Tests Debugging.

Cypress test code runs in the same run loop as the application

Therefore, it has access to the code that is being run on that page while making browser features available as well such as the debugger.

There are a few ways you can debug the test.

  1. Using the debugger in DevTools.
  2. Using debugger inside tests.
  3. Using .debug() — This is a shorthand provided by Cypress to expose the element in concern to the console. The user can interact with it and debug using the console.
  4. Step through tests command by command using .pause() — Allows you to inspect the DOM, network, etc., after each command.

Test re-tries

Most testing tools do not allow automatic test re-runs. However, with a simple configuration, Cypress supports test re-runs for X number of times. The configuration is as follows.

{
"retries": {
// Configure retry attempts for `cypress run` (default: 0)
"runMode": 2,
// Configure retry attempts for `cypress open` (default: 0)
"openMode": 0
}
}

This can be configured for all tests or individual tests. If a test suite or an individual test fails due to a timeout error, this mechanism will avoid the test suite getting halted immediately. Instead, it’ll re-run the failed test, the specified number of times. This avoids unnecessary halting of test suites due to random errors such as timeout errors. The fact that a manual re-run is not required in such a scenario makes Cypress efficient than other testing tools.

Waits for DOM elements

Unlike Selenium, Cypress waits for the DOM elements to appear before running tests. You don’t have to use mechanisms like thread.sleep or waitForTheMoon helpers anymore.

Downsides to Cypress

  • E2E tests may require business-level tests as custom functionality may be required when testing both front-end and APIs together. However, creating business-level commands in Cypress using custom commands is difficult.
  • Does not have out-of-the-box support for Page Object Model (POM). Cypress does not encourage separating element locators into a different layer of page objects. Therefore, a simple change in the frontend UI would break all automated e2e tests tied to it.
  • Limited browser support — Currently Cypress only supports Chrome family browsers (including Electron and Chromium-based Microsoft Edge) and Firefox
  • Cannot persist local storage — After each test run local storage and cookies are cleared
  • Parallelization support — Requires multiple machines to run tests in parallel
  • No native event handling capabilities — No support for upload, download file, tab key, etc. (However, it is in their roadmap)

Summary

Cypress is a great tool for end-to-end testing and makes it enjoyable with a visual experience. Unlike many other testing tools, Cypress is not based on Selenium, hence can grow more powerful in the future. According to my experience with Cypress, I became a fan of it due to the following reasons.

  • Cypress supports any framework quite well. It also works with older server-rendered applications.
  • Cypress is written in JavaScript. Therefore, being a JavaScript developer, it is very convenient as there are no external languages or driver bindings.
  • There are no dependencies. You can merely run your tests by adding them to the package.json.
  • It has clear syntax and a good debugging ability which captures a screenshot for every step.
  • It is faster than other end-to-end testing tools which are based on Selenium.
  • And most importantly, we can test both user scenarios as well as API tests together.

The Cypress documentation is also very comprehensive which makes it easier for developers to learn and adapt to it. It's growing on a fast scale where the latest 5.x release has support for Shadow DOM, experimental network stubbing support, etc. I feel like future releases will give solutions to the current downsides of the tool as well. Therefore, it is definitely worth learning about it. Don’t forget to have a look at the best practices when using Cypress as well.

Let me know your thoughts about testing your applications with Cypress. Thanks for reading!

Build Great Design Systems and Micro Frontends

Take frontend development to the next level with independent components. Build and collaborate on component-driven apps to easily unlocks Micro Frontends, and to share components.

OSS Tools like Bit offer a great dev experience for building and composing independent components, and build solo or together with your team.

Give it a try →

An independently source-controlled and shared “card” component. On the right => its dependency graph, auto-generated by Bit.

--

--