Cristian Muscalu
Cristian Muscalu

Reputation: 9905

Jest play with Redux actions

I'm trying to implement snapshots with jest and i ran into a problem. The solution is probably simple, but i can't find it.

LoginForm.js

class LoginForm extends React.Component {
    constructor(props) {
        super(props)
        }
    }
    componentWillMount(){
        this.props.startSpinner()
    }
    render(){
        return(....)
    }
}

LoginForm.spec.js

it('should render snapshot', () => {
    const component = renderer.create(
            <LoginForm />
    )
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
})

startSpinner action

export function startSpinner() {
    return (dispatch) => {
        dispatch({
            type: 'WINDOW_START_SPINNER',
        })
    }
}

When i run tests, it throws this error, not only with this action, but with all functions called as a redux action.

TypeError: this.props.startSpinner is not a function

How can i make jest play nice with this redux actions?

Upvotes: 3

Views: 493

Answers (3)

EnriqueDev
EnriqueDev

Reputation: 1247

I believe that you are not applying the test properly. You must test actions, reducers, and components separately,

The test is failing because the LoginForm component is trying to use the connect function without been wrapped by a provider and so it's trying to access to an unexistign store.

To implement snapsots in your tests you should first mock a store, there is a nice mock already out there, you can find it here: https://github.com/arnaudbenard/redux-mock-store

Then, you must configure your store, in my projects I do something like this, change it at your will:

// Import your actions and their names (I separate the names in a 
// different file to avoid typos.
import * as actions from '../../src/actions';
import * as types from '../../src/actions';

// You must import an Initial state or create one, I usually import
// the one I have in the reducer.
import { INITIAL_STATE } from '../../src/reducers/AuthReducer'
// Import your middleware and redux mock store
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import MockAdapter from 'axios-mock-adapter';

// --- Mocking config --> Crete your store
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);
let store = mockStore(INITIAL_STATE);

// Clear actions before each time
beforeEach(() => {
  store.clearActions();
});

And now just test your action:

describe('[ ScannerActions ]', () => {
  describe('*** toggleCamera()', () => {
    it('Should dispatch TOGGLE_CAMERA action', () => {
      store.dispatch(actions.toggleCamera());
      expect(store.getActions()).toMatchSnapshot();
    })
  });
});

Upvotes: 1

momsse
momsse

Reputation: 303

You forgot to pass startSpinner as a props in your unit test. If you only need to test the render function you should pass something like a noop function (lodash provide one).

it('should render snapshot', () => {
    const component = renderer.create(
            <LoginForm startSpinner={_.noop} />
    )
    const tree = component.toJSON()
    expect(tree).toMatchSnapshot()
})

For redux actions i would test them separately (jest snapshots are great for them too).

Upvotes: 2

Morleee
Morleee

Reputation: 347

I would test the redux functionality seperately, and pass in startSpinner as a mock function instead.

e.g:

const mockFn = jest.fn()
const component = renderer.create(
   <LoginForm startSpinner={mockFn} />
)
expect(mockFn.toHaveBeenCalled()).toBe(true)

Upvotes: 2

Related Questions