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.body
by default) -> container(createElement('div')
by default) -> wrapper(CountProvider
) ->Component
When you
unmount
the component instance,Wrapper
will also be unmounted. See here.When you
rerender
a new component instance, it just uses a newuseCount
hook and the default context value(you doesn' provide a context provider forrerender
) in theuseContext
. So thecount
will always be0
. From the doc React.createContext:You should NOT unmount the
CountProvider
wrapper, 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