I am attempting to create mock methods and hooks in a file, then import those mock functions as needed in my test files.
useMyHook.jsx
const useMyHook = () => {
const [val, setVal] = useState(200)
return { val }
}
export { useMyHook }
Hello.jsx
:
import { useTestHook } from "@/hooks/useTestHook";
export const Hello = () => {
const { val } = useTestHook();
console.log({ val });
return (
<div>
<h2>Hello</h2>
</div>
);
};
This is the file where I mock the hooks and functions.
mock-hooks.js
:
import { useMyHook } from "@/hooks/useMyHook";
// import * as Hook from "@/hooks/useMyHook";
const mocks = {
useMyHook: (val = 9999) => {
jest
.spyOn({ useMyHook }, "useMyHook")
.mockImplementation(() => ({ val }));
/** this method of mocking used to work before, but now it gives
`TypeError: Cannot redefine property: useMyHook` */
// jest.spyOn(Hook, "useMyHook")
// .mockImplementation(() => ({ val }));
},
};
export { mocks };
The useMyHook
hook is a simple hook that only returns a value (state).
I import the mocks
variable in my test file and call mocks.useMyHook()
, but it does not work. I still receive the original hook's value while testing.
I am testing a Hello.jsx
component that uses the useMyHook
hooks and logs its return value in the console.
Hello.test.jsx
:
import { mocks } from "@/utils/test/mock-hooks";
import { Hello } from "./Hello";
import { render } from "@testing-library/react";
describe("Hello test", () => {
beforeEach(() => {
mocks.useMyHook(12345);
render(<Hello />, {
wrapper: ({ children }) => <>{children}</>,
});
});
test("should render the main container", () => {
screen.debug()
});
});
When I run the test, I still see the original hook's value being logged in the console instead of the mock value (12345).
I discovered that using jest.mock
before the describe
instead of jest.spyOn
works. However, I have many tests that modify the mocked value during the tests (such as inside a specific test()
block) by calling mocks.useMyHook
and the hook would return a different value for those specific test cases. The spyOn
method used to work fine previously, but many changes have been made in the project so now I am unable to make it work.
I am working on a Next.js project. Here is some information about the project:
Dependencies:
{
...
"dependencies": {
"next": "12.3.0",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"@babel/core": "7.17.8",
"@testing-library/jest-dom": "5.16.4",
"@testing-library/react": "12.1.2",
"@testing-library/react-hooks": "7.0.2",
"babel-jest": "27.4.6",
"jest": "28.1.0",
"jest-environment-jsdom": "28.1.0"
}
}
jest.config.js
:
const nextJest = require("next/jest");
const createJestConfig = nextJest({});
const customJestConfig = {
collectCoverageFrom: ["**/*.{js,jsx,ts,tsx}"],
verbose: true,
modulePaths: ["<rootDir>/"],
modulePathIgnorePatterns: ["<rootDir>/.next"],
testPathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/.next/"],
transform: {
"^.+\\.(js|jsx|ts|tsx)$": ["babel-jest", { presets: ["next/babel"] }],
},
transformIgnorePatterns: [
"/node_modules/",
"^.+\\.module\\.(css|sass|scss)",
],
testEnvironment: "jsdom",
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/$1",
},
};
module.exports = createJestConfig(customJestConfig);
.babelrc
:
{
"presets": ["next/babel"],
"plugins": []
}
EDIT: Typo & Added useMyHook
hook & Hello
component code.