Skip to content

Aditya Naik

How to access Redux state in Cypress

React, Redux, Cypress1 min read

Set up our application

I borrowed the code from react-redux.js.org which showcases react + redux in action using a todo list application.

Set up and scaffold Cypress

Cypress 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:

1$ npm install cypress
2or
3$ yarn add cypress

We will also install the recommeded dependency

1$ npm install -D start-server-and-test

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.

src/index.js
1import React from 'react'
2import ReactDOM from 'react-dom'
3
4import { Provider } from 'react-redux'
5import store from './redux/store'
6
7import TodoApp from './TodoApp'
8
9import * as serviceWorker from './serviceWorker'
10
11ReactDOM.render(
12 <Provider store={store}>
13 <TodoApp />
14 </Provider>,
15 document.getElementById('root')
16)
17
18if (window.Cypress) {
19 window.store = store
20}

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

1cy.window().its('store').invoke('getState')

The final version of the test will look like this, with redux code highlighted.

./cypress/integration/redux-test.js
1/// <reference types="Cypress" />
2
3describe('Tests functionality and redux state', () => {
4 it('Successfully uses todo application', () => {
5 cy.visit('/')
6
7 // assertions on view, tabs and redux
8 .get('[data-cy=Header]')
9 .should('have.text', 'Todo List')
10 .get('.add-todo')
11 .should('have.text', 'Add Todo')
12 .get('.todo-list')
13 .should('have.text', 'No todos, yay!')
14 .get('.visibility-filters')
15 .should('include.text', 'all')
16 .get('.visibility-filters')
17 .should('include.text', 'completed')
18 .get('.visibility-filters')
19 .should('include.text', 'incomplete')
20
21 .window()
22 .its('store')
23 .invoke('getState')
24 .then((state) => {
25 expect(state.visibilityFilter).to.be.a('string').and.equal('all')
26 expect(state.todos.allIds).to.be.a('array').and.to.be.empty
27 expect(state.todos.byIds).to.be.a('object').and.to.be.empty
28 })
29
30 // add a todo, add another todo , mark the first one as complete
31 .get('input')
32 .type('My First Todo')
33 .get('.add-todo')
34 .click()
35 .get('input')
36 .type('My Second Todo')
37 .get('.add-todo')
38 .click()
39 .get('.todo-list')
40 .eq(0)
41 .click()
42
43 // assertions on view, tabs and redux
44 .get('.filter')
45 .eq(0)
46 .should('include.text', 'all')
47 .click()
48 .get('.todo-item')
49 .should('include.text', '👋 My First Todo')
50
51 .get('.filter')
52 .eq(2)
53 .should('include.text', 'incomplete')
54 .click()
55 .get('.todo-item')
56 .should('include.text', '👋 My First Todo')
57
58 .get('.filter')
59 .eq(1)
60 .should('include.text', 'completed')
61 .click()
62 .get('.todo-item')
63 .should('have.text', '👌 My Second Todo')
64 .eq(0)
65 .children()
66 .should('have.class', 'todo-item__text--completed')
67 .get('.filter')
68 .eq(0)
69 .should('include.text', 'all')
70 .click()
71
72 .window()
73 .its('store')
74 .invoke('getState')
75 .then((state) => {
76 expect(state.visibilityFilter).to.be.a('string').and.equal('all')
77 expect(state.todos.allIds).to.be.a('array').and.to.have.lengthOf(2)
78 expect(state.todos.byIds)
79 .to.be.a('object')
80 .and.to.deep.equal({
81 1: { content: 'My First Todo', completed: false },
82 2: { content: 'My Second Todo', completed: true },
83 })
84 })
85 })
86})

Watch it Run!

cypress successful test running

Want more ?

We can also dispatch redux actions like this.

1cy.window()
2 .its('store')
3 .invoke('dispatch', {
4 type: 'ADD_TODO',
5 payload: { content: 'Dispatched TODO', completed: true },
6 })
© 2020 by Aditya Naik. All rights reserved.