I want to test that a search box does calls a handler (passed as prop) with the fetched results and resets the input field afterwards.
import React, { useState } from 'react' import Axios from 'axios' import './style.css' function SearchBox({ setPhotos }) { const [searchTerm, setSearchTerm] = useState('') const handleTyping = (event) => { event.preventDefault() setSearchTerm(event.currentTarget.value) } const handleSubmit = async (event) => { event.preventDefault() try { const restURL = `https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=${ process.env.REACT_APP_API_KEY }&per_page=10&format=json&nojsoncallback=1'&text=${encodeURIComponent( searchTerm )}` const { data } = await Axios.get(restURL) const fetchedPhotos = data.photos.photo setPhotos(fetchedPhotos) setSearchTerm('') // 👈 This is giving trouble } catch (error) { if (!Axios.isCancel(error)) { throw error } } } return ( <section> <form action="none"> <input aria-label="Search Flickr" placeholder="Search Flickr" value={searchTerm} onChange={handleTyping} /> <button type="submit" aria-label="Submit search" onClick={handleSubmit}> <span aria-label="search icon" role="img"> 🔍 </span> </button> </form> </section> ) } export default SearchBox
import React from 'react' import { render, fireEvent, waitFor, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { rest } from 'msw' import { setupServer } from 'msw/node' import SearchBox from '.' import { act } from 'react-dom/test-utils' const fakeServer = setupServer( rest.get( 'https://api.flickr.com/services/rest/?method=flickr.photos.search', (req, res, ctx) => res(ctx.status(200), ctx.json({ photos: { photo: [1, 2, 3] } })) ) ) beforeAll(() => fakeServer.listen()) afterEach(() => fakeServer.resetHandlers()) afterAll(() => fakeServer.close()) ... test('it calls Flickr REST request when submitting search term', async () => { const fakeSetPhotos = jest.fn(() => {}) const { getByRole } = render(<SearchBox setPhotos={fakeSetPhotos} />) const inputField = getByRole('textbox', { name: /search flickr/i }) const submitButton = getByRole('button', { name: /submit search/i }) userEvent.type(inputField, 'Finding Walley') fireEvent.click(submitButton) waitFor(() => { expect(fakeSetPhotos).toHaveBeenCalledWith([1, 2, 3]) waitFor(() => { expect(inputField.value).toBe('') }) }) })
This is the error:
Watch Usage: Press w to show more. ● Cannot log after tests are done. Did you forget to wait for something async in your test? Attempted to log "Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function. in SearchBox (at SearchBox/index.test.js:38)". 38 | aria-label="Search Flickr" 39 | placeholder="Search Flickr" > 40 | value={searchTerm} | ^ 41 | onChange={handleTyping} 42 | /> 43 | <button type="submit" aria-label="Submit search" onClick={handleSubmit}>
Advertisement
Answer
waitFor
returns a Promise so you need to use await
:
await waitFor(() => { expect(fakeSetPhotos).toHaveBeenCalledWith([1, 2, 3]); expect(inputField.value).toBe(''); });