如何测试内部包含useAsyncStorage的React Native自定义Hook?
解决useAsyncStorage测试报错方案
错误原因
你使用的@react-native-async-storage/async-storage默认jest mock未包含useAsyncStorage钩子的实现,导致测试时提示该函数不存在。
解决方案
1. 完善AsyncStorage的Mock实现
如果项目中使用了自定义mock文件(__mocks__/@react-native-async-storage/async-storage.js),修改它以添加useAsyncStorage的实现:
// __mocks__/@react-native-async-storage/async-storage.js import AsyncStorageMock from '@react-native-async-storage/async-storage/jest/async-storage-mock'; // 实现useAsyncStorage钩子,返回对应key的操作方法 export const useAsyncStorage = (key) => ({ getItem: async () => AsyncStorageMock.getItem(key), setItem: async (value) => AsyncStorageMock.setItem(key, value), removeItem: async () => AsyncStorageMock.removeItem(key), mergeItem: async (value) => AsyncStorageMock.mergeItem(key, value), clear: async () => AsyncStorageMock.clear(), getAllKeys: async () => AsyncStorageMock.getAllKeys(), }); export default AsyncStorageMock;
2. 修正测试文件的Mock配置
测试文件中无需指定mock的具体路径,直接mock官方包名即可,同时调整导入和测试逻辑:
import { renderHook, waitFor } from '@testing-library/react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { useCustomHook } from '../path-to-your-hook'; // 替换为你的Hook实际路径 // 自动使用__mocks__下的mock文件 jest.mock('@react-native-async-storage/async-storage'); describe('Test hook', () => { beforeEach(async () => { // 清空存储,避免测试用例间数据污染 await AsyncStorage.clear(); await AsyncStorage.setItem('item', 'value'); }); it('Should return stored item', async () => { const { result } = renderHook(() => useCustomHook()); // 等待异步存储操作完成,断言结果 await waitFor(() => { expect(result.current).toBe('value'); }); }); it('Should return default value when no item exists', async () => { await AsyncStorage.removeItem('item'); const { result } = renderHook(() => useCustomHook()); await waitFor(() => { expect(result.current).toBe('some value'); }); }); });
3. 额外优化:修复自定义Hook的重复触发问题
原Hook中useEffect依赖了state,会导致state更新后重复触发effect,可调整依赖并优化逻辑:
export const useCustomHook = () => { const storage = useAsyncStorage('item'); const [state, setState] = useState<string | null>(null); useEffect(() => { // 标记组件挂载状态,避免卸载后更新state let isMounted = true; storage.getItem().then(value => { if (isMounted) { setState(value ?? 'some value'); } }); return () => { isMounted = false; }; }, [storage]); // 移除state依赖,仅在storage实例变化时触发 return state; };
内容的提问来源于stack exchange,提问作者MaksimL
相关产品推荐
相关产品推荐

