E2E tests with Cypress

Mohit Mutha
5 min readFeb 5, 2023

--

This is a continuation of the previous post where we setup component tests with Cypress. In this post we will setup our project for end to end (e2e) tests.

To recap in the previous post we had taken up the sample application where

  • User can input a number in a text box
  • The display blocks display the square, cube and the Fibonacci value of the number index
  • User can mark a number as favorite
  • The list of favorites is displayed and the user can do a quick select of the favorite number
  • User can add and remove favorites

If you have not followed the previous post then do the following to jump directly into the flow of this post

git clone https://github.com/mohitmutha/cypress-demo-app.git
cd cypress-demo-app
yarn install
git checkout -b mybranch COMPONENT_TESTS_COMPLETE

Now lets get into creating the base for executing e2e tests.

Open cypress by executing

yarn cypress open 

If all is well you should see a screen as below

Since we have already added some component tests the block for it appears Configured

Click on E2E testing block and follow the prompts

You should see some new files created under the cypress directory in the root of your project. A new file e2e.js is created and the existing cypress.config.js is modified.

A new block is added to the cypress.config.js We will not go into what extra can go into this block. For the purpose of this post we will keep this as-is, but in case the react app is ejected or some specific webpack overrides are required then this block will need to be modified.

----
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
----

Lets get down to creating our first test spec. Click on Create new spec

Name the spec page_basics.cy.js

This is a empty spec which goes to the example cypress website

Let us now add tests relevant to our application

Ensure that the application is running by executing from the root application directory

yarn start

The application should start and run on port 3000. Let us check by going to http://localhost:3000 in our browser.

Now let us modify our test to point to our application. Let us change the cy.visit statement that opens the application under test

cy.visit('http://localhost:3000')

Now let us add an assertion that the title of the page should be Calculator
Add below to the test so that test now looks like

describe('template spec', () => {
it('passes', () => {
cy.visit('http://localhost:3000')
cy.get('page-title').should('have.text','Calculator')
})
})

cy.get locates the element within the page based on the selector supplied. Cypress has a rich collection of selectors similar to jquery syntax.

This is going to fail as we have not added an test-id to our heading and the heading is News

So let us add a test id to our element but not change the title yet. Open the AppBar.js and chnage below line

<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
News
</Typography>

to

<Typography data-testid="page-title" variant="h6" component="div" sx={{ flexGrow: 1 }}>
News
</Typography>

Now let us change our test to use the data-testid instead. Change the test to

describe('template spec', () => {
it('passes', () => {
cy.visit('http://localhost:3001')
cy.get('[data-testid=page-title]').should('have.text','Calculator')
})
})

Note the difference in the error in assertion now. Previously it did not find the element and hence said expected to be Calculator but got ``. Now it says Expected to be Calculator but got News

Now let us fix our page so that the title is Calculator Change AppBar.js as below

<Typography data-testid="page-title" variant="h6" component="div" sx={{ flexGrow: 1 }}>
Calculator
</Typography>

Let us rerun our test. Our test should pass now

Now let us add a test to check if the calculations are correct when we enter a simple number in the input

it('input 5', () => {
cy.visit('http://localhost:3001')
cy.get('#input-value').type(5) //Locates the text input and type 5

//Assertions on the results
cy.get('#square-result-value').should('have.text',25)
cy.get('#cube-result-value').should('have.text',125)
cy.get('#fibonacci-result-value').should('have.text',3)
})

This should pass on running

As we did with the component tests, we can parameterize this to check for different inputs.

However we already see some problems with the tests we are writing

  • We are having to repeat code such as cy.visit
  • Assertions are repeated the code is repeated
  • The element locators are hard coded and will tend to repeat

We can resolve some of this by adding fixtures. Fixtures are added to hold the test data and are files located by default in the cypress/fixtures directory. Let us create a file for our element locators in the fixtures directory.

Create a file cypress/fixtures/elementLocators.json and add below content to it

{
"pageTitle": "[data-testid=page-title]",
"numberInput": "#input-value",
"squareResult": "#square-result-value",
"cubeResult": "#cube-result-value",
"fibonacciResult": "#fibonacci-result-value"
}

Now modify the test to use the fixture we just created. Change our tests to load the fixture and use values from it

describe('basic page check', () => {
it('header text', () => {
cy.visit('http://localhost:3001')
cy.fixture('elementLocators').then(elementLocators => { //Load the fixture
cy.get(elementLocators.pageTitle).should('have.text', 'Calculator') //Use the value
})

})

it('input 5', () => {
cy.visit('http://localhost:3001')
cy.fixture('elementLocators').then(elementLocators => { //Load the fixture
cy.get(elementLocators.numberInput).type(5) //Use the value
cy.get(elementLocators.squareResult).should('have.text', 25)
cy.get(elementLocators.cubeResult).should('have.text', 125)
cy.get(elementLocators.fibonacciResult).should('have.text', 3)
})
})
})

With this our test looks cleaner but still there is a lot of repetition. While cypress provides commands to create reusable statements and isolate code, I feel using BDD offers a better alternative. Commands can also be used with BDD and we will look at this in the next post.

The source code for the post is available at https://github.com/mohitmutha/cypress-demo-app

--

--