Take this basic component using state:
export const InputChild = () => {
const [count, setCount] = useState(0);
const updateCount = () => setCount((prev) => prev + 1);
return (
<>
<h1>Count: </h1>
<h2>{count}</h2>
<button onClick={updateCount}>Click</button>
</>
);
};
And this test that just ensures the count increases after clicking the button:
it('should increment', () => {
act(() => {
render(<InputChild />);
});
let h2 = screen.getByRole('heading', { level: 2 });
let count = Number(h2.innerHTML);
const button = screen.getByText('Click');
expect(count).toBe(0);
expect(button).toBeInTheDocument();
// fireEvent.click(button); // also works
act(() => {
button.dispatchEvent(new MouseEvent('click', { bubbles: true }));
});
// count = Number(h2.innerHTML); // then use count below
expect(Number(h2.innerHTML)).toBe(1);
fireEvent.click(button);
expect(Number(h2.innerHTML)).toBe(2);
fireEvent.click(button);
expect(Number(h2.innerHTML)).toBe(3);
});
It’s annoying that I have to use Number(h2.innerHTML)
in here in order to get the latest count value. Alternatively I could redefine count whenever clicking the button to get the latest innerHTML value (as the state changes):
count = Number(h2.innerHTML);
expect(count).toBe(1);
fireEvent.click(button);
count = Number(h2.innerHTML);
expect(count).toBe(2);
fireEvent.click(button);
count = Number(h2.innerHTML);
expect(count).toBe(3);
But this seems too verbose.
Is there not a better way of doing this other than something like Number(h2.innerHTML)
? I am new to unit testing and am trying to not write bad code, and the above just doesn’t feel right to me and I assume someone will have a better way of doing it.