Skip to content

findBy doesn't find and waitFor doesn't wait #736

@mjones-ebth

Description

@mjones-ebth

Describe the bug

This is an image gallery and I'm confident it's working correctly. It runs fine in the simulator. I've tried to variations of the same test:

 test('main image should display', async () => {
    const { findByTestId } = render(<ImageGallery images={images} />);
    const mainImage = await findByTestId('largeImage');
    expect(mainImage).toBeDefined();
  });

and

test('main image should display', async () => {
    const { getByTestId } = render(<ImageGallery images={images} />);
    await waitFor(() => {
      expect(getByTestId('largeImage')).toBeDefined();
    });
  });

In both instances the test fails with: Unable to find node on an unmounted component.

Inside my tsx file I have a useEffect hook that preloads all the images before displaying them. It then updates state (which causes another unrelated issue)

 // Cache all images in the gallery after initial component render
  useEffect(() =>  {
    if (!imagesReady) {
      const loadedImages: Array<Promise<boolean>> = images.map((image) => {
        return Image.prefetch(image.url);
      });

      Promise.all(loadedImages).then((imageLoadStatus) => {
        // Filter out any images that didn't properly load
        images = images.filter((_, index) => imageLoadStatus[index]);
        setActiveImage(images[0]);
        setImagesReady(true);
      });
    }
  });

Then in the return:

// Render either loading indicator or image gallery conditionally.
  if (!imagesReady) {
    return (
      <Container>
        <ActivityIndicator size="small" color="#202020" testID="loading" />
      </Container>
    );
  }

  return (
    
    <Container testID="galleryWrapper">
      <LargeImage source={{ uri: activeImage.url }} testID="largeImage" />
      <ThumbnailList
        horizontal
        data={images}
        renderItem={thumbnail}
        keyExtractor={(image) => image.id}
        showsHorizontalScrollIndicator={false}
      />
    </Container>
  );

Like I said, the code is working fine in the simulator and takes way less than 4.5 seconds to load. For testing purposes though, I added a jest.settimeout(10000) to make sure it wasn't a timing issue.

Expected behavior

I expect findBy to wait until the element with testID 'largeImage' appears on the screen, then I expect it to find and return it.

I expect waitFor to wait until the expectation is successful and then allow the test to proceed.

Steps to Reproduce

Most of the code above should help you reproduce. But:

  • Create a component that updates state in useEffect().
  • Attempt to use findBy or waitFor to grab a component that appears after the state update.

npmPackages:
@testing-library/react-native: ^7.2.0 => 7.2.0
react: 16.13.1 => 16.13.1
react-native: https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz => 0.63.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions