I'm testing a component that I need to wait for a dispatch call to be made and then wait for the 'loading' state to change as well.
I'm using jest.mock to deliver the results of the dispatch however it appears as though the results aren't being delivered as far as I can tell...
My Post Detail Component: useEffect(() => {
const postDetail = async () => {
await dispatch(postDetailView(postID))
console.log('post Detail', postID)
setLoading(false)
}
postDetail()
}, [dispatch])
My Test Setup:
const mockDispatch = jest.fn();
jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: () => mockDispatch.mockReturnValueOnce({
_id: '12345',
title:'A New Post',
description: 'A New Description'
}) // Return a value since I'm expecting a value to be returned before I redirect
}))
describe('Post Detail', () => {
it('Post Detail Get View', async () => {
const result = await waitFor(() => render(
<MemoryRouter initialEntries={['/detail/12345']}>
<Provider store={store}>
<Routes>
<Route path='/detail/:postID' exact element={<PostDetail/>} />
</Routes>
</Provider>
</MemoryRouter>))
// This produces and Error that title does not exist
const postElementTitle = screen.getByText(/title/i)
//This test passes
expect(mockDispatch).toHaveBeenCalledTimes(1)
})
})
What I'm hoping would happen is the component would load in the waitFor block and call dispatch, get the results, but that does not seem to be happening, and oddly the dispatch call does get called successfully but the results don't seem to be making it to the component.
The Error results:
TestingLibraryElementError: Unable to find an element with the text: /title/i. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
Ignored nodes: comments, <script />, <style />
<body>
<div>
<div
class="card"
>
<div
class="row"
>
<div
class="col"
>
<a
href="/detail/undefined" // this is where the ID of the dispatch results should appear but it's coming up blank
>
<p /> //This is where title from the dispatch tests should be appearing but it's blank
</a>
</div>
<div
class="col"
>
<p />
</div>
<div
class="col"
>
<button
class="btn btn-outline-primary"
type="button"
>
Update
</button>
<button
class="btn btn-outline-danger"
type="button"
>
Delete
</button>
</div>
</div>
</div>
</div>
</body>
Versions I'm using:
"@reduxjs/toolkit": "^1.7.1",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^13.5.0",
"react": "^17.0.2",
"react-redux": "^7.2.6",
"react-router-dom": "^6.2.1",
"react-scripts": "5.0.0",
To recap what's going on (I think) is that the dispatch element is getting called but the results are not getting read by the component itself. I'm not sure how to remedy this or if anyone can see any glaring missteps on my part. Thanks in advance.
I figured out what I did wrong and that I also had an incorrect approach to testing a component itself. Also I learned a lot about redux and how complicated it is to test but the learning was a good thing for me to figure out more ins and outs of redux.
TestingFile
const store = configureStore({
reducer:{
post: postReducer,
alert: alertReducer
}
})
const MockComponent = (props={}, history={}) => {
return(
<BrowserRouter>
<Provider store={store}>
<PostDetail/>
</Provider>
</BrowserRouter>)
}
const mockDispatch = jest.fn();
// const mockSelector = jest.fn()
jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useDispatch: () => mockDispatch
// useSelector: () => mockSelector.mockReturnValueOnce(true)
}))
// // mock useNavigate
describe('Post Detail', ()=>{
it('post detail', async () => {
render(MockComponent())
// Use dispatch to update the store correctly
store.dispatch(postSliceActions.postDetail({_id:1, title:'A new Post', description: 'A new Desc'}))
// Check that dispatch was called within the component
expect(mockDispatch).toHaveBeenCalledTimes(1)
// Ensure the loading screen has time to go away
await waitForElementToBeRemoved(() => screen.queryByText(/Loading/i))
// Check for the post title in the component
expect(screen.getByText(/a new post/i)).toBeInTheDocument()
// screen.debug()
})
})
Also this article helped me as well, especially with the waiting for the element to be removed...https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning
Thanks,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With