React Native 0.56 +酶+笑话+ React导航:由于import语句,酶崩溃 [英] React Native 0.56 + Enzyme + Jest + React Navigation: Enzyme crashes because of import statement

查看:124
本文介绍了React Native 0.56 +酶+笑话+ React导航:由于import语句,酶崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL; DR:,由于链接到React Navigation的以下错误,我的测试崩溃了:

TL;DR: My tests crash, because of the following error linked to React Navigation:

/path-to-app/react-native/myApp/node_modules/react-navigation/src/views/withNavigation.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import React from 'react';
                                                                                             ^^^^^^
SyntaxError: Unexpected token import

      127 | }
      128 |
    > 129 | export default withNavigation(
          |                                ^
      130 |   connect(
      131 |     null,
      132 |     { loginSuccess }

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:403:17)
      at Object.get withNavigation [as withNavigation] (node_modules/react-navigation/src/react-navigation.js:166:12)
      at Object.<anonymous> (app/components/LoginForm/LoginForm.js:129:32)

奇怪的是,我使用一个命名的导出,这就是为什么甚至不应该加载React Navigation的原因.

The weird thing is that I use a named export, which is why React Navigation shouldn't even be loaded.

我正在尝试为我的登录表单编写单元测试.这是表格的代码:

I'm trying to write unit tests for my login form. Here is the code for the form:

import React, { Component } from "react";
import { View } from "react-native";
import { connect } from "react-redux";
import { Formik } from "formik";
import { object as yupObject, string as yupString } from "yup";
import { withNavigation } from "react-navigation";
import PropTypes from "prop-types";

import { loginSuccess } from "../../actions/login/login";
import alert from "../../api/alert/alert";
import { apiLoginUser } from "../../api/auth/auth";
import {
  BUTTON_TEXT_LOGIN,
  BUTTON_TEXT_FORGOTTEN_PASSWORD
} from "../../config/constants/buttonTexts";
import {
  ERROR_MESSAGE_INVALID_EMAIL_FORMAT,
  ERROR_MESSAGE_EMAIL_REQUIRED,
  ERROR_MESSAGE_PASSWORD_REQUIRED,
  ERROR_MESSAGE_PASSWORD_MIN_LENGTH
} from "../../config/constants/errorMessages";
import AuthInput from "../AuthInput/AuthInput";
import Button from "../Button/Button";
import ClearButton from "../ClearButton/ClearButton";
import styles from "./styles";

export class LoginForm extends Component {
  static propTypes = {
    navigation: PropTypes.object,
    loginSuccess: PropTypes.func,
    isSubmitting: PropTypes.bool
  };

  handleSubmit = (values, formikBag) => {
    formikBag.setSubmitting(true);
    apiLoginUser(values.email, values.password)
      .then(data => {
        this.props.navigation.navigate("HomeScreen");
        formikBag.setSubmitting(false);
        this.props.loginSuccess(data.user);
      })
      .catch(error => {
        alert(error);
        formikBag.setSubmitting(false);
      });
  };

  renderForm = (
    values,
    handleSubmit,
    setFieldValue,
    errors,
    touched,
    setFieldTouched,
    isValid,
    isSubmitting
  ) => (
    <View style={styles.inputContainer}>
      <AuthInput
        placeholder="Email address"
        value={values.email}
        onChange={setFieldValue}
        onTouch={setFieldTouched}
        name="email"
        error={touched.email && errors.email}
        editable={!isSubmitting}
      />
      <AuthInput
        placeholder="Password"
        value={values.password}
        onChange={setFieldValue}
        onTouch={setFieldTouched}
        name="password"
        error={touched.password && errors.password}
        editable={!isSubmitting}
        secureTextEntry
      />
      <ClearButton
        text={BUTTON_TEXT_FORGOTTEN_PASSWORD}
        onPress={() => {}}
        containerStyles={styles.clearButtonContainer}
        buttonTextStyles={styles.clearButtonText}
      />
      <Button onPress={handleSubmit} disabled={!isValid || isSubmitting} loading={isSubmitting}>
        {BUTTON_TEXT_LOGIN}
      </Button>
    </View>
  );

  render() {
    return (
      <Formik
        initialValues={{ email: "", password: "" }}
        onSubmit={this.handleSubmit}
        validationSchema={yupObject().shape({
          email: yupString()
          .email(ERROR_MESSAGE_INVALID_EMAIL_FORMAT)
          .required(ERROR_MESSAGE_EMAIL_REQUIRED),
          password: yupString()
          .min(12, ERROR_MESSAGE_PASSWORD_MIN_LENGTH)
          .required(ERROR_MESSAGE_PASSWORD_REQUIRED)
        })}
        render={({
          values,
          handleSubmit,
          setFieldValue,
          errors,
          touched,
          setFieldTouched,
          isValid,
          isSubmitting
        }) =>
          this.renderForm(
            values,
            handleSubmit,
            setFieldValue,
            errors,
            touched,
            setFieldTouched,
            isValid,
            isSubmitting
          )
        }
      />
    );
  }
}

export default withNavigation(
  connect(
    null,
    { loginSuccess }
  )(LoginForm)
);

这是我的测试文件:

import React from "react";
import { View } from "react-native";
import { shallow } from "enzyme";

import { LoginForm } from "./LoginForm";

describe("LoginForm", () => {
  describe("rendering", () => {
    let wrapper;
    beforeEach(() => {
      wrapper = shallow(<LoginForm />);
    });

    it("should render a <View />", () => {
      expect(wrapper.find(View)).toHaveLength(1);
    });
  });
});

正如您所看到的,我正在使用命名导出将LoginFormConnectedLoginForm中拆分出来,该ConnectedLoginForm连接到Redux和React Navigation.而且,Enzyme或Jest的某些部分仍然不喜欢React Navigation.你知道如何解决这个问题吗?

As you can see I'm using a named export to split the LoginForm from the ConnectedLoginForm which is connected to Redux and React Navigation. And still some part of Enzyme or Jest does not like React Navigation. Do you have any idea how to circumvent this problem?

我设法使用NavigationService找到了解决方法.知道如何解决它仍然很棒,因为此错误也使我无法测试使用React Navigation的屏幕.

I managed to find a workaround using a NavigationService. It would still be awesome to know how to fix this, because this bug also prevents me from testing my screens that are using React Navigation.

对于任何想知道如何模拟这个的人,我最后要做的是在node_modules文件夹旁边创建一个__mocks__文件夹.在其中,我创建了一个名为react-navigation.js的文件,其中模拟了我需要模拟的所有行为.

For anyone wondering how to mock this, what I ended up doing was creating a __mocks__ folder adjacent to the node_modules folder. In it I created a file called react-navigation.js in which I mocked all the behavior I needed to mock.

对于withNavigation()而言,这意味着仅实现一个虚拟 HOC :

In the case of withNavigation() this meant just implementing a dummy HOC:

export const withNavigation = () => WrappedComponent => WrappedComponent;

推荐答案

您可以模拟依赖项,例如导航,如下所示:

You could mock dependencies, such as navigation, like this:

jest.mock("react-navigation", ({ withNavigation: (component) => component });

然后将包括导航在内的道具手动传递给您的组件:

And then pass props, including navigation, to your component manually:

const mockProps = {
    navigation: { navigate: jest.fn() },
    loginSuccess: jest.fn(),
    isSubmitting: true
}
wrapper = shallow(<LoginForm {...mockProps}/>);

这篇关于React Native 0.56 +酶+笑话+ React导航:由于import语句,酶崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆