【问题标题】:How to test a component is given the parent component's function in React (Native) with Jest and Enzyme?如何使用 Jest 和 Enzyme 在 React (Native) 中给定父组件的功能来测试组件?
【发布时间】:2018-10-05 12:46:42
【问题描述】:

我正在构建一个 React Native 应用程序,并且我正在使用 Jest 和 Enzyme 进行单元测试。此外,我正在使用 TypeScript。

我使用Formik 构建以下表单。

import strings from "./strings";
import styles from "./styles";
import { strings as loginStrings } from "../../screens/Login";
import { Formik, FormikActions, FormikProps } from "formik";
import React, { Component } from "react";
import { View } from "react-native";
import { Button, Input } from "react-native-elements";
import { NavigationScreenProp } from "react-navigation";
import { object as yupObject, string as yupString } from "yup";

export interface FormValues {
  email: string;
  password: string;
}

export interface Props {
  navigation: NavigationScreenProp<any, any>;
}

export default class LoginForm extends Component<Props, object> {
  handleSubmit = (values: FormValues, formikBag: FormikActions<FormValues>) => {
    // ... api calls and stuff
  };

  renderForm = ({
    values,
    handleSubmit,
    setFieldValue,
    touched,
    errors,
    setFieldTouched,
    isValid,
    isSubmitting
  }: FormikProps<FormValues>) => (
    <View style={styles.container}>
      // ... two inputs and a button
    </View>
  );

  render() {
    return (
      <Formik
        initialValues={{ email: "", password: "" }}
        onSubmit={(values: FormValues, formikBag: FormikActions<FormValues>) =>
          this.handleSubmit(values, formikBag)
        }
        validationSchema={yupObject().shape({
          email: yupString()
            .email(strings.invalidEmailFormat)
            .required(strings.emailRequired),
          password: yupString()
            .min(8, strings.passwordMinLength)
            .required(strings.passwordRequired)
        })}
        render={(formikBag: FormikProps<FormValues>) => this.renderForm(formikBag)}
      />
    );
  }
}

如您所见,它只是一个简单的形式。我现在想测试&lt;Formik /&gt; 组件get 是否通过renderForm()handleSubmit,所以我编写了以下测试:

it("should be passed the component's handleSubmit function for onSubmit", () => {
  expect(wrapper.find("Formik").prop("onSubmit")).toEqual(
    (values: FormValues, formikBag: FormikActions<FormValues>) =>
      wrapper.instance().handleSubmit(values, formikBag)
  );
});

renderForm() 也一样。不幸的是,这会引发错误:

● LoginForm › rendering › should be passed the component's handleSubmit function for onSubmit

    expect(received).toEqual(expected)

    Expected value to equal:
      [Function anonymous]
    Received:
      [Function onSubmit]

    Difference:

    - Expected
    + Received

    - [Function anonymous]
    + [Function onSubmit]

      28 |
      29 |     it("should be passed the component's handleSubmit function for onSubmit", () => {
    > 30 |       expect(wrapper.find("Formik").prop("onSubmit")).toEqual(
         |                                                       ^
      31 |         (values: FormValues, formikBag: FormikActions<FormValues>) =>
      32 |           wrapper.instance().handleSubmit(values, formikBag)
      33 |       );

所以我不确定如何正确测试该函数是否已传递给组件。如何做到这一点?

我发现了一种可行的方法,就是将函数传递给&lt;Formik /&gt;,如下所示:

onSubmit={this.handleSubmit}
render={this.renderForm}

然后就是:

expect(wrapper.find("Formik").prop("onSubmit)).toEqual(wrapper.instance().onSubmit)

问题是我在过去的单元测试中遇到了麻烦,当时我刚刚通过了这样的函数。这样我也失去了 TypeScript 的类型。有没有办法让我的初步尝试奏效”

【问题讨论】:

    标签: typescript react-native jestjs enzyme formik


    【解决方案1】:

    当您定义该匿名函数时,您实际上是在创建一个新函数,因此它永远不会等于渲染器内部使用的那个。您的选择是将其存储为对象的一部分并检查引用相等(这是您建议的工作):

    expect(wrapper.find("Formik").prop("onSubmit)).toEqual(wrapper.instance().onSubmit)
    

    另一种选择是模拟handleSubmit,并让您的测试检查当您单击Submit 按钮时是否调用handleSubmit,我认为这是一个更合理的测试。

    // set handleSubmit to our fake mock function
    wrapper.instance().handleSubmit = jest.fn();
    wrapper.update();
    // Here you need to simulate a click to submit form
    // I don't know how your input looks like
    // but it will be similar to
    inp.simulate('click')
    // expect our mock function to have been called at least once
    expect(wrapper.instance().handleSubmit).toHaveBeenCalledTimes(1);
    

    【讨论】:

    • 感谢您的帮助。不过,您将如何使用renderForm() 制作模拟版本?现在有我可以模拟的事件,是吗?
    • 虽然官方文档中没有测试,但是你可以看看 PR hereThese lines 告诉你如何模拟提交
    猜你喜欢
    • 2019-07-26
    • 1970-01-01
    • 2020-11-02
    • 2017-04-13
    • 2020-04-08
    • 1970-01-01
    • 2017-02-12
    • 1970-01-01
    • 2020-07-17
    相关资源
    最近更新 更多