During our monthly internal day - Haxorz, I recently held a workshop dedicated to End-to-End testing using Cypress. The workshop was mainly for internal needs, but I thought the topic was something a wider audience could appreciate as well.
I assume that you are here because you want to start or just have started a journey with End-to-End testing. I hope you will find this post useful as an introduction to Cypress Framework: what is it, when to use it and, above all, how to use it. Let’s get started.
What is End-to-End testing?
End-to-End testing is a technique that scans the entire software ensuring that everything is working as expected and flows smoothly. It defines system dependencies and checks for integrations. The goal of E2E is to check the software from the user perspective to avoid malfunctions caused by a failure of any of the subsystems. To find out more about this type of software evaluation, go to the post How To Conduct End-To-End Testing In Endtest.io?.
End-to-End tests are usually conducted at the end of the development cycle as they cover the UI and analyse whether the application is pleasant to use and the users can achieve exactly what they need to. They are also crucial for checking moving parts of software like servers, configuration and other external dependencies.
What is Cypress?
Cypress is a free, open-source automation testing tool created for modern web applications like React or Vue.js. Most interestingly, it is not based on Selenium and therefore works inside the browser DOM elements. What is more, it beats Selenium-based tools in terms of speed, reliability and ease of use.
Initially, it was developed for unit testing, to be later extended for E2E automation testing.
Cypress provides a visual interface to highlight which tests and commands are running, passed or failed. It is helpful for testing interactive applications, allows DOM manipulation, reading and writing data into/from fields, creating redirect and submitting forms.
The tool uses NPM for JavaScript, making it extremely easy to use with basic knowledge of JavaScript.
With the help of Cypress, End-to-End, integration and unit tests are super easy to write and debug.
Pros and cons of Cypress.io
There should be no surprises that with every tool come pros and cons. Among the advantages of using Cypress, there are:
- high execution speed
- ability to take screenshots and videos
- easy debugging
- visualisation of the running tests and commands
However, the tool has some limitations:
- limited browser support (Chrome and Firefox)
- only supports JavaScript
- does not support mobile or native events
Let’s now move on to End-to-End testing and briefly explain what it is all about.
Why Cypress?
As mentioned above, Cypress is fast, reliable and easy to use. As it is highly independent, it is suitable for many projects on the web. It could be integrated into an existing project or run alongside other testing environments. The setup is easy and there are only two prerequisites to Cypress: installing Node.js and any code editor.
When talking about why Cypress is the right tool for testing it is worth mentioning its core concepts:
- leveraging jQuery’s powerful selector engine - Cypress uses jQuery’s DOM querying API, which allows selecting any elements and shortens the test code. However, keep in mind Cypress is not like jQuery and if it will be unable to find any matching DOM elements it will automatically retry the query until the element is found or a timeout is reached.
- asynchronous nature and relying on timeouts - it is crucial to understand that Cypress commands do not do anything at the moment they are invoked, but rather queue themselves to be run later. This means Cypress knows when to stop waiting on an app to get into the expected state. It will try to run the given command until it succeeds or timeouts and fails.
- commands do not return their subjects, they yield them - Cypress chains commands together - with each command yielding a subject to the next command until the chain ends or an error is encountered. There is no need to use Promises directly, however, having an understanding of them can be helpful.
- no need to assert to have a useful test - many commands have built-in assertions letting you perform actions like ensuring an element is visible or has a particular attribute, CSS class or state. Assertions enable you to describe the desired state of the application while Cypress will wait until the elements reach this state or fail the test. To get more info about that go to the documentation.
Additionally, Cypress offers a complete End-to-End testing experience with Cypress test runner and Cypress dashboard. More about that on the official website.
Setup and configuration: Timeouts and stuff
Now that we have discussed all the for and against and got to know Cypress, it is time to start the setup and begin testing. Let’s begin with the commands.
To install Cypress, in the project folder run:
npm i cypress --save-dev
in order to add Cypress as a project development dependency.
And then:
node_modules/.bin/cypress open
to start a test manager. Cypress will automatically add some tests in Cypress/integration folder - remove all of them and create your own test file.
Then, inside the newly created file add an actual test case, in the it
block write:
If that is a bit confusing, a complete guide to Cypress testing can be found here.
Additionally, there is a git repo that contains the whole app that is tested using Cypress where you can find various practices and approaches to use when writing tests with Cypress, check out the real-world app.
When Cypress is added to a project it creates a cypress.json file on its first run and that's the place where you should customize your global Cypress configuration.
Let me show you some configuration options and other useful commands.
Configuration options
baseUrl
- URL used as prefix for cy.visit() or cy.request() command’s URLdefaultCommandTimeout
- time in milliseconds until default (eg.cy.get
,cy.contains
etc.) commands are considered timed outresponseTimeout
- time in milliseconds until a response is considered timed outviewportHeight/Width
- height/width in pixels for the application viewport
Documentation - Cypress options
Navigating, getting and interacting with elements
cy.visit("<url>")
- Visit a remote URL, one of the first commands in your test casecy.get("<selector>")
- Get one or more DOM elementscy.contains("<text_or_regexp>")
- Get the DOM element containing the textsubject.click()
- Click a DOM element.subject.type("<text_to_type>")
- Type into a DOM elementsubject.within(<callback>)
- Scopes all subsequent cy commands to within this elementsubject.then(<callback>)
- Enables to work with the subject yielded from the previous command
Making assertions
- with explicit subjects - eg.
expect([]).to.be.empty
, - with implicit subjects -
subject.should("your_chainer_here")
- eg.cy.get("error").should("be.empty")
can be chained using.and
Debugging
cy.pause()
- pauses the test execution in given momentcy.debug()
- inserts JavaScript debugger, requires Developer tools opened
Summary
Cypress is an amazing tool for E2E testing, which, in my opinion, is far better than Selenium.
Because of the ease of writing tests, high execution time and simple debugging it is a great solution for developers with any amount of experience, especially those with JavaScript knowledge. Not to mention it is reliable and independent.
However, you should keep in mind that there are some limitations like browser compatibility and the lack of support for native events.
If you are looking for a specialized developer or a team not only for executing End-to-End tests but also for building a high-quality solution from start to finish, contact Selleo. Our fully-fledged teams of experienced engineers will be happy to help you augment your existing team or outsource the project altogether. Feel free to get in touch to get a free quote and schedule a call.