jeudi 5 novembre 2020

How to Test (in Jest, React-Testing-Library) that Redux Dispatch function gets called during componentDidMount in React Class Component

Here is my basic React setup:

  1. I have a React class Component
  2. That is connected to my Redux store using connect()
  3. That fires a function during componentDidMount
  4. and that function is one that the Component has access to via mapDispatchToProps (implicitly)

I want to test that the above more or less works, that a specific function, in this cases fetchComments gets called during the componentDidMount lifecycle even of my component.

Here is the relevant component code:

class CommentContainer extends React.Component{
  componentDidMount(){
    this.props.fetchComments(this.props.resourceId)
  }

...

export default connect(mapStateToProps, { authorizeUser, addComment, fetchComments })(CommentContainer)

For testing, I have tried A LOT of different approaches. The only thing I can get to work is not to test that fetchComments has been called (which from my understanding would be the best way to isolate functionality), but to test that the store gets updated in a specific way (which would only happen if fetchComments gets called).

The test I have that works:

import { render } from '@testing-library/react'

...

it ('loads comments upon rendering', ()=> {
  const store = createStore(rootReducer, applyMiddleware(thunk)) //I've also tried mockStores, but that didn't seem to work well with the connect() method in the component
  expect(store.getState().comments.loadStatus).toBe(null)
  render(<Provider store={store}>
          <Router>
              <CommentContainer 
                relativePath={"/resources/:id"} 
                resourceId={1}
              />
            </Router>
          </Provider>
        )
  expect(store.getState().comments.loadStatus).not.toBe(null)
}

What I would like to do is something more along the lines of:

const spy = jest.spyOn(store, "dispatch")
render(<Provider store={store}>
            <Router>
            <CommentContainer 
              relativePath={"/resources/:id"} 
              resourceId={1}
            />
          </Router>
        </Provider>
        )
expect(spy).toHaveBeenCalledWith(fetchComments)

However, when I do this the test fails. The spy gets called twice, and the output I get is:

Expected: [Function fetchComments]
    Received
           1: [Function anonymous]
           2: [Function anonymous]

I gather this is happening because under the hood, store.dispatch is getting passed an anonymous function with the "work" of fetchComments but not getting passed the actual function fetchComments. Is that accurate?

I have also tried, among other things, creating a mock function of fetchComments and passing that as a prop directly to CommentContainer, but that prop seems to get overwritten by the connect() method and mapDispatchToProps

Another thing I tried was to use Enzyme and shallow and mount instead of react-testing-library's render and then use the .props() method to retrieve fetchComments from CommentContainer, but when I did that I got an error that prop was "Read Only" so I couldn't do something like jest.spyOn(wrapper.props, 'fetchComments')

I'd appreciate any feedback on how to make this work or how I should test this functionality.

Aucun commentaire:

Enregistrer un commentaire