I've created a react component that when clicked executes an animation, and after the animation ends a callback runs. I want to test this functionality using Jest and react testing library. This is my component:
export const Valuable = ({ onClick }) => {
const [isClicked, setIsClicked] = useState(false);
const handleClick = () => {
setIsClicked(true);
};
const handleAnimationEnd = () => {
setIsClicked(false);
onClick();
};
return (
<div
className={isClicked ? 'animate-valuable ' : ''}
onClick={handleClick}
onAnimationEnd={handleAnimationEnd}
data-testid="valuable-container"
>
...
</div>
);
};
The test:
describe('Valuable', () => {
const valuableProps = {
onClick: jest.fn(),
};
beforeEach(() => {
render(<Valuable {...valuableProps} />);
});
it('should execute on click callback', () => {
expect(valuableProps.onClick).not.toHaveBeenCalled();
const container = screen.getByTestId('valuable-container');
expect(container).toBeInTheDocument();
fireEvent.click(container);
expect(valuableProps.onClick).toBeCalledTimes(1);
fireEvent.click(container);
fireEvent.click(container);
expect(valuableProps.onClick).toBeCalledTimes(3);
});
});
This is the error I got
● Valuable › should execute on click callback
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
My assumption is that you are running your tests in a jsdom environment. Per the React Testing Library Setup docs:
However, most people using React Testing Library are using it with the Jest testing framework with the testEnvironment set to jest-environment-jsdom (which is the default configuration with Jest 26 and earlier). jsdom is a pure JavaScript implementation of the DOM and browser APIs that runs in Node.
If this is the case, the animationend event is not supported in jsdom.
You can work around it by explicitly firing the animationend event:
it('should execute on click callback', () => {
expect(valuableProps.onClick).not.toHaveBeenCalled();
const container = screen.getByTestId('valuable-container');
expect(container).toBeInTheDocument();
fireEvent.click(container);
expect(valuableProps.onClick).toBeCalledTimes(0);
fireEvent.animationEnd(container);
expect(valuableProps.onClick).toBeCalledTimes(1);
fireEvent.click(container);
fireEvent.animationEnd(container);
fireEvent.click(container);
fireEvent.animationEnd(container);
expect(valuableProps.onClick).toBeCalledTimes(3);
});