Testing React Redux - cannot read properties of undefined, or wrapper undefined

佐手、 提交于 2019-12-14 01:30:03

问题


Im having a bit of a problem setting up a Redux store in my component for my test suite. The problem is that even if I try a unconnected mount then the test throws errors looking for variables in authState. I have the following component:

import React, { Component } from 'react';
import { Link, Redirect } from "react-router-dom";
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import * as authActions from '../../../actions/auth.actions';

export class PasswordReset extends Component {
    constructor(props) {
        super(props);
        this.state = {
            email: '',
            emailConfirm: '',
            message: ""
        };
    }

    handleChange = e => {
        e.preventDefault();
        const { value, name } = e.target;

        if (name === 'email') {
            this.setState({...this.state, email: value.trim()});
        } else if (name === 'secondary') {
            this.setState({...this.state, emailConfirm: value.trim()});
        }
    }

    handleSubmit = e => {
        e.preventDefault();
        if (this.state.email.length === 0 && this.state.emailConfirm.length === 0) {
            this.setState({message: "Please Enter and Confirm Email Before Submit"});
            return;
        }

        if (this.state.email !== this.state.emailConfirm) {
            this.setState({message: 'Emails Do Not Match, Please Try Again'});
            return;
        }

        this.props.authActions.resetPassword(this.state.email);
    }

    render() {
        if (this.props.authState.resetStatus === 'reset') {
            return <Redirect to='/login' />
        }
        const error = this.props.authState.resetError === 'TypeError: Failed to fetch' ? 'Agent Id does not exist' : false
        return (
            <div className={'container-login100'}>
                <div className={'wrap-login100 p-t-85 p-b-20'}>
                    <form className={'login100-form validate-form'}>
                        <span className={'login100-form-title p-b-70'}>Reset Password</span>
                        <div className={'wrap-input100 validate-input m-t-85 m-b-35'}>
                        <div style={{margin: '0 auto', alignItems: 'center', justifyContent: 'center', display: 'flex', color: 'red'}}>
                        {error || this.state.message}
                        </div>
                            <input
                                onChange={e => this.handleChange(e)}
                                className={'input100'}
                                name='email'
                                value={this.state.email}
                                placeholder="Please Enter Your Email"
                                required
                            />
                        </div>
                        <div className={'wrap-input100 validate-input m-t-85 m-b-35'}>
                            <input
                                onChange={e => this.handleChange(e)}
                                className={'input100'}
                                name="secondary"
                                value={this.state.secondary}
                                placeholder="Please Confirm By Re-entering Your Email"
                                required
                            />
                        </div>
                        <div className={'container-login100-form-btn'}>
                            <button className={'login100-form-btn btn-disabled'} onClick={e => this.handleSubmit(e)}>Reset Password</button>
                        </div>
                        <div className={'container-login100-form-btn'}>
                            <Link to='/login'>Back to Login</Link>
                        </div>
                    </form>
                </div>
            </div>
        )
    }
}

const mapStateToProps = state => ({
    authState: state.auth,
})

const mapDispatchToProps = dispatch => ({
    authActions: bindActionCreators({resetPassword: authActions.resetPassword}, dispatch),
})

export default connect(mapStateToProps, mapDispatchToProps)(PasswordReset);

And the following test structure:

import React from 'react';
import configureStore from 'redux-mock-store';
import Enzyme, {mount, shallow} from 'enzyme';
import Provider from 'react-redux';
import Adapter from 'enzyme-adapter-react-16';

import ConnectedPasswordReset, {PasswordReset} from '../';

Enzyme.configure({adapter: new Adapter()});

const mockStore = configureStore();
let wrapper, store, mWrapper;
const initialState = {isLoggedIn: false, isInProgress: false, email: null, error: null, resetError: null, resetStatus: null};

describe('PasswordReset component', () => {
    beforeEach(() => {
        store = mockStore(initialState);
        wrapper = shallow(<PasswordReset store={store} />);
        mWrapper = mount(<Provider store={store}><ConnectedPasswordReset /></Provider>);
    })

    it('shallow - should have initial state.email of ""', () => {
        expect(wrapper.state().email).toEqual('');
    });

    it('mount - should have a initial state.email of ""', () => {
        expect(mWrapper.state().email).toEqual('');
    });
});

Im getting the following output:


回答1:


Here is the setup that finally worked for me. You can also use mount, but you will need to import your Router and wrap the component in it.

import React from 'react';
import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { PasswordReset } from '../';

Enzyme.configure({adapter: new Adapter()});

const setup = () => {
    let props = {
        authState: {
           isLoggedIn: false, 
           isInProgress: false, 
           email: null, 
           error: null, 
           resetError: null, 
           resetStatus: null
        },
        authActions: {
            login: jest.fn(),
            resetPassword: jest.fn()
        }
    }

    let resetWrapper = shallow(<PasswordReset {...props}/>);

    return {props, resetWrapper};
};

describe('PasswordReset component', () => {
    const {resetWrapper} = setup();

    describe('initial render', () => {
        it('should have initial state.email of ""', () => {
            expect(resetWrapper.state('email')).toEqual('');
        });

        it('should have a initial internal state.emailConfirm of ""', () => {
            expect(resetWrapper.state('emailConfirm')).toEqual('');
        });

        it('should have one form component', () => {
            expect(resetWrapper.find('form').length).toBe(1);
        })

        it('should have two input fields', () => {
            expect(resetWrapper.find('input').length).toBe(2);
        });
    });
});


来源:https://stackoverflow.com/questions/53565280/testing-react-redux-cannot-read-properties-of-undefined-or-wrapper-undefined

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!