I'm trying to intercept a post request with MSW to mock the result. I have a handleLogin function within a context, however, MSW cannot recognize handleLogin as a function. I get the error ReferenceError: handleLogin is not a function. If I make the api call out of context, it works.
This is my context:
export function AuthProvider({ children }: { children: ReactNode }) {
...
const handleLogin = async function(event: FormEvent<HTMLFormElement>): Promise<AxiosResponse> {
/**
* Authenticate the user.
* if username and password are corrects, the token refresh is stored on localStorage and
* the isAuthenticate will be truthy.
*/
const url = 'http://127.0.0.1:8000/api/token/';
const response = await axios.post(url, {
username: event.currentTarget.username.value,
password: event.currentTarget.password.value,
});
return new Promise(function(resolve, reject) {
if (response.status !== 200) return reject('unauthorized');
const tokenRefresh = JSON.stringify(response.data.refresh);
const tokenAccess = JSON.stringify(response.data.access);
localStorage.setItem('userTokens', tokenRefresh);
setUserTokens(tokenRefresh);
setIsAuthenticated(tokenAccess);
return resolve(response);
})
}
return (
<AuthContext.Provider value={{
userTokens: userTokens,
isAuthenticated: isAuthenticated,
handleLogin: handleLogin,
handleLogout: handleLogout,
}}>
{children}
</AuthContext.Provider>
)
}
this is my login form:
export default function LoginPage() {
...
const { handleLogin, isAuthenticated } = useContext(AuthContext);
...
function handleSubmit(e: FormEvent<HTMLFormElement>): void {
e.preventDefault();
if (!validateFields()) return;
setLoading(true);
handleLogin(e)
.then(() => {
navigate('/admin/dashboard', { replace: true });
setLoading(true);
})
.catch(() => {
setLoading(false);
setUsernameError('username or password is invalid');
});
}
...
}
this is my test
import { render, screen, fireEvent } from '@testing-library/react';
import LoginPage from '..';
import { BrowserRouter } from 'react-router-dom';
import { userEvent } from '@testing-library/user-event';
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
const handlers = [
http.post('http://127.0.0.1:8000/api/token/', () => {
return new HttpResponse(null, { status: 401 })
}),
]
const server = setupServer(...handlers);
function renderLoginPage() {
return (
render(
<BrowserRouter>
<LoginPage />
</BrowserRouter>
)
)
}
describe('<loginPage />', () => {
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
it('should render error message if user not found', async () => {
renderLoginPage();
// mock input data
const usernameInput = screen.getByLabelText(/username/i);
const passwordInput = screen.getByLabelText(/password/i);
fireEvent.change(usernameInput, {target: {value: 'test'}});
fireEvent.change(passwordInput, {target: {value: 'test'}});
const button = await screen.findByText(/sign in/i);
await userEvent.click(button);
await screen.findByText(/usuário ou senha inválidos/i);
});
})
my error
I created a login function directly inside the login form, and everything works normally, but I need the handleLogin function within the context.
You need to wrap LoginPage with AuthProvider to access AuthContext.
function renderLoginPage() {
return (
render(
<BrowserRouter>
<AuthProvider>
<LoginPage />
</AuthProvider>
</BrowserRouter>
)
)
}