javascriptreactjsjestjsreact-testing-library

How can I mock an image with React testing library?


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}/>

Solution

  • 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
    });