0

In my <App /> component I want to show a loading screen until I've fetched my data and after fetching my data all the images(whose source's I got from my data) are loaded.

I am having difficulty to test that.

I want in essence something like this

const { products } = await vi.hoisted(
  async () => await import('./mock-products.js')
)

vi.mock('../../ShoppingCart-Core/api.js', () => {
  return {
    fetchData: vi.fn(
      async () =>
        new Promise((resolve) => {
          resolve(products)
        })
    ),
  }
})

  it('Loading Screen', () => {
    const {queryAllByTitle} = render(<App />)
    let products = queryAllByTitle(/category/i)
    expect(products.length).toBe(0)

//  do something that fetchs your mocked data and images are also loaded

    products = queryAllByTitle(/category/i)
    expect(products.length).toBe(0)
  })

I know how to implement it but don't know how to test it.

I've tried to do this

vi.mock('../../ShoppingCart-Core/api.js', () => {
  return {
    fetchData: vi.fn(
      async () =>
        new Promise((resolve) => {
          setTimeout(() => {
            resolve(products)
          }, 500)
        })
    ),
  }

it('Loading Screen', async () => {
    vi.useFakeTimers()
    render(<App />)

    await waitFor(() => {
      if (fetchData.mock.calls.length > 0) {
        vi.advanceTimersByTime(800)
      } else {
        throw new Error('Fetch not called yet')
      }
})

I am waiting for fetchData to be called and then advance timer so that the promise is resolved but. it doesn't work. Advancing timers doesn't do anything and just says waitFor timed out, and also the promise is not resolved.

My implementation in useEffect

  const [products, setProducts] = useState([])

  useEffect(() => {
    const getProducts = async () => {
      const products = await fetchData()
      setProducts(products)
    }

    getProducts()
  }, [])

1 Answer 1

0

You can use fireEvent to load images and then test if the loading state before and after load event.

   it('Loading Screen', async () => {
    const { getAllByAltText, findAllByTitle, getByTestId } = render(<App />)

    const loadingScreen = getByTestId('loading-screen')
    expect(loadingScreen).toBeInTheDocument()

    await findAllByTitle(/category/i)
    expect(loadingScreen).toBeInTheDocument()

    const images = getAllByAltText('product image')
    expect(loadingScreen).toBeInTheDocument()
    images.forEach((image) => fireEvent.load(image))
    expect(loadingScreen).not.toBeInTheDocument()
  })


Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.