Как смоделировать навигационную опору React Navigation для модульных тестов с TypeScript в React Native? - PullRequest
0 голосов
/ 29 сентября 2018

Я создаю приложение React Native с помощью TypeScript.Для своей навигации я использую React Navigation, а для юнит-тестирования я использую Jest и Enzyme.

Вот (урезанный) код для одного из моих экранов (LoadingScreen.tsx):

import styles from "./styles";
import React, { Component } from "react";
import { Text, View } from "react-native";
import { NavigationScreenProps } from "react-navigation";

// Is this correct?
export class LoadingScreen extends Component<NavigationScreenProps> {
// Or should I've done:
// export interface Props {
//   navigation: NavigationScreenProp<any, any>;
// }

// export class LoadingScreen extends Component<Props> {
  componentDidMount = () => {
    this.props.navigation.navigate("LoginScreen");
  };

  render() {
    return (
      <View style={styles.container}>
        <Text>This is the LoadingScreen.</Text>
      </View>
    );
  }
}

export default LoadingScreen;

При попытке проверить экраны я столкнулся с проблемой.На экранах ожидается поддержка с типом NavigiationScreenProps, потому что я получаю доступ к React Navigations navigation prop.Вот код тестового файла (LoadingScreen.test.tsx):

import { LoadingScreen } from "./LoadingScreen";
import { shallow, ShallowWrapper } from "enzyme";
import React from "react";
import { View } from "react-native";
import * as navigation from "react-navigation";

const createTestProps = (props: Object) => ({
  ...props
});

describe("LoadingScreen", () => {
  describe("rendering", () => {
    let wrapper: ShallowWrapper;
    let props: Object;
    beforeEach(() => {
      props = createTestProps({});
      wrapper = shallow(<LoadingScreen {...props} />);
    });

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

Проблема в том, что LoadingScreen ожидает navigation проп.

Я получаю ошибку:

[ts]
Type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string | number | symbol): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string | ... 1 more ... | symbol): boolean; }' is not assignable to type 'Readonly<NavigationScreenProps<NavigationParams, any>>'.
  Property 'navigation' is missing in type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v: string | number | symbol): boolean; isPrototypeOf(v: Object): boolean; propertyIsEnumerable(v: string | ... 1 more ... | symbol): boolean; }'.
(alias) class LoadingScreen

Как я могу это исправить?

Я думаю, что я каким-то образом должен насмехаться над navigation опорой.Я попытался сделать это (как вы можете видеть, я импортировал * из React Navigation в моем тесте), но не смог понять.Существует только NavigationActions, который может быть полезен удаленно, но включает только navigate().TypeScript ожидает, что все, даже состояние, будет подделано.Как я могу издеваться над navigation опорой?

Редактировать 1: Является ли подход использования NavigationScreenProps даже правильным или я должен использовать подход interface Props?Если да, то как бы вы тогда посмеялись (это приводит к той же ошибке).

Редактировать 2: Использование второго подхода с интерфейсом и

export class LoadingScreen extends Component<Props, object>

Iудалось «решить» эту проблему.Мне буквально пришлось издеваться над каждым отдельным свойством объекта навигации, как это:

const createTestProps = (props: Object) => ({
  navigation: {
    state: { params: {} },
    dispatch: jest.fn(),
    goBack: jest.fn(),
    dismiss: jest.fn(),
    navigate: jest.fn(),
    openDrawer: jest.fn(),
    closeDrawer: jest.fn(),
    toggleDrawer: jest.fn(),
    getParam: jest.fn(),
    setParams: jest.fn(),
    addListener: jest.fn(),
    push: jest.fn(),
    replace: jest.fn(),
    pop: jest.fn(),
    popToTop: jest.fn(),
    isFocused: jest.fn()
  },
  ...props
});

Остается вопрос: это правильно?Или есть лучшее решение?

Редактировать 3: Когда я использовал JS, достаточно было смоделировать только то свойство, которое мне было нужно (часто просто перемещаться).Но с тех пор, как я начал использовать TypeScript, мне пришлось высмеивать все аспекты навигации.В противном случае TypeScript будет жаловаться, что компонент ожидает пропеллер с другим типом.

Ответы [ 2 ]

0 голосов
/ 03 октября 2018

Issue

Макет не соответствует ожидаемому типу, поэтому TypeScript сообщает об ошибке.

Решение

Вы можете использовать тип any "дляотказаться от проверки типов и позволить значениям проходить проверку во время компиляции ".

Подробности

Как вы упоминали, в JavaScript он работает только для того, чтобы макетировать то, что необходимо длятест.

В TypeScript та же самая имитация вызовет ошибку, поскольку она не полностью соответствует ожидаемому типу.

В ситуациях, подобных этим, у вас есть знакомая имитация, которая не соответствуетожидаемый тип, который вы можете использовать any, чтобы позволить макету проходить проверки во время компиляции.


Вот обновленный тест:

import { LoadingScreen } from "./LoadingScreen";
import { shallow, ShallowWrapper } from "enzyme";
import React from "react";
import { View } from "react-native";

const createTestProps = (props: Object) => ({
  navigation: {
    navigate: jest.fn()
  },
  ...props
});

describe("LoadingScreen", () => {
  describe("rendering", () => {
    let wrapper: ShallowWrapper;
    let props: any;   // use type "any" to opt-out of type-checking
    beforeEach(() => {
      props = createTestProps({});
      wrapper = shallow(<LoadingScreen {...props} />);   // no compile-time error
    });

    it("should render a <View />", () => {
      expect(wrapper.find(View)).toHaveLength(1);   // SUCCESS
      expect(props.navigation.navigate).toHaveBeenCalledWith('LoginScreen');   // SUCCESS
    });
  });
});
0 голосов
/ 02 октября 2018

Да, именно так вы бы высмеяли свойство navigation, как и любое другое свойство.Я делаю так в своих проектах.

Одно предложение: не издевайтесь над каждым отдельным свойством.Дразните только те, которые вам действительно нужны в вашем компоненте, и это будет называться.

...