React native 在嵌套的react导航组件上使用Jest进行快照测试-对象键更改,因此快照匹配失败
当我在StackNavigator.test.js上运行我的jest测试时,它总是失败,因为生成了密钥:React native 在嵌套的react导航组件上使用Jest进行快照测试-对象键更改,因此快照匹配失败,react-native,jestjs,react-navigation,React Native,Jestjs,React Navigation,当我在StackNavigator.test.js上运行我的jest测试时,它总是失败,因为生成了密钥: - Snapshot + Received @@ -79,11 +79,11 @@ fromRoute={null} index={0} navigation={ Object { "_childrenNavigation": Object
- Snapshot
+ Received
@@ -79,11 +79,11 @@
fromRoute={null}
index={0}
navigation={
Object {
"_childrenNavigation": Object {
- "**id-1542980055400-0**": Object {
+ "**id-1542980068677-0**": Object {
"actions": Object {
"dismiss": [Function],
"goBack": [Function],
"navigate": [Function],
"pop": [Function],
@@ -109,11 +109,11 @@
"replace": [Function],
"reset": [Function],
"router": undefined,
"setParams": [Function],
"state": Object {
- "key": "**id-1542980055400-0**",
+ "key": "**id-1542980068677-0**",
"routeName": "SignInOrRegister",
},
},
},
"actions": Object {
@@ -157,15 +157,15 @@
},
"setParams": [Function],
"state": Object {
"index": 0,
"isTransitioning": false,
- "key": "**id-1542980055400-1**",
+ "key": "**id-1542980068677-1**",
"routeName": "FluidTransitionNavigator",
"routes": Array [
Object {
- "key": "**id-1542980055400-0**",
+ "key": "**id-1542980068677-0**",
"routeName": "SignInOrRegister",
},
],
},
}
@@ -191,11 +191,11 @@
"overflow": "hidden",
},
undefined,
]
}
- toRoute="**id-1542980055400-0**"
+ toRoute="**id-1542980068677-0**"
>
<View
style={
Object {
"bottom": 0,
// keys are date and order-of-test based, so just removed them
const filterKeys = (state) => {
if (state.routes) {
return {
...state,
routes: state.routes.map((route) => {
const { key, ...others } = route
return filterKeys(others)
}),
}
}
return state
}
it('clears all other routes', () => {
const inputState = {}
const action = { type: AUTH_LOGOUT_SUCCESS }
const state = filterKeys(reducer(inputState, action))
expect(state.routes).toBe........
})
-快照
+收到
@@ -79,11 +79,11 @@
fromRoute={null}
索引={0}
航行={
反对{
“_childrenNavigation”:对象{
-“**id-1542980055400-0**”:对象{
+“**id-1542980068677-0**”:对象{
“动作”:对象{
“解除”:[功能],
“goBack”:[函数],
“导航”:[功能],
“pop”:[功能],
@@ -109,11 +109,11 @@
“替换”:[功能],
“重置”:[功能],
“路由器”:未定义,
“setParams”:[函数],
“状态”:对象{
-“密钥”:“**id-1542980055400-0**”,
+“密钥”:“**id-1542980068677-0**”,
“routeName”:“SigninoRegister”,
},
},
},
“动作”:对象{
@@ -157,15 +157,15 @@
},
“setParams”:[函数],
“状态”:对象{
“索引”:0,
“isTransitioning”:错误,
-“密钥”:“**id-1542980055400-1**”,
+“密钥”:“**id-1542980068677-1**”,
“routeName”:“FluidTransitionNavigator”,
“路由”:数组[
反对{
-“密钥”:“**id-1542980055400-0**”,
+“密钥”:“**id-1542980068677-0**”,
“routeName”:“SigninoRegister”,
},
],
},
}
@@ -191,11 +191,11 @@
“溢出”:“隐藏”,
},
未定义,
]
}
-toRoute=“**id-1542980055400-0**”
+toRoute=“**id-1542980068677-0**”
>
{
返回{
过渡规格:{
持续时间:1000,
放松:放松.out(放松.poly(4)),
计时:动画。计时,
useNativeDriver:错误,
},
屏幕插值器:场景操作=>{
常量{布局、位置、场景}=sceneProps
const thisceneindex=scene.index
const width=layout.initWidth
const translateX=位置.interpolate({
输入范围:[此场景索引-1,此场景索引],
outputRange:[宽度,0],
})
返回{transform:[{translateX}]}
},
}
}
const StackNavigator=createStackNavigator(
{
FluidTransitionNavigator:{
屏幕:FluidTransitionNavigator
},
仪表板:{
屏幕:仪表板
}
},
{
initialRouteName:'FluidTransitionNavigator',
headerMode:'浮动',
导航选项:(道具)=>({
标题:渲染阅读器(道具)
}),
transitionConfig:transitionConfig
}
);
const renderHeader=(道具)=>{
让index=props.navigation.state.index;
const logout=(props.navigation.state.routeName=='Dashboard');
让title='';
开关(props.navigation.state.routeName){
案例“仪表板”:
标题=‘仪表板’;
打破
案例“FluidTransitionNavigator”:
如果(索引!==未定义){
开关(props.navigation.state.routes[index].routeName){
案例“登录”:
标题='登录';
打破
案例“SigninoRegister”:
标题='SigninoRegister';
打破
违约:
标题='';
}
}
打破
违约:
标题='';
}
返回(['SignInOrRegister','Sign-In']。包括(标题))?空:(
);
};
renderHeader.propTypes={
导航:PropTypes.object
};
常量元素={
工具栏:{
容器:{
…平台。选择({
ios:{
身高:70
},
安卓:{
身高:76
}
})
},
},
};
导出默认StackNavigator;
以下是我的测试:
StackNavigator.test.js
import React, { Component } from 'react';
import { Platform, Animated, Easing } from 'react-native';
import { createStackNavigator } from 'react-navigation';
import { ThemeContext, getTheme } from 'react-native-material-ui';
import PropTypes from 'prop-types'
import FluidTransitionNavigator from './FluidTransitionNavigator';
import Dashboard from './../pages/Dashboard';
import Login from './../pages/Login';
import SignInOrRegister from './../pages/SignInOrRegister';
import UniToolbar from './UniToolbar';
const transitionConfig = () => {
return {
transitionSpec: {
duration: 1000,
easing: Easing.out(Easing.poly(4)),
timing: Animated.timing,
useNativeDriver: false,
},
screenInterpolator: sceneProps => {
const { layout, position, scene } = sceneProps
const thisSceneIndex = scene.index
const width = layout.initWidth
const translateX = position.interpolate({
inputRange: [thisSceneIndex - 1, thisSceneIndex],
outputRange: [width, 0],
})
return { transform: [ { translateX } ] }
},
}
}
const StackNavigator = createStackNavigator(
{
FluidTransitionNavigator: {
screen: FluidTransitionNavigator
},
Dashboard: {
screen: Dashboard
}
},
{
initialRouteName: 'FluidTransitionNavigator',
headerMode: 'float',
navigationOptions: (props) => ({
header: renderHeader(props)
}),
transitionConfig: transitionConfig
}
);
const renderHeader = (props) => {
let index = props.navigation.state.index;
const logout = (props.navigation.state.routeName === 'Dashboard');
let title = '';
switch (props.navigation.state.routeName) {
case 'Dashboard':
title = 'Dashboard';
break;
case 'FluidTransitionNavigator':
if (index !== undefined) {
switch (props.navigation.state.routes[index].routeName) {
case 'Login':
title = 'Sign In';
break;
case 'SignInOrRegister':
title = 'SignInOrRegister';
break;
default:
title = '';
}
}
break;
default:
title = '';
}
return (['SignInOrRegister', 'Sign In'].includes(title)) ? null : (
<ThemeContext.Provider value={getTheme(uiTheme)} >
<UniToolbar navigation={props.navigation} toolbarTitle={title} logout={logout} />
</ThemeContext.Provider>
);
};
renderHeader.propTypes = {
navigation: PropTypes.object
};
const uiTheme = {
toolbar: {
container: {
...Platform.select({
ios: {
height: 70
},
android: {
height: 76
}
})
},
},
};
export default StackNavigator;
import React from "react";
import renderer from "react-test-renderer";
import StackNavigator from "../StackNavigator";
test("renders correctly", () => {
const tree = renderer.create(<StackNavigator />).toJSON();
expect(tree).toMatchSnapshot();
});
从“React”导入React;
从“反应测试渲染器”导入渲染器;
从“./StackNavigator”导入StackNavigator;
测试(“正确渲染”,()=>{
const tree=renderer.create().toJSON();
expect(tree.toMatchSnapshot();
});
我在这里看到了一个几乎相同的问题:
被接受的答案仍然不能回答我的问题。但它确实把我引向了另一个兔子洞:
我尝试使用内联匹配:expect(tree)。toMatchInlineSnapshot()
在运行纱线运行测试:unit
后生成树,然后尝试插入任何
来代替所有键。不幸的是,这没有起作用
我被难住了。我不知道如何解决这个问题。我已经搜索了又搜索,尝试了多种方法来解决它,我就是解决不了这个问题
有人能帮我一把吗?我解决了我的问题,但不是通过嘲弄日期。现在,这在许多其他情况下都被建议
相反,我修改了一个名为Joey Baker的用户在上找到的答案
其理由如下:
这些键对于您的测试目的并不重要。您需要什么
真正关心的是路线和索引
他的代码如下所示,并假设在Redux中使用操作和减缩器:
- Snapshot
+ Received
@@ -79,11 +79,11 @@
fromRoute={null}
index={0}
navigation={
Object {
"_childrenNavigation": Object {
- "**id-1542980055400-0**": Object {
+ "**id-1542980068677-0**": Object {
"actions": Object {
"dismiss": [Function],
"goBack": [Function],
"navigate": [Function],
"pop": [Function],
@@ -109,11 +109,11 @@
"replace": [Function],
"reset": [Function],
"router": undefined,
"setParams": [Function],
"state": Object {
- "key": "**id-1542980055400-0**",
+ "key": "**id-1542980068677-0**",
"routeName": "SignInOrRegister",
},
},
},
"actions": Object {
@@ -157,15 +157,15 @@
},
"setParams": [Function],
"state": Object {
"index": 0,
"isTransitioning": false,
- "key": "**id-1542980055400-1**",
+ "key": "**id-1542980068677-1**",
"routeName": "FluidTransitionNavigator",
"routes": Array [
Object {
- "key": "**id-1542980055400-0**",
+ "key": "**id-1542980068677-0**",
"routeName": "SignInOrRegister",
},
],
},
}
@@ -191,11 +191,11 @@
"overflow": "hidden",
},
undefined,
]
}
- toRoute="**id-1542980055400-0**"
+ toRoute="**id-1542980068677-0**"
>
<View
style={
Object {
"bottom": 0,
// keys are date and order-of-test based, so just removed them
const filterKeys = (state) => {
if (state.routes) {
return {
...state,
routes: state.routes.map((route) => {
const { key, ...others } = route
return filterKeys(others)
}),
}
}
return state
}
it('clears all other routes', () => {
const inputState = {}
const action = { type: AUTH_LOGOUT_SUCCESS }
const state = filterKeys(reducer(inputState, action))
expect(state.routes).toBe........
})
我已将其用于我的案例(我还没有使用Redux),如下所示:
test("renders correctly", () => {
const tree = renderer.create(<StackNavigator />);
const instance = tree.getInstance();
const state = filterKeys(instance.state.nav);
expect(state).toMatchSnapshot();
});
// keys are date and order-of-test based, so just removed them
const filterKeys = (state) => {
if (state.routes) {
return {
...state,
routes: state.routes.map((route) => {
const { key, ...others } = route
return filterKeys(others);
}),
}
}
return state;
};
在ReactNavigation v5中,您可以这样模拟它:
// Jest Snapshot v1
exports[`renders correctly 1`] = `
Object {
"index": 0,
"isTransitioning": false,
"key": "StackRouterRoot",
"routes": Array [
Object {
"index": 0,
"isTransitioning": false,
"routeName": "FluidTransitionNavigator",
"routes": Array [
Object {
"routeName": "SignInOrRegister",
},
],
},
],
}
`;
jest.mock('nanoid/non-secure', () => ({
nanoid: () => 'routeUniqId',
}));