kentcdodds/testing-react-apps

Mocking Browser APIs and Modules Inconsistency

tylerpashigian opened this issue · 3 comments

In the video solution, the test execution for this module passed despite the error (and correctly updated the UI when running screen.debug()) before wrapping the execution of the resolve and promise in act(), however my test was actually failing here (and the screen.debug() still showed the loading spinner) until wrapping those actions in act(). Just a not in case you wanted to update the comments/video because I was confused where my inconsistencies were coming from. I spent quite a bit of time trying to find the issue and all I had to do was add act(), though I'm still not sure why they behave differently.

Hey Tyler,

I'll look at this more in my next Office Hours, but if you could please give more details that would be helpful. I'm not 100% certain I understand what you're saying is wrong.

Hey Kent,

Sure. In the video you said the DOM gets updated despite not having the resolve and promise wrapped in the act() function and there was only the warning in the test execution output and the test would still pass. My test failed before adding the act() function. I'll share specific code below (with unrelated parts of the test commented out)

This test code:

test('displays the users current location', async () => {
  const fakePosition = {
    coords: {
      latitude: 30,
      longitude: 43
    }
  }

  const {promise, resolve} = deferred()

  window.navigator.geolocation.getCurrentPosition.mockImplementation(
    callback => {
      promise.then(() => callback(fakePosition))
    }
  )

  render(<Location />)
  expect(screen.getByLabelText(/loading/i)).toBeInTheDocument()
  
  // await act(async () => {
    resolve()
    await promise
  // })
  screen.debug()
  expect(screen.queryByLabelText(/loading/i)).not.toBeInTheDocument()
  // expect(screen.getByText(/latitude/i)).toHaveTextContent(`Latitude: ${fakePosition.coords.latitude}`)
  // expect(screen.getByText(/longitude/i)).toHaveTextContent(
  //   `Longitude: ${fakePosition.coords.longitude}`,
  // )
})

Outputs this DOM from screen.debug():

<body>
      <div>
        <div
          aria-label="loading..."
          class="lds-ripple"
        >
          <div />
          <div />
        </div>
      </div>
    </body>

And fails with this error:

expect(element).not.toBeInTheDocument()

    expected document not to contain element, found <div aria-label="loading..." class="lds-ripple"><div /><div /></div> instead

However, if I uncomment the act() function, the test passes (and obviously screen.debug() outputs the correct DOM and the act function error also goes away)

I answered this during office hours today. At around 20 minutes or so: https://www.youtube.com/watch?v=iTy6aJqBvOQ