如何模拟导航';使用React Native中的TypeScript进行单元测试的导航道具?

如何模拟导航';使用React Native中的TypeScript进行单元测试的导航道具?,typescript,unit-testing,react-native,jestjs,react-navigation,Typescript,Unit Testing,React Native,Jestjs,React Navigation,我正在用TypeScript构建一个React原生应用程序。对于导航,我使用React导航;对于单元测试,我使用Jest和Enzyme 以下是我的一个屏幕(LoadingScreen.tsx)的(精简)代码: 问题是,加载屏幕需要一个导航道具 我得到一个错误: [ts] Type '{ constructor: Function; toString(): string; toLocaleString(): string; valueOf(): Object; hasOwnProperty(v:

我正在用TypeScript构建一个React原生应用程序。对于导航,我使用React导航;对于单元测试,我使用Jest和Enzyme

以下是我的一个屏幕(LoadingScreen.tsx)的(精简)代码:

问题是,
加载屏幕
需要一个
导航
道具

我得到一个错误:

[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
我能够“解决”这个问题。我必须模拟导航对象的每个属性,如下所示:

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会抱怨组件需要一个不同类型的道具。

是的,这就是模拟
导航属性的方式,就像模拟任何其他属性一样。我在我的项目中就是这样做的

一个建议是:不要嘲笑每一处房产。只模拟组件中真正需要的组件,并调用它们。

Issue 模拟与预期类型不匹配,因此TypeScript报告错误

解决方案 您可以使用类型
any

细节 正如您提到的,在JavaScript中,它只模拟测试所需的内容

在TypeScript中,相同的模拟将导致错误,因为它与预期的类型不完全匹配

在这种情况下,如果您知道某个模拟与预期类型不匹配,则可以使用
any
来允许模拟通过编译时检查


以下是更新的测试:

从“/LoadingScreen”导入{LoadingScreen};
从“酶”中导入{shallow,shallowRapper};
从“React”导入React;
从“react native”导入{View};
const createTestProps=(props:Object)=>({
导航:{
导航:jest.fn()
},
…道具
});
描述(“加载屏幕”,()=>{
描述(“呈现”,()=>{
让包装:浅层振打器;
让props:any;//使用类型“any”退出类型检查
在每个之前(()=>{
props=createTestProps({});
wrapper=shallow();//无编译时错误
});
它(“应该呈现”,()=>{
expect(wrapper.find(View)).toHaveLength(1);//成功
期望(props.navigation.navigate).toHaveBeenCalledWith('LoginScreen');//成功
});
});
});

我对我的解决方案不太满意,但我已经开始模拟特定组件所需的导航属性,例如:

导出功能用户主屏幕({
航行
}: {
导航:{
goBack:()=>无效;
导航:导航功能;
setOptions:(选项:{title:string})=>void;
};
})
在测试中,我可以提供以下模拟:

const goBack=jest.fn();
const navigate=jest.fn();
const setOptions=jest.fn();
renderer.create()
NavigationFunction
的定义也很有说服力:

导出类型导航函数=(
目标:路线,,
参数?:参数列表[T]
)=>无效;

我无法为Navigator的函数addListener和RemovelListener提供正确的签名,因为我使用的是TypeScript,这不起作用。如果我不模拟每个属性,TypeScript会抱怨组件需要不同类型的porp。哦,对不起,我没有注意到您正在使用
TypeScript
。我没有使用它,但我真的认为这是正确的等待。您将始终使用这些方法传递道具。你不能模仿那些你不想使用的,而只是定义一些像这样的
navigate:()=>{}
True,但是我更喜欢这种模仿的方式,因为如果我需要它,我可以用这个模仿来做任何事。我希望有一种方法可以用TypeScript自动模拟开玩笑的对象,因为TypeScript知道对象的属性。也许精通打字脚本的人会想出更好的解决方案。无论如何,谢谢你的意见!对于确实如此的组件,您可以使用一个设置文件为所有测试模拟它们。对于我不相信的组件,使用或不使用TypeScript。我不知道你是否可以为导航创建一个类型并模拟该类型。。。如果这是可能的,那肯定是一个更好的解决方案。但是由于我没有使用TypeScript,所以我不能说这是正确的,也不能说它会工作。很好,顺便说一句。我用它来设置环境来查看这个问题谢谢!这很有趣,因为我记得你帮我解决了我遇到的另一个关键问题。我要为你传播你的知识!哈哈,听起来不错。知识并不是真正的“我的”,所以把它传播开来……知识在共享时效果最好,那么功能组件呢?
[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
export class LoadingScreen extends Component<Props, object>
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
});