首页 > 解决方案 > TypeError:无法使用 Jest 和 React 读取未定义道具的属性“电子邮件”。为什么?

问题描述

尝试使用 Jest 为 ReactJs 代码编写单元测试。当我试图传递道具时,它会显示以下错误

TypeError:无法读取未定义的属性“电子邮件”

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

登录.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);

登录.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")  
  });
});

需要对 SignIn 进行单元测试并收到此错误,如何使用道具映射状态?

用道具映射状态的正确方法是什么。

标签: reactjsjestjsbabel-jest

解决方案


我支持绕过 redux 部分actionsreducers独立进行测试。因此,我建议class为您的测试导出和导入它。

工作示例(单击Tests选项卡运行测试):

编辑受保护的路由 - Redux


容器/登录/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);

容器/登录/__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);
  });
});

推荐阅读