我们真实文件以及我的测试文件:
// screens/Details.js
import React from 'react';
import {Text, View} from 'react-native';
import Styles from '../constants/Styles';
import {useRoute} from '@react-navigation/native';
const DetailsScreen = () => {
const {params} = useRoute();
const {data} = params;
return (
<View style={Styles.container}>
<Text style={Styles.title}>Details Screen</Text>
<Text>Data passed: {data}</Text>
</View>
);
};
export default DetailsScreen;
// screens/Home.js
import React from 'react';
import {Text, TouchableOpacity, View} from 'react-native';
import {useNavigation} from '@react-navigation/native';
import Styles from '../constants/Styles';
const HomeScreen = () => {
const {navigate} = useNavigation();
return (
<View style={Styles.container}>
<Text style={Styles.title}>Home Screen</Text>
<TouchableOpacity
onPress={() => navigate('Details', {data: 'Potato 🥔'})}>
<Text>Go to Details Screen</Text>
</TouchableOpacity>
</View>
);
};
export default HomeScreen;
// screens/index.js
export {default as DetailsScreen} from './Details';
export {default as HomeScreen} from './Home';
// __tests__/App-test.js
import 'react-native';
import React from 'react';
import renderer, {act} from 'react-test-renderer';
import {HomeScreen} from '../screens';
import MockedNavigator from '../MockedNavigator';
it('renders correctly', async () => {
const {toJSON} = renderer.create(<MockedNavigator component={HomeScreen} />);
await act(async () => {
expect(toJSON()).toMatchSnapshot();
});
});
// MockedNavigator.js
import React from 'react';
import {NavigationContainer} from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';
const Stack = createStackNavigator();
const MockedNavigator = ({component, params = {}}) => {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="MockedScreen"
component={component}
initialParams={params}
/>
</Stack.Navigator>
</NavigationContainer>
);
};
export default MockedNavigator;
这里是成功的代码。但出现的错误,下面有描述。
我在实际的项目中发现如果有用到 react-navigation 的时候就会出现很多错误,首先看第一个错误:
我们知道在使用 react-navigation 的时候需要安装这个依赖。既然我们知道错误是那一个插件,那么查找错误就相对容易些;有两个方向,首先看这个插件或者看 react-navigation 上有没有说明。我在 react-navigation 文档中看到相关的说明 Testing with Jest 。我就按照官网说的进行添加,首先新建文件
jest.setup.js ,在里面添加如下内容:
import 'react-native-gesture-handler/jestSetup';
jest.mock('react-native-reanimated', () => {
const Reanimated = require('react-native-reanimated/mock');
// The mock for `call` immediately calls the callback which is incorrect
// So we override it with a no-op
Reanimated.default.call = () => {};
return Reanimated;
});
// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper');
然后在 package.json 中 jest 中添加属性 setupFiles 是一个数组,这里我们就只有一个,第一个元素的值为: "./jest.setup.js" ,这里取决于你这个文件所放的位置,我的跟 packgae.json 这个文件在同一个目录下。接着执行 yarn test ,满怀期待的眼神看着,希望能看到成功,结果却是下面的错误:
请不要怀疑人生,有第一个错误就会有无数个。
我们来分析错误,很明显这个是 react-navigation 导航的返回的图片,既然知道是 react-navigation 的错误,接下来就很简单了,首先去 react-navigation 的 github 中的 issures 中搜索,结果我看到了我想要的答案 "Syntax Error: Invalid or unexpected token" with .png #2663 ,热心的好友们提供了自己觉得可行的方案,我尝试我下面的方案,发现成功了,至于为什么目前我还不清楚。
打开 package.json 在 jest 下增加:
"moduleNameMapper": {
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/assetsTransformer.js",
"\\.(css|less)$": "<rootDir>/assetsTransformer.js"
}
assetsTransformer.js 这个文件跟上面的一样新建一个,一般都不存在这个文件,有的话就直接添加,内容如下:
const path = require('path');
module.exports = {
process(src, filename, config, options) {
return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
},
};
然后接着执行 yarn test 。
我在做的时候就在想,现在应该可以了,结果:
成功了,只不过有一个警告。
上面有提示怎么消除这个警告,按照操作来一波:
it('renders correctly', async () => {
const {toJSON} = renderer.create(<MockedNavigator component={HomeScreen} />);
await act(async () => {
expect(toJSON()).toMatchSnapshot();
});
});
这样就没有警告了,大功告成。
我要说明一下,如果没有我代码里面的 MockedNavigator.js 文件,那么就会出现下面的错误:
✕ renders correctly (28ms)
● renders correctly
Couldn't find a navigation object. Is your component inside a screen in a navigator?
5 |
6 | const HomeScreen = () => {
> 7 | const {navigate} = useNavigation();
| ^
8 | return (
9 | <View style={Styles.container}>
10 | <Text style={Styles.title}>Home Screen</Text>
at useNavigation (node_modules/@react-navigation/core/lib/commonjs/useNavigation.tsx:17:11)
at HomeScreen (screens/Home.js:7:22)
at renderWithHooks (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:5552:18)
at mountIndeterminateComponent (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:7918:13)
at beginWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9019:16)
at performUnitOfWork (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:12649:12)
at workLoopSync (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:12622:22)
at performSyncWorkOnRoot (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:12333:9)
at node_modules/react-test-renderer/cjs/react-test-renderer.development.js:1825:24
at unstable_runWithPriority (node_modules/scheduler/cjs/scheduler.development.js:653:12)
console.error
The above error occurred in the <HomeScreen> component:
in HomeScreen
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
at logCapturedError (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10141:21)
at logError (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10178:5)
at update.callback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:11288:5)
at callCallback (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:3259:12)
at commitUpdateQueue (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:3280:9)
at commitLifeCycles (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:10497:11)
at commitLayoutEffects (node_modules/react-test-renderer/cjs/react-test-renderer.development.js:13295:7)
所以这个文件是需要的,至于为啥需要,目前的我也不知道。