With React, I have an overlay component that renders on top of an <img>
, setting its width/height/left/top to that of the image using various callbacks and other shenanigans. When I render the component, onload
doesn't fire. When I manually run fireEvent.load(img)
via react testing library it correctly fires, but none of the properties of the image are set ( clientWidth , actualWidth, etc.). I need these because the Overlay
doesn't render if width/height are zero. I believe these aren't set because react testing library doesn't actually computer the layout/render of the component.
I thought I would mock the <img>
tag, but it seems you can't do that. I tried mocking global.Image
but its constructor doesn't seem to be called by the renderer.
Is there a way to mock <img>
or manually set clientWidth
, actualWidth
, etc.?
Essentially my code looks something like this:
...
const [imgLoaded, setImageLoaded] = useState(false);
const onLoad = ()=>setImageLoaded(true);
const [imgWidth, setImageWidth] = useState();
useEffect(()=>{
if (!imgLoaded){
return;
}
//imgRef assigned elsewhere
setImageWidth(imgRef.actualWidth);
}, [imgLoaded]);
......
return <>
<img onload={onLoad}/>
<Overlay width={imgWidth}/>
For mocking <img>
tag, you can manually set the properties like clientWidth
and actualWidth
using the Object.defineProperty()
method to define these properties on the imgRef
object. I would create a utility function to mock the properties. Something like:
function mockImageProperties(image, properties) {
for (const [key, value] of Object.entries(properties)) {
Object.defineProperty(image, key, {
value,
writable: true, // You can use them as per your requirement.
configurable: true,
});
}
};
Then in your test file:
// ...Rest of the code
it('should test', () => {
const { getByRole } = render(<YourComponent />);
const image = getByRole('img');
mockImageProperties(image, {
clientWidth: 100,
actualWidth: 100,
// Mock other props as needed
});
fireEvent.load(image);
// Your test assertions
});