In my last commit, I degraded the performance of my React app (I introduced Context, and I learned that it interfers with Memoization).
I would like to add tests that checks that a memoized component is not rerenderer after a user action.
App.jsx
import {MemoizedChildComponent} from "./ChildComponent"
export function App() {
return (
<div>
...
<MemoizedChildComponent prop1={...} prop2../>
...
</div>
)
}
ChildComponent.jsx
import {memo} from "react"
function ChildComponent({prop1, prop2,...}) {
return (
...
)
}
const MemoizedChildComponent = memo(ChildComponent);
export { MemoizedChildComponent};
Using Jest & React Testing Library, I would like to write this test :
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { App } from "./App"
test("ChildComponent was not rerendered", async () => {
render(<App>);
await userEvent.click(...)
// Assert that ChildComponent was not rerendered
}
I searched in the React Testing Library API and I could not find a way to listen to render events. I thought about Jest mocks, but I don't want to replace ChildComponent, but listen to its render events.
Do you have a proposal to write this test?
I was finally able to make it work. This SO answer gave the info I needed to access the underlying component of a Memoized component.
So my solution
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { App } from "./App"
import * as ChildComponentModule from "../../RecordRow/RecordRow";
jest.mock("./ChildComponent", () => {
const ChildComponentModule = jest.requireActual("./ChildComponent");
return {
...ChildComponentModule, // Unnecessary if there's only 1 exported item
MemoizedChildComponent : {
...ChildComponentModule.MemoizedChildComponent,
type: jest.spyOn(ChildComponentModule.MemoizedChildComponent, "type"), // Spy on the underlying ChildComponent of MemoizedChildComponent
},
};
});
test("ChildComponent was not rerendered", async () => {
render(<App>);
jest.clearAllMocks(); // ignore initial renders
await userEvent.click(...)
// Assert that ChildComponent was not rerendered
expect(ChildComponentModule.MemoizedChildComponent.type).not.toHaveBeenCalled();
}
In my case, I use named exports. For default exports, you may use this syntax