简体   繁体   中英

How would I test this using Jest & React Testing library?

I have a component that I would like to test using Jest and React Testing Library . When I say test, I'm basically saying that I want to check if the content shows up on the screen. However, I'm running into a serious problem because I'm dealing with an async operation that updates the state, so the content is not appearing immediately. How would I approach this problem? A code snippet would be much appreciated.

import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';

const Home = () => {
  const [tv, setTv] = useState([]);
  const [tvLoading, setTvLoading] = useState(true);

  // Go and fetch popular TV shows
  const getPopularTv = async () => {
    axios.get( ... )
    setTv(data);
    setTvLoading(false);
  };

  // This will run once. As soon as the component gets rendered for the 1st time
  useEffect(() => {
    getPopularTv();
  }, []);

  let TvData, loading;
  const img_path = 'https://image.tmdb.org/t/p/w500/';

  // If we have TV shows, set the 'TvData' variable to a pre-defined block of JSX using it.
  if (tv && tv.total_results > 0) {
    TvData = (
      <div className="row animated fadeIn ">
        {tv.results.slice(0, 10).map((show) => {
          return (
            // I WANT TO TEST IF THIS DIV APPEARS ON THE SCREEN
            // SO, ON THIS DIV I'M SETTING UP THE 'data-testid'
            // HOWEVER THIS IS A ASYNC OPERATION AND THE CONTENT
            // WON'T SHOW UP IMMEDIATELY. HOW WOULD I TEST THIS???
            <div
              data-testid="home-shows" // HERE'S THE ID THAT I WANT TO USE IN MY TEST
              className="col s6 m6 l6"
              key={show.id}
            >
              <Link to={'/tvs/' + show.id}>
                <img
                  className="responsive-img z-depth-3 poster tooltipped"
                  data-tooltip={show.name}
                  data-position="top"
                  src={img_path + show.poster_path}
                  alt={show.name}
                />
              </Link>
            </div>
          );
        })}
      </div>
    );
  }

   // Set up the 'loading' screen
   loading = (
    <div className="progress">
      <div className="indeterminate"></div>
    </div>
  );

  return (
      <div className="container">
            {tvLoading ? loading : TvData}
      </div>
  );
};

export default Home;

I've tried a combination of act , findByTestId , waitFor , etc. But I can't get it to work properly.

For example, I tried something like this:

it('should display TV shows', async () => {
  const { getByText, findByTestId } = 
    render(
      <BrowserRouter>
        <Home />
      </BrowserRouter>
    )
  await findByTestId('home-shows')
  expect(getByText('More Info')).toBeInTheDocument();
});

My thinking was, if the content appears then it should contain the text of "More Info". If that's not the case the content is not visible, so the test should fail. however, the test fails regards if the content appears or not and I'm getting an error that I should wrap my test inside of an act() callback.

Thanks to @EstusFlask I came to a breakthrough. The solution was to use waitFor . This is how I solved the problem:

it('should display movies', async () => {
  render(
    <BrowserRouter>
      <Home />
    </BrowserRouter>
  );
  

  const data = await waitFor(() => screen.findByTestId('home-shows'));
  expect(data).toBeTruthy();
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM