Write End-to-End Test Flows
Cypress makes the process of writing e2es relatively simple with lots of built-in methods and documentation to show you the way to use it effectively.
Write end-to-end test flows#
In the last lesson, we prepared Hardware Handler to use Cypress as its end-to-end testing framework and installed a few extra helper libraries to ensure that the tests we write are quality tests.
Now it's time to start writing those tests.
In this lesson, we'll walk through adding a few end-to-end tests, getting into progressively more complex test setup and actions as we go.
Add a base URL for all Cypress tests#
Cypress describes itself as a testing framework made to run during active development, and since that is its primary goal, it makes it easy to do some minor configurations, like setting a baseUrl
property that automatically prefixes common Cypress commands like cy.visit
and cy.request
with this URL.
Open up the cypress.json
file that was created at the root of our client/
folder when we installed Cypress into the project. It should be an empty object right now, and go ahead and add the following property.
{
"baseUrl": "http://localhost:3000"
}
This simple line will prevent us from having to type localhost:3000
over and over again as we add end-to-end tests that navigate around to different pages within the app.
Cool. With that little bit of setup done, let's write our first test.
Create a new navigation_spec.js file#
The first end-to-end test file I want to add — one that requires less pre-seeding of data and more generically tests our app's functionality — is to run the app and navigate to each page via the nav bar links and check each page loads.
So, let's make a new file inside of the Cypress folder's integration/
folder named navigation_spec.js
. This is where we'll write our first test using the very same describe
and it
test syntax we're already used to from the integration testing.
For Cypress to work correctly, the app must already be running locally
Be aware that for Cypress to be able to run end-to-end tests locally, our app should already be running in a separate terminal window.
Trying to start the server from a Cypress test is considered an anti-pattern. You can read more about the reasoning behind this decision by Cypress here.
Bottom line: just start the app locally before starting your e2e tests.
Write a test for our site's nav links#
Our first test isn't going to be fancy. It's also not going to be very complicated because we want to get a feel for how Cypress works and expects things to be structured. Let's just make a test to ensure that after our app loads, all of its links in the nav bar successfully move us between different pages in Hardware Handler, and those pages load. Should be simple enough.
Inside of our navigation_spec.js
file, let's make a describe
block and an it
statement testing this functionality.
describe('Navigating around the site', () => {
it('should successfully visit all the pages linked to in the nav bar', () => {});
});
The first thing any of our tests will need to do is visit our locally running app, and from there, we can start clicking the nav links. Add two lines to our test to visit our app's home page, and we'll check that the page loads, and we can see the page title.
it('should successfully visit all the pages linked to in the nav bar', () => {
cy.visit('/');
cy.get('h1').should('contain', 'Welcome to Hardware Handler!');
Cypress's testing syntax feels pretty intuitive (to me, anyway). cy.visit
brings us to a particular URL in the app, and cy.get
lets us target particular elements on the page (you can do it by HTML tag, element ID or class, data
test attributes, and more), which we can then use in a variety of ways. In this first case, we'll check the text that's present in the DOM.
After we've confirmed the homepage has loaded, let's start targeting (and clicking) each nav link and making sure that each page loads. To do this, we'll use Cypress's cy.get
to target each text link within the nav bar and click it, then check the <h1>
element that's visible is the right one for that page.
Here's how I'd write this test to check that the My Products page loads.
cy.get('.navbar-links-wrapper').within(() =>
cy.contains('My Products').click(),
);
cy.get('h1').should('contain', 'My Products');
After this code takes us to the list of products page, we'll repeat the same process to check each of our other pages. So here's the rest of how that test would look, checking the Add New Products and Checkout pages.
cy.get('.navbar-links-wrapper').within(() =>
cy.contains('Add New Products').click(),
);
cy.get('h1').should('contain', 'Add A New Product');
cy.get('.navbar-links-wrapper').within(() => cy.contains('Checkout').click());
cy.get('h1').should('contain', 'Checkout');
And that's about all I want to do with this first test case. Now's the time to give our one test a try.
Start our app up locally in one terminal window if it's not already running:
cd client/ && yarn start
In a second terminal window, run the Cypress command:
cd client/ && yarn cypress:run
With any luck, the test to navigate around the site to various pages should pass.

Refactor our command to target nav bar links#
After writing our first successful e2e, you might notice there's a bit of duplicate code here — the duplication I notice is how we're targeting each link in the nav bar.
This is a good opportunity to turn this bit of code into a reusable command that any Cypress test will be able to utilize.
Make a navigation_commands.js
support file
To do this, let's head over into our cypress/support/
folder and create a new commands/
folder.
Inside of the new folder, make a new file named navigation_commands.js
. In this file, we'll take the code we were using to target each nav link and make it into a reusable function in which we pass the link text to tell it which link to click.
Here's one way we could do that.
export const goToPageFromNavBar = (link) =>
cy.get('.navbar-links-wrapper').within(() => cy.contains(`${link}`).click());
Add the new command to the commands.js
file
To make this function accessible in the whole testing suite, we also need to add this new file's exports to the commands.js
file, also in the support/
folder.
The commands.js
file already has some sample commands commented out, but I'm just going to leave them for future reference and work around them.
First, import any and all navigation commands we've defined in our new navigation_commands.js
file.
import * as navigationCommands from './commands/navigation_commands';
Then, give that individual command a name that Cypress tests can use to reference it. Names similar to the function name itself are easiest to remember.
Cypress.Commands.add(
'goToPageFromNavBar',
navigationCommands.goToPageFromNavBar
);
With this completed, any Cypress test should be able to use this new custom command.
This page is a preview of The newline Guide to Modernizing an Enterprise React App