Find image after onLoad event with react-testing-library

22 Views Asked by At

I wanted to test appearing image after spinner (loader) disapper

Image component

export const Thumb: React.FC<ThumbProps> = ({ file, removeImage, url }) => {
  const [thumb, setThumb] = useState(undefined)
  const [isLoading, setIsLoading] = useState(false)
  const [isShowRemoveBtn, setIsShowRemoveBtn] = useState(false)

  const imageRef = useRef<HTMLImageElement | null>(null)

  useEffect(() => {
    if (file) {
      const reader = new FileReader()
      reader.onloadstart = () => {
        setIsLoading(true)
      }

      reader.onloadend = () => {
        // @ts-ignore
        setThumb(reader.result)
        setIsLoading(false)
        delay(300).then(() => setIsShowRemoveBtn(true))
      }

      reader.readAsDataURL(file)
    }
  }, [file])

  useEffect(() => {
    if (url) {
      setIsLoading(true)
      const image = imageRef.current

      if (image) {
        image.onload = () => {
          setIsLoading(false)
          delay(300).then(() => setIsShowRemoveBtn(true))
        }
      }

      return () => {
        if (image) {
          image.onload = null
        }
      }
    }
  }, [url])

  if (!file && !url) {
    return null
  }

  if (isLoading) {
    return (
      <Box
        sx={{ display: "grid", placeContent: "center", height: LOADED_IMAGE_HEIGHT }}
        data-testid={TEST_ID.SPINNER}>
        <CircularProgress color="primary" />
      </Box>
    )
  }

  return (
    <ImageWrapper>
      <ProductImage
        ref={imageRef}
        src={thumb || url}
        alt="product-image"
        $isLoading={!isShowRemoveBtn}
        data-testid={TEST_ID.PRODUCT_CREATE_EDIT_IMAGE}
      />

      <Tooltip title="Remove">
        <StyledIconButton onClick={removeImage} $isLoading={!isShowRemoveBtn}>
          <ClearRoundedIcon fontSize="large" />
        </StyledIconButton>
      </Tooltip>
    </ImageWrapper>
  )
}

How can I do it correctly? I've tried to find it throw waitFor, but it does not work

describe("Product edit", () => {
  it("Edit product and return settings back", async () => {
    render(
      <MemoryRouter>
        <Products />
        <Popups />
      </MemoryRouter>
    )

     await waitFor(() => {
       const productImage = screen.getByTestId(TEST_ID.PRODUCT_CREATE_EDIT_IMAGE)
       expect(productImage).toBeInTheDocument()
     })
  })
})

Also I've tried to wait for disappering spinner

 const spinner = screen.getByTestId(TEST_ID.SPINNER)
 await waitForElementToBeRemoved(spinner)

But it complains to Error: Timed out in waitForElementToBeRemoved. Even if I pass timeout

 await waitForElementToBeRemoved(spinner, { timeout: 5000 })

It shows Error: Test timed out in 5000ms.

Also I've tried to replace getByTestId to findByTestId

   const productImage = await screen.findByTestId(TEST_ID.PRODUCT_CREATE_EDIT_IMAGE)
   expect(productImage).toBeInTheDocument()

And it again complain Unable to find an element by: [data-testid="product_create_edit_image"]

What do I need to do for the tests to work?

0

There are 0 best solutions below