More tests with cypress.io!

Tun Khine
The Startup
Published in
5 min readNov 8, 2019

In a previous article, I covered integrating and writing your first tests using the end-to-end testing platform, cypress.io. This week, let’s delve into writing tests for some React components.

I recently was challenged to build a React app that had a few requirements. They included:

  • Use an API to fetch an object
  • Create a home page that displays the latest image on load
  • Create a search page with an input form to search & render an image

Some of the additional elements that were required involved specific className‘s for elements, which was a critical step in completing this challenge. I always hear the faint voices of my instructors, “READ THE F*CKING README.” Thanks to Tez & Hanaa for pushing me to improve my attention to detail!

Now normally, if I wasn’t under a time constraint, I’d follow TDD principles, but I need to be honest with myself, and YOU, I’m still learning and not proficient at writing tests while under the gun!

Adding Cypress to existing projects

One of the great things about using the cypress.io desktop client, you can drag and drop a project folder and et voila! Cypress is ready to go in your project. Alternatively you can use the command line by cd’ing into your project folder and using the below commands to install Cypress locally as a dev dependency for your project.

npm install cypress --save-dev

The tests we’ll be writing cover the following:

  • Our API responds and returns an object
  • Test our home component for specific criteria
  • Test our search component for specific criteria
  • Test our navbar component for specified criteria and navigation ability
  • Test our search form functionality

API tests

This might be one of the most important tests we write for this challenge. It’s the piece that requests and returns the data we want to display. Let’s remember we’ll need our describe or context block, it function and finally the assertion or should.

In our first API test, we’re wanting to make sure that we get a status code of 200 and a status text of OK. It might look something like:

Once we run it we’ll know that our API is working and returning a positive status. This leads to our next portion of our API test - the returning of an object of data.

We can use the same spec file to chain on another test to check the data we are returning. Having also tested the API in my favorite API tool, Postman, I knew that a single object will be returned with 11 key / value pairs.

The test I’ve implemented below will verify the schema of the returned object:

Home page tests

Our home page will need to display an image and also has three className requirements as outlined in the graphic below:

Great, let’s write some cypress tests to check those requirements off the list.

Our first home.spec.jstest, will check that specific elements on load have the correct className‘s. We first send the test to the correct URL, ask it to look for a specific dom element, and it should expect to have the correct className.

describe('Home page tests', () => {  beforeEach(() => {     
cy.visit('http://localhost:3006/')
})
it('should have specific class names for elements', () => {
cy.get('.search')
.should('have.class', 'search')
cy.get('.latest')
.should('have.class', 'latest')
})
Heck, yea. My favorite green check marks coming through.

Now that we understand how to write tests to check for className elements, let’s move on to the next home.spec.js test for checking if my fetched image gets rendered. We again point it to the correct URL, it should get a specific dom element with the className latestComic, and finally find the image and make sure it is visible.

Mr. Burns also enjoys passing tests.

Search page tests

Our search page/component has similar tests to our home page with regards to specific className‘s.

Our implementation of those elements will look like this:

Form testing

An additional feature of our search page is the form. This form will will take a value and then display an image.

Our first set of tests should select a specific dom element with a name of .searchInput, types some text, check its presence, clear it and finally check ensure there is no value.

context('Check search form functionality', () => {
beforeEach(() => {
cy.visit('http://localhost:3006/search')
})
it('.clear() - clears an input or textarea element', () => {
cy.get('.searchInput').type('Clear this text')
.should('have.value', 'Clear this text')
.clear()
.should('have.value', '')
})

The next set of tests takes us to form submission by again selecting a specific dom element and entering a value.

it('.submit() - submit a form and display an image', () => {
cy.get('.searchInput')
.type('303').should('have.value', '303')

We then chain on the selection of another dom element, this time the button, with className searchSubmit.

cy.get('.searchSubmit').click()

And finally we check that the image is displayed, again selecting a specific dom element and ensuring it contains an image.

cy.get('div[class="searchedComic"]').find("img")
.should('be.visible')

Our full form.spec.js should look like:

Navigation tests

The final set of tests will check the functionality of our navigation bar as well as the routes I’ve set up in the application. Those routes are / and /search respectively. Let’s dive right into it!

Our navbar has two clickable elements, a latest and search hyperlink. To ensure these are clickable elements, and that they load to the corresponding routes, we first need to select the navbar, look for the particular elements and then click them. Our test will look like:

describe('Test Navbar functionality', () => {
beforeEach(() => {
cy.visit('http://localhost:3006/'),
cy.get('.navbar-nav').contains('Latest').click()
// Cypress checks for a HTTP 200 response
cy.get('.navbar-nav').contains('Search').click()
// Cypress checks for a HTTP 200 response
})

The next part of our tests will verify path names

it('cy.go() - go back or forward in the browser\'s history', () => {  cy.go('forward')
cy.location('pathname').should('include', '/')
// clicking back cy.go(-1)
cy.location('pathname').should('not.include', 'search')
// clicking forward cy.go(1)
cy.location('pathname').should('include', 'search')
})

Our entire full navigation.spec.js should look like:

Conclusion

With the basic functionalities I’ve outlined above, you’ll get a long way testing your app. These examples show the ease and simplicity of cypress testing. It bundles the popular Chai assertion library and allows for simple and powerful chaining. In addition, the cypress.io website provides excellent documentation if you can’t find the answer to your problems!

The repo, with tests, can be found here. The application can be found here.

--

--

Tun Khine
The Startup

Software Engineer, former International Civil Servant, Dad, and new ATLien