I am trying to mock post request to api that returns status of 404, so after it returns response i can display an alert message which has data-testid="error-pw-api"
. But feels like the msw's post mock doesn't get triggered at all and it says can't find this element with this data-testid. I am on this issue quite long time hence i need help.
"axios": "^0.27.2", "msw": "^0.44.2",
The component looks like this:
import React, { useState } from 'react'
import { Alert, Modal, Spinner } from 'react-bootstrap'
import { toaster, translation } from '../../models/main';
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import { passwordSchema } from '../../utils/validationSchemas';
import axios from 'axios';
type Props = {
isModalOpen: boolean;
closeModal: () => void;
l: translation;
toaster: toaster;
userName: string
}
const PasswordChange = ({ isModalOpen, closeModal, l, userName, toaster }: Props) => {
const { register, handleSubmit, formState: { errors }, reset, clearErrors } = useForm({
mode: "onSubmit",
resolver: yupResolver(passwordSchema(userName, l)),
});
const [isPasswordVisible, setIsPasswordVisible] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const [serverError, setServerError] = useState("")
const submitChanges = async (data) => {
clearErrors()
setIsLoading(true);
try {
const url = '/user/' + userName + '/password'
const result = await axios.post(url,
{
password: data.passwordOne,
oldPassword: data.oldPassword
})
toaster.success(l("account_settings.message.password_changed_success"))
closeModal()
setServerError("")
reset()
} catch (err) {
const errorMessage = err.response.status === 404 && err.response.data.message ? l("account_settings.message.old_password_error") : err.response.statusText;
setServerError(l("account_settings.message.server_error") + errorMessage)
}
finally {
setIsLoading(false)
}
}
const handleClose = () => {
reset()
closeModal()
setServerError("")
setIsLoading(false)
setIsPasswordVisible(false)
}
return (
<Modal
size="lg"
show={isModalOpen}
onHide={handleClose}
aria-labelledby="example-modal-sizes-title-lg"
>
<Modal.Header closeButton>
<Modal.Title id="example-modal-sizes-title-lg">
{l("account_settings.change_password")}
</Modal.Title>
</Modal.Header>
<form onSubmit={handleSubmit(data => submitChanges(data))}>
<Modal.Body>
<div className="form-group">
<label
htmlFor="oldPassword">{l("account_settings.enter_old_password_label")}</label>
<input
required
id="oldPassword"
name="oldPassword"
data-testid="oldPassword"
type={isPasswordVisible ? "text" : "password"}
className={`form-control ${errors.oldPassword ? "is-invalid" : "border border-dark"}`}
{...register("oldPassword")}
placeholder={l("account_settings.old_password_placeholder")} />
{errors.oldPassword && <div className="invalid-feedback" data-testid="error-oldpw">
{errors.oldPassword.message}
</div>}
</div>
<div className="form-group">
<label htmlFor="passwordOne">{l("account_settings.enter_password")}</label>
<input
required
id="passwordOne"
data-testid="passwordOne"
name="passwordOne"
type={isPasswordVisible ? "text" : "password"}
className={`form-control ${errors.passwordOne ? "is-invalid" : "border border-dark"}`}
{...register("passwordOne")}
placeholder={l("account_settings.password")} />
{errors.passwordOne && <div className="invalid-feedback" data-testid="error-pw-one">
{errors.passwordOne.message}
</div>}
</div>
<div className="form-group">
<label htmlFor="passwordTwo">{l("account_settings.enter_password_again")}</label>
<input
required
id="passwordTwo"
data-testid="passwordTwo"
name="passwordTwo"
type={isPasswordVisible ? "text" : "password"}
className={`form-control ${errors.passwordTwo ? "is-invalid" : "border border-dark"}`}
{...register("passwordTwo")}
placeholder={l("account_settings.verify_password")} />
{errors.passwordTwo && <div className="invalid-feedback" data-testid="error-pw-two">
{errors.passwordTwo.message}
</div>}
</div>
{serverError && <div className="my-2" datat-testid="error-pw-api">
<Alert variant="danger">
<i className="fa-solid fa-triangle-exclamation"></i> {serverError}
</Alert>
</div>}
</Modal.Body>
<Modal.Footer>
<button
className="btn btn-outline-dark"
type="button"
onClick={() => setIsPasswordVisible(prev => !prev)}
>
{isPasswordVisible ?
<i className="fas fa-eye mt-2" /> : <i className="fas fa-eye-slash mt-2"></i>
}
</button>
<button
id="submit-pw-change"
data-testid="submit-pw-change"
disabled={isLoading}
type="submit"
className="btn btn-primary">
{isLoading && <Spinner data-testid="spinner-btn-pw-change" animation="border" variant="light" size='sm' className="mx-1" />}
{l("account_settings.change_password_button")}
</button>
<button
type="button"
className="btn btn-outline-dark"
onClick={handleClose}>
{l("buttons.cancel")}
</button>
</Modal.Footer>
</form>
</Modal>
)
}
export default PasswordChange;
And the test file itself is like
import { fireEvent, render, cleanup } from "@testing-library/react";
import React from "react";
import { act } from "react-dom/test-utils";
import PasswordChange from "../../src/components/UserDetails/passwordChange";
import { mockedToaster, mockFunc } from "./userDetails.test";
import { server } from "../__mocks__/serverMock";
import { rest } from "msw";
jest.mock("axios")
beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers());
describe("Server error tests", () => {
it("Test validation with ser verror", async () => {
await act(async () => {
const { findByTestId, getByTestId, queryByTestId } = render(<PasswordChange
isModalOpen={true}
closeModal={mockFunc}
l={mockedL}
toaster={mockedToaster}
userName={"randomname"} />)
fireEvent.change(await getByTestId("oldPassword"), { target: { value: 'RandomGang420££' } })
fireEvent.change(await getByTestId("passwordOne"), { target: { value: 'RandomGang420££' } })
fireEvent.change(await getByTestId("passwordTwo"), { target: { value: 'RandomGang420££' } })
fireEvent.submit(await getByTestId("submit-pw-change"));
server.use(rest.post("/user/:user/password", async (req, res, ctx) => {
return res(
ctx.status(404),
)
}))
expect(await queryByTestId("error-pw-one")).toBeNull()
expect(await queryByTestId("error-pw-two")).toBeNull()
expect(await findByTestId("error-pw-api")).toBeInTheDocument()
})
});
})
The reason MSW is not kicking in here is because you are using jest to fully mock axios. So MSW should work if you remove jest.mock("axios")
.