How to test componentDidUpdate()?

Filipe Gorges Reuwsaat picture Filipe Gorges Reuwsaat · Oct 22, 2018 · Viewed 23.4k times · Source

This is an example implementation:

export class Person extends Component {
  componentDidMount() {
    const { onLoadProfile, onLoadPolicy, person } = this.props
    onLoadProfile(person.profile.uri)
    onLoadPolicy(person.policy.uri)
  }

  componentDidUpdate(prevProps) {
    const { onLoadProfile, onLoadPolicy, person } = this.props
    const prevPerson = prevProps.person.uri
    const curPerson = person.uri

    // If person has changed, update Person component
    if (prevPerson !== curPerson) {
      onLoadProfile(person.profile.uri)
      onLoadPolicy(person.policy.uri)
    }
  }
}

On componentDidMount(), I've managed to test it like this:

describe('<Person />', () => {
  let props
  let mountedPerson
  const mockLoadProfile = jest.fn()
  const mockLoadPolicy = jest.fn()

  const person = () => {
    if (!mountedPerson) {
      mountedPerson = mount(<Person {...props} />)
    } 
    return mountedPerson
  }

  beforeEach(() => {
    props = {
      onLoadProfile = mockLoadProfile,
      onLoadPolicy = mockLoadPolicy
    }
    mountedPerson = undefined
  })

  afterEach(() => {
    mockLoadProfile.mockClear()
    mockLoadPolicy.mockClear()
  })

  describe('componentDidMount', () => {
    it('loads profile', () => {
      person().instance().componentDidMount()
      expect(mockLoadProfile).toBeCalled()
    })

    it('loads policy', () => {
      person().instance().componentDidMount()
      expect(mockLoadPolicy).toBeCalled()
    })
  })
})

On componentDidUpdate(), I'd need the component to attempt to render() twice in order to verify if it updates when it should and vice-versa, yet I couldn't find a proper way to do it.

What is the correct approach to test a componentDidUpdate() method in React?

PS.: I'm using jest, enzyme and React 15.

Answer

Bonomi picture Bonomi · Dec 4, 2018

I am using a different approach but you can copy the idea. You need to make a change in the props, I used the setProps() function:

describe('componentDidUpdate', () => {
    it('loads profile', () => { 
        const wrapper = shallow(<Person  {...props} />) as any;
        wrapper.setProps({ person: { uri: "something_different" } });
        expect(wrapper.instance().props.onLoadProfile).toBeCalled();
    })
})

I can see the pink in the coverage tests page is gone in the componentDidUpdate after running the test