I need help figuring out how to mock an axios post request. The docs have failed me. I've tried just about every combination I could find on stack overflow. All end up with either typescript errors or the undesired results shown below...
The rendered component
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>
);
}
The spyon function
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);
}
}
test trial #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);
});
});
test trial #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);
});
});
Any help would be appreciated.

I am not sure if this is the problem, but I am pretty sure you are supposed to use waitFor on your expects, not on your fireEvents. So it might just be that you are waiting to early and then not awaiting the actual result. I do either
or
also, I don't use axios, but for fetch I could use a node module
"jest-fetch-mock"and then just:There is a node module
jest-mock-axioswith 150k weekly downloads, I would try that one: https://www.npmjs.com/package/jest-mock-axios?activeTab=readme