Background
So I am trying to test a React functional component that calls a custom hook and depending on the return value of the hook, the component will render something differently. See below for an example:
// App.js
import "./styles.css";
import useCustomHook from "./useHook";
export default function App() {
const [state, handler] = useCustomHook();
return state ? <div>state is true</div> : <div>state is false</div>;
}
// useHook.js
import { useState } from "react";
const useCustomHook = () => {
const [myState, setMyState] = useState(false);
const handleSetMyState = () => {
return setMyState((prevState) => !prevState);
};
return [myState, handleSetMyState];
};
export default useCustomHook;
and finally, my test:
import "@testing-library/jest-dom";
import { render, screen, cleanup } from "@testing-library/react";
import App from "./App";
import useCustomHook from './useHook';
jest.mock("./useHook", () => ({
__esModule: true,
default: () => [false, jest.fn()]
}));
describe("testing App state", () => {
afterEach(() => {
jest.clearAllMocks();
cleanup();
});
it("should render false when state is false", () => {
// initialized as false AND mocked returned as false
render(<App />);
expect(screen.queryByText(/false/i)).toBeInTheDocument();
});
it("should render true when state is true", () => {
// the following doesn't work
useCustomHook.mockImplementation(() => [ true, jest.fn() ]) // outputs error: TypeError: _useCustomHook.default.mockImplementation is not a function
render(<App />);
expect(screen.queryByText(/true/i)).toBeInTheDocument();
});
});
Now the test would pass in my local environment ( unfortunately codesandbox's environment has issues with jest.mock, so I cannot provide a live sample ) but for the next test case, if the state returned is true the component should render text with "true" in it.
Issue
However, I am unable to change the mocked implementation or the returned value of the mock for it to return something like [true, jest.fn()]
So I have been stuck on this issue for some time now and cannot find any relatable resource online that fits as a solution. I have tried the following and none worked.
- importing the custom hook in test and changing its mocked implementation ( like shown in example )
- same as above but changing its mockReturnValueOnce to
[ true, jest.fn() ]
- adding a
__mocks__
directory in the same lvl as the hook and having a file with the same name__mocks__/useHook.js
, and mock the whole module byjest.mock('./useHook')
instead. Similar to this solution. - (updated, also tried this as latest attempt to mock)
jest.mock('./useHook', () => ({ __esModule: true, default: {useCustomHook: jest.fn()}}))
and it still outputs the same error when I tried to change the implementationTypeError: _useCustomHook.default.mockImplementation is not a function
Please help, something as simple as changing a mocked returned value is done so easily with other languages and testing frameworks. Why is jest complaining about?