Code Example
Hi, I have an unusual test case, it's not working the way I expect. I am testing a component that resides inside of a context in our app. One of the values being passed down by the context is a piece of state as well as the setter of that piece of state.
e.g
// testContext.js
import { createContext, useState } from "react";
export const TestContext = createContext(null);
export default function TestContextProvider({ children }) {
const [stateVariable, setStateVariable] = useState(1);
return (
<TestContext.Provider value={{ stateVariable, setStateVariable }}>
{children}
</TestContext.Provider>
);
}
-
// App.js
import * as React from "react";
import "./styles.css";
import ComponentToBeTested from "./ComponentToBeTested";
import TestContextProvider from "./testContext";
export default function App() {
return (
<div className="App">
<TestContextProvider>
<ComponentToBeTested />
</TestContextProvider>
</div>
);
}
-
//ComponentToBeTested.js
import { useContext } from "react";
import { TestContext } from "./testContext";
export default function ComponentToBeTested() {
const { stateVariable, setStateVariable } = useContext(TestContext);
return (
<>
<h1>
Current value: <span data-testid="answer">{stateVariable}</span>
</h1>
<button
data-testid="increment-button"
onClick={() => setStateVariable(stateVariable + 1)}
>
Increment
</button>
</>
);
}
Testing ComponentToBeTested.js
I am trying to test that when the use clicks the button, the value increases. I thought I could use the renderHook function to mock the useState. I also put a spy on the return value of useContext and returned my mocked implementation of the state and setter. I then simulate a button click and assert that the value shown in the UI is the same as the value returned from renderHook
e.g
it("mocks the useState and renders state updates", () => {
const { result } = renderHook(() => useState(1));
jest.spyOn(React, "useContext").mockReturnValue({
stateVariable: result.current[0],
setStateVariable: result.current[1]
});
render(<ComponentToBeTested />);
const button = screen.getByTestId("increment-button");
fireEvent.click(button);
const answer = parseInt(screen.getByTestId("answer").innerHTML);
expect(answer).toEqual(result.current[0]);
});
This is not working however. The UI does not update. I am wondering if anyone knows:
Why is the component not re-rendering when the value being returned by the useContext has been updated?
Is there a way to get the component to rerender manually given the updated state, I would expect it to render as expected?
Is there just a better way to achieve this. I feel like I might be going all around the world to do something that is probably simple
Link to a codesandbox where you can play around with this example here