Testing mandatory PropTypes passed to Redux HOC's

Viewed 285

I would like to write a test which ensures that a react component passes a prop which has propType.isRequired to a child component.

I would like this test to fail if the prop is not provided and pass if it is. I'm using jest-prop-type-error to throw errors in my tests.

Given the following two components:

Parent.js

const Parent = ({ renderReduxChild , childTitle }) => 
    { return renderReduxChild ? <ReduxChild title={childTitle} /> : <NonReduxChild />}

ReduxChild.js

const ReduxChild = ({ title }) => <div>{title}</div>

ReduxChild.propTypes = { title: PropTypes.string.isRequired }

export default connect(mapStateToProps, mapStateToProps)(ReduxChild)

I would like ensure my Parent component passes the childTitle prop without needing to write an explicit test which says:

Parent.test.js

it('should send the required "title" prop to ReduxChild', () => {
  const wrapper = shallow(<Parent renderReduxChild={true} childTitle={'expectedTitle'} />)
  expect(wrapper.props().title).toBeDefined()
})

Please note the following:

  • If child was not a connected component, I could not pass childTitle to Parent and the test would fail. Since it is a connected component, if I don't pass childTitle the test passes (even though it's required in ReduxChild)
  • I'm aware that this is quite close to testing the functionality of PropTypes, but it's subtly different in that I want to check that Parent is using Child correctly, not that ReduxChild throws a PropTypes error when the prop isn't passed. I want the test to fail at build time when a dev removes the required prop, not at runtime when I exercise the code.

EDIT:

To further illustrate the issue, if I have a second child component NonReduxChild and give it a propType which isRequired and have a test for Parent which renders the NonReduxChild without providing the prop I get an error thrown at build / test time. Wheres with the ReduxChild I do not.

NonReduxChild.js

const NonReduxChild = ({ text }) = <div>{text}</div>
NonReduxChild.propTypes = { text: PropTypes.string.isRequired }

Test output

FAIL  test/components/Parent.test.js (8.782s)

● <Parent /> › when rendering the component › if renderReduxChild is false it should render <NonReduxChild />

Warning: Failed prop type: The prop `title` is marked as required in `NonReduxChild`, but its value is `undefined`.
    in NonReduxChild

  28 |   render() {
  29 |     const { renderReduxChild, childTitle } = this.state
> 30 |     return renderReduxChild ? <ReduxChild title={childTitle } /> : <NonReduxChild />
     |                                                                                                                                                                                                ^
  31 |   }
  32 | }
  33 |

As you can see from the test output, when I don't provide a required prop to NonReduxChild I get a test failure which nicely captures the usage of NonReduxChild from other components which might not provide required PropTypes I don't get this same failure from ReduxChild I have to write a specific test (which I don't want to do across a codebase with hundreds of components).

2 Answers

I believe the issue you are running into is that PropTypes just logs warnings, which don't actually cause tests to fail.

If the prop is critically important to the operation of the component and you are set on not writing tests to assert that props are present, you could always have the component throw an error if that prop isn't present. That will cause the tests to fail.

I think you can define title as prop and u could call it, instead of "childTitle". Try this.. it may work

it('should send the required "title" prop to ReduxChild', () => {
`var wrapper = shallow(<Parent renderReduxChild={true} title={"expectedTitle"} />);`
  expect(wrapper.props().title).toBeDefined()
  `console.log("",childTitle);`
})
Related