Today I Learned

Test multi-promise function without return

The tested function:

_setDevices = () => {
  const { selectCamera } = this.props

  WebRTCDevices.getPermissionForDevices({ video: true })
    .then(() => WebRTCDevices.getDevices(['cameraType']))
    .then(devices => {
      const chosenDeviceId = devices.length ? devices[0].deviceId : null
      selectCamera(chosenDeviceId)
    })
}

WebRTCDevices.getPermissionForDevices and WebRTCDevices.getDevices both return promises.

I want to test that selectCamera prop is called with the correct argument.

If we mock return values of those functions with the externally resolvable promise we can test it as follows:

it('calls select camera prop', done => {
  let resolveDevicePermissionPromise
  const permissionPromise = new Promise(resolve => {
    resolveDevicePermissionPromise = resolve
  })
  let resolveGetDevicesPromise
  const getDevicesPromise = new Promise(resolve => {
    resolveGetDevicesPromise = () => {
      resolve([{ deviceId: '1111' }])
    }
  })
  props.selectCamera = jest.fn()
  jest.spyOn(WebRTCDevices, 'getPermissionForDevices').mockReturnValue(permissionPromise)
  jest.spyOn(WebRTCDevices, 'getDevices').mockReturnValue(getDevicesPromise)
  const { component } = renderWrapper()

  component._setDevices()
  resolveDevicePermissionPromise()
  resolveGetDevicesPromise()

  // Move our expect to the end of queue, so "thens" from `component._setDevices()` execute before
  setTimeout(() => {
    getDevicesPromise.then(() => {
      expect(props.selectCamera).toHaveBeenCalledWith('1111')
      jest.resetAllMocks()
      done()
    })
  }, 0)
})