I’m using a custom react hook to perform two GET operations using react query. The API is in a separate module and uses both getTestByUid() and getTestStatuses() inside useQuery.
// TestHook.js
import { useQuery } from "react-query"
export const useTest = (uid) => {
const { data: test } = useQuery("test", () => getTestByUid(uid));
const { data: testStatuses } = useQuery("statuses", () => getTestStatusesByUid(uid));
return {
test,
testStatuses
}
}
My tests are defined as follows:
// test-hook.test.js
import { renderHook } from "@testing-library/react-hooks";
import { QueryClient, QueryClientProvider } from "react-query";
import { useTest } from "../src/hooks/TestHook";
import * as testApi from "../src/api/test-api.js";
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
const wrapper = ({ children }) => {
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
};
describe("useTestHook", () => {
it("should return a test", async () => {
jest
.spyOn(testApi, "getTestByUid")
.mockImplementationOnce(() =>
Promise.resolve({ data: { name: "secret test" } })
);
const { result, waitForNextUpdate } = renderHook(
() => useTest("bb450409-d778-4d57-a4b8-70fcfe2087bd"),
{ wrapper: wrapper }
);
await waitForNextUpdate();
expect(result.current.test).toBe({ name: "secret test" });
});
it("should return statuses for a test", async () => {
jest.spyOn(testApi, "getTestStatusesByUid").mockImplementationOnce(() =>
Promise.resolve({
data: ["in_progress", "ready_for_approval", "rejected"],
})
);
const { result, waitForNextUpdate } = renderHook(
() => useTest("bb450409-d778-4d57-a4b8-70fcfe2087bd"),
{ wrapper: wrapper }
);
await waitForNextUpdate();
expect(result.current.testStatuses).toBe([
"in_progress",
"ready_for_approval",
"rejected",
]);
});
});
The first test passes fine but in the second test I get undefined returned when trying to assert testStatuses value. Why might this be happening when I am spying on the getTestStatusesByUid api call?
2
Answers
You should mock
getTestStatusesByUid
andgetTestByUid
for each test case, otherwise, the test case is not isolated.These two test cases test the return value of the
useTest
hook, so there is no need to separate them. One test case is enough.Besides, the mock resolved values for both APIs are not correct based on the expected value in assertion statement. Since
useQuery
returns adata
field to hold the resolved value, wrap the resolved value into{ data: "mock resolved value" }
is not necessary.E.g.
api.js
:test-hook.js
:test-hook.test.js
:Test result:
package versions:
In your second test, you are mocking the getTestStatusesByUid function using jest.spyOn, but it seems like you are not returning the mocked value correctly. The mockImplementationOnce function expects a function that returns the mocked value, but you are passing an object instead.
To fix the issue, you need to wrap the mocked value in a function. Here’s an updated version of your second test:
In the updated code, the mockImplementationOnce function receives an arrow function that returns the mocked value. Also, note that I changed the expectation from toBe to toEqual since you are comparing arrays, and toEqual performs a deep comparison.
With these changes, the second test should now correctly assert the value of testStatuses in your custom hook.