Mock mutateAsync in jest
I have this hook that I mock with MSW. The tests for the isolated hook work.
Writing tests for my component has been painful. It seems like I have to mock the entire implementation of
export const useEditUserProfile = () => {
return useMutation({
mutationFn: ({ data }: Payload) =>
request({
url: "user",
body: data,
method: "PATCH",
}),
});
};
export const useEditUserProfile = () => {
return useMutation({
mutationFn: ({ data }: Payload) =>
request({
url: "user",
body: data,
method: "PATCH",
}),
});
};
mutateAsync
. Is there a better way to do this?
export const Profile = () => {
const { mutateAsync: mutateUserProfile } = useEditUserProfile();
const onUpdateUserProfile = useCallback(
async (values: UserProfileForm) => {
await mutateUserProfile(
{ data: values },
{
onSuccess: res => {
console.log("res :>> ", res);
const currentUserData = user();
const updatedUserData = {
...currentUserData,
first_name: res.first_name,
last_name: res.last_name,
email: res.email,
};
setUser(updatedUserData);
setAlert({
message: "User profile updated!",
type: "success",
});
},
onError: () => {
setAlert({
message: "Uh-oh! Something went wrong!",
type: "error",
});
},
},
);
},
[mutateUserProfile, setAlert],
);
export const Profile = () => {
const { mutateAsync: mutateUserProfile } = useEditUserProfile();
const onUpdateUserProfile = useCallback(
async (values: UserProfileForm) => {
await mutateUserProfile(
{ data: values },
{
onSuccess: res => {
console.log("res :>> ", res);
const currentUserData = user();
const updatedUserData = {
...currentUserData,
first_name: res.first_name,
last_name: res.last_name,
email: res.email,
};
setUser(updatedUserData);
setAlert({
message: "User profile updated!",
type: "success",
});
},
onError: () => {
setAlert({
message: "Uh-oh! Something went wrong!",
type: "error",
});
},
},
);
},
[mutateUserProfile, setAlert],
);
1 Reply
like-goldOP•2y ago
this is the test. However, when I log
There was a similar question asked two years ago https://stackoverflow.com/a/67111510. I partially agree with the answer. However, what if you wanted to test some behavior inside the
res
inside onSuccess, I don't get a value. Is there any resources as to how I can mock the values on onSuccess
or onError
?
jest.mock("@libs/api/data-access", () => ({
apiUrl: () => "http://localhost:8000/api/user/",
useUserLogout: () => jest.fn(),
useEditUserProfile: () => ({
mutateAsync: jest.fn().mockImplementation(userData => {
const mockResponse = {
first_name: "Jerry",
last_name: "Seinfeld",
email: "jerryseinfeld@gmail.com",
};
return new Promise((resolve, reject) => {
resolve(mockResponse);
});
}),
}),
user: () => ({
first_name: "Elaine",
last_name: "Benes",
email: "elainebenes@gmail.com",
}),
}));
describe("Settings: Profile", () => {
it("updates user profile and shows success alert on successful update", async () => {
const mockSetAlert = jest.fn();
const { getByLabelText, getByRole } = render(<Profile />);
fireEvent.change(getByLabelText(/first name/i), {
target: { value: "Jerry" },
});
fireEvent.change(getByLabelText(/last name/i), {
target: { value: "Seinfeld" },
});
fireEvent.change(getByLabelText(/email/i), {
target: { value: "jerryseinfeld@gmail.com" },
});
fireEvent.click(getByRole("button", { name: /update/i }));
await waitFor(() => {
expect(mockSetAlert).toHaveBeenCalledWith({
message: "User profile updated!",
type: "success",
});
});
});
});
jest.mock("@libs/api/data-access", () => ({
apiUrl: () => "http://localhost:8000/api/user/",
useUserLogout: () => jest.fn(),
useEditUserProfile: () => ({
mutateAsync: jest.fn().mockImplementation(userData => {
const mockResponse = {
first_name: "Jerry",
last_name: "Seinfeld",
email: "jerryseinfeld@gmail.com",
};
return new Promise((resolve, reject) => {
resolve(mockResponse);
});
}),
}),
user: () => ({
first_name: "Elaine",
last_name: "Benes",
email: "elainebenes@gmail.com",
}),
}));
describe("Settings: Profile", () => {
it("updates user profile and shows success alert on successful update", async () => {
const mockSetAlert = jest.fn();
const { getByLabelText, getByRole } = render(<Profile />);
fireEvent.change(getByLabelText(/first name/i), {
target: { value: "Jerry" },
});
fireEvent.change(getByLabelText(/last name/i), {
target: { value: "Seinfeld" },
});
fireEvent.change(getByLabelText(/email/i), {
target: { value: "jerryseinfeld@gmail.com" },
});
fireEvent.click(getByRole("button", { name: /update/i }));
await waitFor(() => {
expect(mockSetAlert).toHaveBeenCalledWith({
message: "User profile updated!",
type: "success",
});
});
});
});
onSuccess
callback? In my case, I update the user value that is stored in localstorage.
I have separate tests that test the behavior of updating localStorage variables. But they are considered "unit" rather than "integration" tests, which what the above is.