@testing-library/react-native中axios post模拟调用次数验证失败求助
模拟Axios POST请求的测试问题
我需要解决React Native项目中模拟Axios POST请求的测试问题,现有文档未能提供有效帮助。尝试了Stack Overflow上能找到的各种方案,但最终要么出现TypeScript错误,要么得到如下不符合预期的结果:

渲染组件代码
import React, { useState } from 'react'; import { Image, StyleSheet, Text, TextInput, View } from 'react-native'; import { Formik } from 'formik'; import * as Yup from 'yup'; import { MaterialCommunityIcons as Icon } from '@expo/vector-icons'; import { BtnMain, MainView } from '@app/components'; import { useAuthStore } from '@app/stores'; import { apiGetCurrentUser, apiLogin } from '@app/apis'; const validationSchema = Yup.object({ username: Yup.string().required('Username required'), password: Yup.string().required('Password required') }); export default function ScreenLogin(): JSX.Element { const [isLoggingIn, setIsLoggingIn] = useState(false); const [hidePassword, setHidePassword] = useState(true); const { setIsViewerAuthenticated, setViewerInfo } = useAuthStore(store => store); const loginHander = async (values: { username: string; password: string }): Promise<void> => { try { setIsLoggingIn(true); const responseToken = await apiLogin(values.username, values.password); if (!responseToken) { throw new Error('Access Denied'); } await setIsViewerAuthenticated(responseToken); const responseViewerInfo = await apiGetCurrentUser(); await setViewerInfo(responseViewerInfo); } catch (error: any) { throw error; } finally { setIsLoggingIn(false); } }; return ( <MainView> <Formik initialValues={{ username: '', password: '', submitError: null }} validationSchema={validationSchema} onSubmit={(values, { setErrors }) => loginHander(values).catch(error => setErrors({ submitError: error.message })) } > {({ handleChange, handleBlur, handleSubmit, values, errors // isValid, dirty }) => ( <View style={styles.container}> <Image source={require('@/assets/images/vlogo.png')} style={styles.image} /> <View style={styles.form}> <View> <TextInput style={styles.inputMain} placeholder="Username" onBlur={handleBlur('username')} onChangeText={handleChange('username')} value={values.username} /> {errors.username && <Text style={styles.error}>{errors.username}</Text>} </View> <View> <View style={styles.inputContainer}> <TextInput style={styles.inputPswd} placeholder="Password" secureTextEntry={hidePassword} onBlur={handleBlur('password')} onChangeText={handleChange('password')} value={values.password} /> <Icon style={styles.eyeIcon} onPress={() => setHidePassword(!hidePassword)} name={hidePassword ? 'eye-off' : 'eye'} size={20} /> </View> {errors.password && <Text style={styles.error}>{errors.password}</Text>} </View> <View> <BtnMain btnName="Login" // isDisabled={isLoggingIn || !dirty || !isValid} isLoading={isLoggingIn} btnStyles={styles.btn} btnTextStyles={styles.txtLogin} onPress={handleSubmit} /> {errors.submitError && <Text style={styles.submitError}>{errors.submitError}</Text>} </View> </View> </View> )} </Formik> </MainView> ); }
apiLogin函数代码
export async function apiLogin(username: string, password: string): Promise<string> { try { const result = await axiosLoginRequest([mapApiEndpoints.login, { username: username, password: password }]); return result.data.Response; } catch (error: any) { throw new Error(error); } }
测试尝试1(Axios Mock)
import React from 'react'; import { render, fireEvent, waitFor, cleanup, screen } from '@testing-library/react-native'; import ScreenLogin from './ScreenLogin'; jest.mock('expo-asset'); jest.mock('expo-font'); const mockAxios = { post: jest.fn(() => Promise.resolve({ data: {} })) }; describe('Login screen...', () => { afterAll(() => { cleanup(); }); it('renders inputs and button', async () => { render(<ScreenLogin />); const userInput = screen.getByPlaceholderText('Username'); const passwordInput = screen.getByPlaceholderText('Password'); const loginButton = screen.getByText('Login'); expect(userInput).toBeTruthy(); expect(passwordInput).toBeTruthy(); expect(loginButton).toBeDefined(); }); it('enter username/password and click login', async () => { render(<ScreenLogin />); const userInput = screen.getByPlaceholderText('Username'); const passwordInput = screen.getByPlaceholderText('Password'); const loginButton = screen.getByText('Login'); await waitFor(() => fireEvent.changeText(userInput as never, 'test1')); expect(userInput.props.value).toEqual('test1'); await waitFor(() => fireEvent.changeText(passwordInput as never, 'pass1')); expect(passwordInput.props.value).toEqual('pass1'); expect(loginButton).toBeDefined(); mockAxios.post.mockImplementationOnce(() => Promise.resolve({ data: { results: 'token' } }) ); await waitFor(() => fireEvent(loginButton, 'click')); expect(mockAxios.post).toHaveBeenCalledTimes(1); }); });
测试尝试2(SpyOn)
import React from 'react'; import { render, fireEvent, waitFor, cleanup, screen } from '@testing-library/react-native'; import ScreenLogin from './ScreenLogin'; import { apiLogin } from '@app/apis/index'; const api = { apiLogin }; jest.mock('expo-asset'); jest.mock('expo-font'); jest.spyOn(api, 'apiLogin').mockResolvedValue('token'); describe('Login screen...', () => { afterAll(() => { cleanup(); jest.resetAllMocks(); }); it('renders inputs and button', async () => { render(<ScreenLogin />); const userInput = screen.getByPlaceholderText('Username'); const passwordInput = screen.getByPlaceholderText('Password'); const loginButton = screen.getByText('Login'); expect(userInput).toBeTruthy(); expect(passwordInput).toBeTruthy(); expect(loginButton).toBeDefined(); }); it('enter username/password and click login', async () => { // setup render(<ScreenLogin />); const userInput = screen.getByPlaceholderText('Username'); const passwordInput = screen.getByPlaceholderText('Password'); const loginButton = screen.getByText('Login'); // enter credentials await waitFor(() => fireEvent.changeText(userInput as never, 'test1')); expect(userInput.props.value).toEqual('test1'); await waitFor(() => fireEvent.changeText(passwordInput as never, 'pass1')); expect(passwordInput.props.value).toEqual('pass1'); // login await waitFor(() => fireEvent.press(loginButton)); // results expect(api.apiLogin).toHaveBeenCalledTimes(1); }); });
恳请各位提供帮助。
内容的提问来源于stack exchange,提问作者Fiddle Freak
相关产品推荐
相关产品推荐

