Having very simple component:
import PropTypes from 'prop-types' import React from 'react' import { connect } from 'react-redux'
class MyComponent extends React.Component {
componentWillMount() {
if (this.props.shouldDoSth) {
this.props.doSth()
}
}
render () {
return null
}
}
MyComponent.propTypes = {
doSth: PropTypes.func.isRequired,
shouldDoSth: PropTypes.bool.isRequired
}
const mapStateToProps = (state) => {
return {
shouldDoSth: state.shouldDoSth,
}
}
const mapDispatchToProps = (dispatch) => ({
doSth: () => console.log('you should not see me')
})
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)
I want to test if doSth
is called when shouldDoSth
is equal true
.
I've written a test:
describe('call doSth when shouldDoSth', () => {
it('calls doSth', () => {
const doSthMock = jest.fn()
const store = mockStore({shouldDoSth: true})
shallow(<MyComponent doSth={doSthMock}/>, { context: { store } }).dive()
expect(doSthMock).toHaveBeenCalled()
})
})
but it seems that although I pass doSth as props it gets overridden by mapDispatchToProps
as console.log('im not a mock')
is executed.
How to properly pass/override/assign doSth
function to make component use mock instead of function from mapDispatchToProps
. Or maybe I'm doing something which should not be allowed at all and there is 'proper' way of testing my case. Shall I just mock dispatch instead and check if it is called with proper arguments?
it('mapDispatchToProps works as expected', () => { const actionProps = mapDispatchToProps({ submitClaimsForm: jest. fn() }); actionProps. submitClaimsForm(); expect(submitClaimsForm). toHaveBeenCalled(); });
The mapStateToProps() method is used to render the stored data to the component. The mapDispatchToProps() method is used to render the action creators with props to the component. The entirety of the results of the mapStateToProps() method is a plain object which is later merged into the component's prop.
Steps: extract each mapDispatchToProps property as a separate action creator function in another file. extract each mapStateToProps property as a separate selector function in another file. write tests for the selectors and action creators.
I think one thing you need to figure out is whether you want doSth
to be a prop, or a redux action connected in mapDispatchToProps.
If it's a prop, then you would connect it to redux in a parent (container). Remove it from this component's mapDispatchToProps. This would make the component more testable.
If you want it to be a redux action connected in this component, then it would make sense to move the action out of this component, somewhere like actions.js
, import it in this component, and then mock it in the test jest.mock('actions.js', () => ({doSth: jest.mock()}))
Export the unconnected component and use it in the test and you will be able to override the mapDispatchToProps action.
export class MyComponent extends React.Component {
componentWillMount() {
if (this.props.shouldDoSth) {
this.props.doSth()
}
}
render () {
return null
}
}
MyComponent.propTypes = {
doSth: PropTypes.func.isRequired,
shouldDoSth: PropTypes.bool.isRequired
}
const mapStateToProps = (state) => {
return {
shouldDoSth: state.shouldDoSth,
}
}
const mapDispatchToProps = (dispatch) => ({
doSth: () => console.log('you should not see me')
})
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)
import {MyComponent} from '../MyComponent'
describe('call doSth when shouldDoSth', () => {
it('calls doSth', () => {
const doSthMock = jest.fn()
const store = mockStore({shouldDoSth: true})
shallow(<MyComponent doSth={doSthMock}/>, { context: { store } }).dive()
expect(doSthMock).toHaveBeenCalled()
})
})
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