Easily test React-Redux with Cypress
Tags: javascript, react, redux
Published: 2021-03-19 09:51:38

Cypress is a very visual Javascript testing framework that can do end-to-end, integration and unit tests. One of its cool features, is the ease of querying elements with the tool on the test browser, especially when using frameworks like Semantic UI, Bootstrap, etc. because UI components are pre-defined and it's harder to know the underlying HTML elements making up the components.

## Quickly testing from the user's perspective

```javascript
    it('New project modal form is controlled', () => {

        cy.get('.eight > .button')
          .click()
          
        cy.get(':nth-child(2) > .ui > input')
          .type('Test title')
          .should('have.value', 'Test title')

        cy.get('textarea')
          .type('Test description')
          .should('have.value', 'Test description')

        cy.get('#new-project')
          .click()
   })
```

[Cypress](https://docs.cypress.io/guides/overview/why-cypress.html#In-a-nutshell) will give you the selectors like: `cy.get('.eight > .button')` (from their browser testing select feature), which give access to the element from the DOM. In this case, it is an input element so we can `.type` something into the input, check the updated value it `.should` have, and finally `.click()` on the submit button.

## Testing the store and the backend API

Cypress allows for end-to-end testing having access to asynchronous calls, and also the application environment. However, having access to our redux store can be a little tricky. 

First, because this data is only meant to exist inside the React application, and making it available to an external environment like Cypress can be insecure. 

```javascript
...
export const store = createStore(reducer, 
  applyMiddleware(thunk)
  );

...

if (window.Cypress) {
  window.store = store
}
...
```

Second, if the application state updates asynchronously, this requires the tests to only run after the state has updated. Cypress has several ways to deal with this like only testing the DOM elements on the surface instead of the Redux store underneath or testing the backend with asynchronous requests tests. 

But if we want to build an application starting from Redux, and focus on developing tests for the store we can use the [`cypress-pipe`](https://github.com/NicholasBoll/cypress-pipe) package, which helps Cypress wait to test the store when it's actually updated.

```javascript
    it('Adds a new user', () => {
      cy.visit('/projects')
      cy.get('[href="#/new-project"]').click()
      cy.get(':nth-child(2) > .ui > input').type('Test Title')
      cy.get('textarea').type('Test Description')
      cy.get('[type="submit"]').click()

      cy.request(`${URL}people`)
        .then((response) => {
          expect(response.status).to.eq(200)
        })

      const getProjects = (window) => window.store.getState().projects

      cy.window().pipe(getProjects).should('have.length', 5)
    })
```

Here we make a test of a new project feature on the site. So the test types the title and description and then submits it. We can have access to the store through the window object on the Cypress browser environment and test our Redux state with the right timing.

Feel more than welcome to reach out with any ideas/comments at [Linkedin](https://www.linkedin.com/in/santiago-salazar-pavajeau/) or [Twitter](https://twitter.com/santispavajeau), or check out my [portfolio](https://www.santiagosalazarpavajeau.live).