TypeError: Cannot read property 'email' of undefined props using Jest and React. Why?

蹲街弑〆低调 提交于 2020-01-24 20:32:08

问题


Trying to write unit tests for the ReactJs code using Jest. When I am trying to pass the props it shows me below error

TypeError: Cannot read property 'email' of undefined

  62 | 
  63 | const mapStateToProps = state => {
> 64 |   const { email, password, errors, loading } = state.auth;
     |           ^
  65 | 
  66 |   return { email, password, errors, loading };
  67 | };

SignIn.js

import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import * as actions from "Actions";
import classnames from "classnames";

class SignIn extends Component {
  onSubmit(e) {
    e.preventDefault();

    const { email, password } = this.props;
    this.props.loginUser({ email, password });
  }

  render() {
    const { email, password, errors, fieldChanged } = this.props;
    return (
      <div className="contentWrapper">
        ....
      </div>
    );
  }
}

SignIn.propTypes = {
  loginUser: PropTypes.func.isRequired,
  fieldChanged: PropTypes.func.isRequired,
  email: PropTypes.string.isRequired,
  password: PropTypes.string.isRequired
};

const mapStateToProps = state => {
  const { email, password, errors, loading } = state.auth;

  return { email, password, errors, loading };
};

export default connect(
  mapStateToProps,
  actions
)(SignIn);

SignIn.test.js

import React, { Suspense } from 'react';
import Enzyme, {shallow} from 'enzyme';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-15';
Enzyme.configure({ adapter: new Adapter() });
import { Provider } from 'react-redux';
import configureMockStore from "redux-mock-store";
import thunk from 'redux-thunk';
import SignIn from '../containers/authentication/SignIn';
import mapStateToProps from "../containers/authentication/SignIn";

const mockStore = configureMockStore();

describe('SignIn', () => {

  it('render sign in', () => {
      const state = {
          email: "aaky8668@gmail.com",
          password: "pass123"
      };

      const store = mockStore(state);
      const dwrapper = Enzyme.mount(<SignIn store={store} />);
      console.log(dwrapper);
      expect(dwrapper.props().email).toBe("aakshay8668@gmail.com")  
  });
});

Need to unit test SignIn and getting this error, how to map state with props?

What will be the correct way to map state with props.


回答1:


The line of

const { email, password, errors, loading } = state.auth;

is attempting to destructure state.auth, it attempts to store its email, password, errors, loading members into variables with the same names. The error indicates that state.auth is undefined. You will need to make sure that state exists, it has an auth member which has attributes of the names that your code above expects.




回答2:


I'm a proponent of bypassing the redux portion and testing against actions and reducers independently. Therefore, I'd recommend exporting the class and importing that for your test.

Working example (click the Tests tab to run tests):


containers/Login/index.js

import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { login } from "../../actions/Auth";
import Form from "../../components/Form";
import SubTitle from "../../components/SubTitle";
import Title from "../../components/Title";

export class Login extends Component {
  state = {
    email: "",
    password: ""
  };

  handleChange = ({ target: { name, value } }) =>
    this.setState({ [name]: value });

  handleSubmit = e => {
    e.preventDefault();

    const { email, password } = this.state;
    if (!email || !password) return;

    this.props.login(email);
  };

  render = () => (
    <Fragment>
      <Title>Login</Title>
      <SubTitle>You must login before viewing the dashboard!</SubTitle>
      <Form onSubmit={this.handleSubmit}>
        <input
          name="email"
          type="email"
          className="uk-input"
          placeholder="email"
          value={this.state.email}
          onChange={this.handleChange}
        />
        <input
          className="uk-input"
          name="password"
          type="password"
          placeholder="password"
          value={this.state.password}
          onChange={this.handleChange}
        />
        <br />
        <button className="uk-button uk-button-primary" type="submit">
          Login
        </button>
      </Form>
    </Fragment>
  );
}

Login.propTypes = {
  login: PropTypes.func.isRequired
};

export default connect(
  null,
  { login }
)(Login);

containers/Login/__tests__/Login.test.js

import React from "react";
import { mount } from "enzyme";
import { Login } from "../index";

const login = jest.fn();

const initProps = {
  login
};

describe("Login", () => {
  let wrapper;
  beforeEach(() => {
    wrapper = mount(<Login {...initProps} />);
  });

  afterEach(() => {
    login.mockClear();
  });

  it("renders without errors", () => {
    expect(wrapper.find("form").exists()).toBeTruthy();
  });

  it("calls handleChange class field to update an input with a value", () => {
    const value = "test@test.com";
    wrapper
      .find("input")
      .first()
      .simulate("change", { target: { value, name: "email" } });

    expect(wrapper.state("email")).toEqual(value);
    expect(
      wrapper
        .find("input")
        .first()
        .props().value
    ).toEqual(value);
  });

  it("doesn't call 'login' prop if email or password fields are empty", () => {
    wrapper.find("form").simulate("submit");

    expect(login).toHaveBeenCalledTimes(0);
  });

  it("calls 'login' prop to log in a user", () => {
    const email = "test@test.com";
    wrapper.setState({ email, password: "password" });
    wrapper.find("form").simulate("submit");

    expect(login).toHaveBeenCalledWith(email);
  });
});



回答3:


SignIn.test.js

The key too solution is that we have to add dive() to the shallow component so that it could get the component wrapper completely, this solution worked for me

import React, { Suspense } from 'react';
import Enzyme, { shallow, configur } from 'enzyme';
import EnzymeAdapter from 'enzyme-adapter-react-15';
import SignIn from '../containers/authentication/SignIn';
import configureStore from '../configureStore';

Enzyme.configure({
    adapter: new EnzymeAdapter(),
    disableLifecycleMethods: true
});

describe('SignIn', () => {
  it('render sign in', () => {
     const state = {
          auth: {
            email: "test@test.com",
            password: "password",
            errors: {
              login: "red"
            },
            loading: true
          }          
      };

      const store = configureStore(state);
      const dwrapper = shallow(<SignIn store={store}/>).dive();
      expect(dwrapper.find(".contentWrapper").exists()).toBeTruthy();  
  });
});


来源:https://stackoverflow.com/questions/59446441/typeerror-cannot-read-property-email-of-undefined-props-using-jest-and-react

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