How to access Redux state in Cypress
Tags: react, redux, cypress, testing
Published: 2020-06-20 15:09:20

---
title: How to access Redux state in Cypress
published: true
date: 2020-06-20 00:00:00 UTC
tags: react, redux, cypress,testing
canonical_url: https://adityanaik.dev/how-to-access-redux-state-in-cypress
---

### Set up our application

I borrowed the code from [react-redux.js.org](https://react-redux.js.org/introduction/basic-tutorial#a-todo-list-example) which showcases **react + redux** in action using a todo list application.

### Set up and scaffold Cypress

[Cypress](https://www.cypress.io/) is a fantastic testing framework. It is easy to set up and can be picked up pretty quickly.

Setting up Cypress is pretty straight forward - just run:

```bash
$ npm install cypress
or
$ yarn add cypress
```

We will also install the recommeded dependency

```bash
$ npm install -D start-server-and-test
```

[start-server-and-test](https://github.com/bahmutov/start-server-and-test) is a cool tool that basically

> Starts server, waits for URL, then runs test command; when the tests end, shuts down server

as explained on their github repo.

### How to access the store in Cypress

We don't have access to `store()` object ordinarily, but cypress can access `window()` object.
We use this to attach the store to window in our `index.js`.

```js
import React from 'react'
import ReactDOM from 'react-dom'

import { Provider } from 'react-redux'
import store from './redux/store'

import TodoApp from './TodoApp'

import * as serviceWorker from './serviceWorker'

ReactDOM.render(
  <Provider store={store}>
    <TodoApp />
  </Provider>,
  document.getElementById('root')
)

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

Now we have access to `store()` and more importantly the **state** inside it.

### Writing the test

Now that we have the store available, we can access redux state at

```js
cy.window().its('store').invoke('getState')
```

The final version of the test will look like this

```js
/// <reference types="Cypress" />

describe('Tests functionality and redux state', () => {
  it('Successfully uses todo application', () => {
    cy.visit('/')

      // assertions on view, tabs and redux
      .get('[data-cy=Header]')
      .should('have.text', 'Todo List')
      .get('.add-todo')
      .should('have.text', 'Add Todo')
      .get('.todo-list')
      .should('have.text', 'No todos, yay!')
      .get('.visibility-filters')
      .should('include.text', 'all')
      .get('.visibility-filters')
      .should('include.text', 'completed')
      .get('.visibility-filters')
      .should('include.text', 'incomplete')

      .window()
      .its('store')
      .invoke('getState')
      .then((state) => {
        expect(state.visibilityFilter).to.be.a('string').and.equal('all')
        expect(state.todos.allIds).to.be.a('array').and.to.be.empty
        expect(state.todos.byIds).to.be.a('object').and.to.be.empty
      })

      // add a todo, add another todo , mark the first one as complete
      .get('input')
      .type('My First Todo')
      .get('.add-todo')
      .click()
      .get('input')
      .type('My Second Todo')
      .get('.add-todo')
      .click()
      .get('.todo-list')
      .eq(0)
      .click()

      // assertions on view, tabs and redux
      .get('.filter')
      .eq(0)
      .should('include.text', 'all')
      .click()
      .get('.todo-item')
      .should('include.text', '👋 My First Todo')

      .get('.filter')
      .eq(2)
      .should('include.text', 'incomplete')
      .click()
      .get('.todo-item')
      .should('include.text', '👋 My First Todo')

      .get('.filter')
      .eq(1)
      .should('include.text', 'completed')
      .click()
      .get('.todo-item')
      .should('have.text', '👌 My Second Todo')
      .eq(0)
      .children()
      .should('have.class', 'todo-item__text--completed')
      .get('.filter')
      .eq(0)
      .should('include.text', 'all')
      .click()

      .window()
      .its('store')
      .invoke('getState')
      .then((state) => {
        expect(state.visibilityFilter).to.be.a('string').and.equal('all')
        expect(state.todos.allIds).to.be.a('array').and.to.have.lengthOf(2)
        expect(state.todos.byIds)
          .to.be.a('object')
          .and.to.deep.equal({
            1: { content: 'My First Todo', completed: false },
            2: { content: 'My Second Todo', completed: true },
          })
      })
  })
})
```

### Want more ?

We can also dispatch redux actions like this.

```js
cy.window()
  .its('store')
  .invoke('dispatch', {
    type: 'ADD_TODO',
    payload: { content: 'Dispatched TODO', completed: true },
  })
```