测试React Redux-无法读取未定义或包装未定义的属性

时间:2018-11-30 21:40:52

标签: reactjs testing redux redux-mock-store

我在为测试套件的组件中设置Redux存储时遇到了问题。问题是,即使我尝试未连接的安装,测试也会在authState中查找变量时引发错误。我有以下组件:

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);

以及以下测试结构:

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('');
    });
});

我得到以下输出:

testing output

1 个答案:

答案 0 :(得分:1)

这是最终对我有用的设置。您也可以使用mount,但是您需要导入路由器并将组件包装在其中。

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);
        });
    });
});