2
votes

Expected:

Test runs and state is updated in the Login component, when then enables the Notification component (error message) to be found

Results:

Test fails, expected 1, received 0

enter image description here

Originally before I added redux and the store, thus needing to use the store and provider logic in my test, this Jest/Enzyme tests were passing.

The Login.test (updated current version)

import React from 'react'
import { Provider } from "react-redux"
import ReactTestUtils from 'react-dom/test-utils'
import { createCommonStore } from "../../store";
import { mount, shallow } from 'enzyme'
import toJson from 'enzyme-to-json'
import { missingLogin } from '../../consts/errors'
// import Login from './Login'
import { LoginContainer } from './Login';
import Notification from '../common/Notification'

const store = createCommonStore();

const user = {
    id: 1,
    role: 'Admin',
    username: 'leongaban'
};
const loginComponent = mount(
    <Provider store={store}>
        <LoginContainer/>
    </Provider>
);
const fakeEvent = { preventDefault: () => '' };

describe('<Login /> component', () => {
    it('should render', () => {
        const tree = toJson(loginComponent);
        expect(tree).toMatchSnapshot();
    });

    it('should render the Notification component if state.error is true', () => {
        loginComponent.setState({ error: true });
        expect(loginComponent.find(Notification).length).toBe(1);
    });
});

Login.test (previous passing version, but without the Redux store logic)

import React from 'react'
import ReactTestUtils from 'react-dom/test-utils'
import { mount, shallow } from 'enzyme'
import toJson from 'enzyme-to-json'
import { missingLogin } from '../../consts/errors'
import Login from './Login'
import Notification from '../common/Notification'

const loginComponent = shallow(<Login />);
const fakeEvent = { preventDefault: () => '' };

describe('<Login /> component', () => {
    it('should render', () => {
        const tree = toJson(loginComponent);
        expect(tree).toMatchSnapshot();
    });

    it('should render the Notification component if state.error is true', () => {
        loginComponent.setState({ error: true });
        expect(loginComponent.find(Notification).length).toBe(1);
    });
});
1

1 Answers

3
votes

Your problem is that by mixing the redux store logic into the tests, the loginComponent variable no longer represents an instance of Login, but an instance of Provider wrapping and instance of Login.

Thus when you do this

loginComponent.setState({ error: true })

You're actually calling setState on the Provider instance.

I would recommend testing the LoginComponent you've wrapped with connect to produce LoginContainer separately from the store state. The Redux GitHub repo has a great article on testing connected components, which gives a general outline on how to do this.

To summarize what you need to do

  1. Export both LoginComponent and LoginContainer separately
  2. Test LoginComponent individually from the container, essentially doing what your previous working tests before mixing in redux store state did.
  3. Write separate tests for LoginContainer where you test the mapStateToProps, mapDispatchToProps and mergeProps functionality.

Hope this helps!