I'm trying to test the onload function of a custom hook to load image, but when i run the test, it skips the onload.
Hook:
import { useEffect, useState } from "react";
const useImage = (src: string) => {
const [loaded, setLoaded] = useState(false);
useEffect(() => {
const image = new Image();
image.src = src;
image.onload = () => {
return setLoaded(true); //can't test it
};
}, [src]);
return { loaded };
};
export default useImage;
Test:
import {
renderHook,
waitFor,
} from "@testing-library/react";
import useImage from "./useImage";
describe("useImage", () => {
it("Loads a data url into an image element", async () => {
const img = new Image();
img.src = "foo";
const { result } = renderHook(() => useImage("foo"));
await waitFor(() =>
expect(result.current).toStrictEqual({ loaded: true }) // loaded is always false
);
});
});
How can i make the test run the onload inside the useEffect? I'm using Jest and Typescript.
First of all, your
useImagehook is not doing anything except loading the image, then set a state. If this is only for demonstration purposes, that's fine, otherwise, you should look into what you are trying to achieve with that hook.Regarding the test, if you are using
jestandjsdomto test. Thenjsdomonly fire load events when they actually load something. Meaning you must use a real image in thesrcAND change some jest configuration like this:In
package.json, if you use jest.config.js, then please refer to the official doc for the equivalent.You'll also need to install canvas
Then your test is going to pass now. But, if you find this is a bit problematic to install a new dependency and change how the default test framework works, then you can mock the Image object implementation instead, personally, I would prefer this way: