I have question about react-testing-library with custom hooks
My tests seem to pass when I use context in custom hook, but when I update context value in hooks cleanup function and not pass. So can someone explain why this is or isn't a good way to test the custom hook ?
The provider and hook code:
// component.tsx
import * as React from "react";
const CountContext = React.createContext({
count: 0,
setCount: (c: number) => {},
});
export const CountProvider = ({ children }) => {
const [count, setCount] = React.useState(0);
const value = { count, setCount };
return <CountContext.Provider value={value}>{children}</CountContext.Provider>;
};
export const useCount = () => {
const { count, setCount } = React.useContext(Context);
React.useEffect(() => {
return () => setCount(50);
}, []);
return { count, setCount };
};
The test code:
// component.spec.tsx
import * as React from "react";
import { act, render, screen } from "@testing-library/react";
import { CountProvider, useCount } from "./component";
describe("useCount", () => {
it("should save count when unmount and restore count", () => {
const Wrapper = ({ children }) => {
return <ContextStateProvider>{children}</ContextStateProvider>;
};
const Component = () => {
const { count, setCount } = useCount();
return (
<div>
<div data-testid="foo">{count}</div>
</div>
);
};
const { unmount, rerender, getByTestId, getByText } = render(
<Component />, { wrapper: Wrapper }
);
expect(getByTestId("foo").textContent).toBe("0");
unmount();
rerender(<Component />);
// I Expected: "50" but Received: "0". but I dont understand why
expect(getByTestId("foo").textContent).toBe("50");
});
});
When you call
render, the rendered component tree is like this:base element(
document.bodyby default) -> container(createElement('div')by default) -> wrapper(CountProvider) ->ComponentWhen you
unmountthe component instance,Wrapperwill also be unmounted. See here.When you
rerendera new component instance, it just uses a newuseCounthook and the default context value(you doesn' provide a context provider forrerender) in theuseContext. So thecountwill always be0. From the doc React.createContext:You should NOT unmount the
CountProviderwrapper, you may want to just unmount theComponent. So that the component will receive the latest context value after mutate it.So, the test component should be designed like this:
component.tsx:component.test.tsx:Test result:
Also take a look at this example: Codesandbox