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.
JavaScript
โx
54
54
1
import React, { useState } from 'react'
2
import Axios from 'axios'
3
โ
4
import './style.css'
5
โ
6
function SearchBox({ setPhotos }) {
7
const [searchTerm, setSearchTerm] = useState('')
8
โ
9
const handleTyping = (event) => {
10
event.preventDefault()
11
setSearchTerm(event.currentTarget.value)
12
}
13
โ
14
const handleSubmit = async (event) => {
15
event.preventDefault()
16
โ
17
try {
18
const restURL = `https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=${
19
process.env.REACT_APP_API_KEY
20
}&per_page=10&format=json&nojsoncallback=1'&text=${encodeURIComponent(
21
searchTerm
22
)}`
23
const { data } = await Axios.get(restURL)
24
const fetchedPhotos = data.photos.photo
25
setPhotos(fetchedPhotos)
26
setSearchTerm('') // ๐ This is giving trouble
27
} catch (error) {
28
if (!Axios.isCancel(error)) {
29
throw error
30
}
31
}
32
}
33
โ
34
return (
35
<section>
36
<form action="none">
37
<input
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}>
44
<span aria-label="search icon" role="img">
45
๐
46
</span>
47
</button>
48
</form>
49
</section>
50
)
51
}
52
โ
53
export default SearchBox
54
โ
JavaScript
1
41
41
1
import React from 'react'
2
import { render, fireEvent, waitFor, screen } from '@testing-library/react'
3
import userEvent from '@testing-library/user-event'
4
import { rest } from 'msw'
5
import { setupServer } from 'msw/node'
6
โ
7
import SearchBox from '.'
8
import { act } from 'react-dom/test-utils'
9
โ
10
const fakeServer = setupServer(
11
rest.get(
12
'https://api.flickr.com/services/rest/?method=flickr.photos.search',
13
(req, res, ctx) =>
14
res(ctx.status(200), ctx.json({ photos: { photo: [1, 2, 3] } }))
15
)
16
)
17
โ
18
beforeAll(() => fakeServer.listen())
19
afterEach(() => fakeServer.resetHandlers())
20
afterAll(() => fakeServer.close())
21
โ
22
23
โ
24
test('it calls Flickr REST request when submitting search term', async () => {
25
const fakeSetPhotos = jest.fn(() => {})
26
const { getByRole } = render(<SearchBox setPhotos={fakeSetPhotos} />)
27
โ
28
const inputField = getByRole('textbox', { name: /search flickr/i })
29
const submitButton = getByRole('button', { name: /submit search/i })
30
โ
31
userEvent.type(inputField, 'Finding Walley')
32
fireEvent.click(submitButton)
33
โ
34
waitFor(() => {
35
expect(fakeSetPhotos).toHaveBeenCalledWith([1, 2, 3])
36
waitFor(() => {
37
expect(inputField.value).toBe('')
38
})
39
})
40
})
41
โ
This is the error:
JavaScript
1
13
13
1
Watch Usage: Press w to show more.
2
โ Cannot log after tests are done. Did you forget to wait for something async in your test?
3
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.
4
in SearchBox (at SearchBox/index.test.js:38)".
5
โ
6
38 | aria-label="Search Flickr"
7
39 | placeholder="Search Flickr"
8
> 40 | value={searchTerm}
9
| ^
10
41 | onChange={handleTyping}
11
42 | />
12
43 | <button type="submit" aria-label="Submit search" onClick={handleSubmit}>
13
โ
Advertisement
Answer
waitFor
returns a Promise so you need to use await
:
JavaScript
1
5
1
await waitFor(() => {
2
expect(fakeSetPhotos).toHaveBeenCalledWith([1, 2, 3]);
3
expect(inputField.value).toBe('');
4
});
5
โ