Prepare
We can use cra to create a basic react project easily.
npx create-react-app@latest react-demo-cra
Then we are ready to go.
Test useTitle
Say we have a custom hook called useTitle, which just update the title in the useEffect hook.
import { useEffect } from "react";
export default function useTitle(title) {
useEffect(() => {
document.title = title;
});
}
For the hook to actually run, we need run it in a component to test it.
import { render } from "@testing-library/react";
import useTitle from "./useTitle";
test("useTitle", () => {
const Component = () => {
useTitle("test");
return <div></div>;
};
render(<Component />);
expect(document.title).toBe("test");
});
Actually, react testing library provides a simple method renderHook
to run custom hooks. We we need to do is just pass it a callback, which calls the custom hook inside.
import { render, renderHook } from "@testing-library/react";
import useTitle from "./useTitle";
test("useTitle2", () => {
renderHook(() => useTitle("test2"));
expect(document.title).toBe("test2");
});
Test useValue
Now let see how to test a custom hook with states.
Below we define a custom hook useValue, which just define a state with useState hook.
import { useState } from "react";
export default function useValue(init) {
const [value, setValue] = useState(init);
return { value, setValue };
}
So how to test a hook like this? The renderHook
function returns a value, which contains all the values the custom hook returns. Then we could assert on these values.
import { renderHook } from "@testing-library/react";
import { act } from "react-dom/test-utils";
import useValue from "./useValue";
test("useValue", () => {
const { result } = renderHook(() => useValue("1"));
expect(result.current.value).toBe("1");
act(() => {
result.current.setValue("2");
});
expect(result.current.value).toBe("2");
});
Note that if we want to call the functions the custom hook returns, we need to wrap them in the act
function.