title: How can I get a test to wait for an async React component to render before trying an assertion?
body: <p>I'm trying to test that a component that gets its data from an API loads as expected using <code>react-router-dom</code>. It seems like the test needs to wait for the component's Promise to resolve, but I can't seem to find an approach that works.</p>
  <p>Here's the really simple <code>App</code> I'm testing.</p>
  <pre class="lang-js prettyprint-override"><code>class App extends React.Component {
    render() {
      return (
        &lt;div className=&quot;container&quot;&gt;
          &lt;Switch &gt;
            &lt;Route path='/object/:id'&gt;
              &lt;ObjectDetail /&gt;
            &lt;/Route&gt;
            &lt;Route path='/'&gt;
              &lt;Table /&gt;
            &lt;/Route&gt;
          &lt;/Switch&gt;
        &lt;/div&gt;
      )
    }
  }
  
  export default App
  </code></pre>
  <p>And here's the <code>objectDetail</code> component (which uses a service to handle the API call):</p>
  <pre class="lang-js prettyprint-override"><code>class ObjectDetail extends React.Component {
    state = {
      data: {},
      dataResolved: false,
    }
  
    componentDidMount() {
      const id  = this.props.match.params.id;
  
      objectService.getObjectDetail(id).then((result) =&gt; {
        this.setState({
          data: result,
          dataResolved: true,
        });
      });
  
      document.title = 'Object Detail';
    }
  
    render() {
      const { data, dataResolved } = this.state;
  
      if(dataResolved) {
        return (
          &lt;div&gt;
            &lt;h1&gt;
              Object Detail
            &lt;/h1&gt;
          
          // ... etc.
        );
      } else {
        return null;
      }
    }
  }
  
  export default withRouter(ObjectDetail)
  </code></pre>
  <p>The <code>Table</code> component renders a table with objects along with a details link, and the <code>ObjectDetail</code> component renders a heading, so I'm trying to test that the link navigation works as expected, like so:</p>
  <pre class="lang-js prettyprint-override"><code>test('navigates to details when you click the details link', async () =&gt; {
    render(
      &lt;MemoryRouter&gt;
        &lt;App /&gt;
      &lt;/MemoryRouter&gt;
    );
    await wait();
  
    const rows = within(screen.getByRole('rowgroup', {name: 'Table Body'})).getAllByRole('row');
  
    const link = within(rows[0]).getByRole('link')
  
    fireEvent.click(link)
  
    expect(screen.getByRole('heading', {name: 'Object Detail'})).toBeInTheDocument();
  });
  </code></pre>
  <p>Everything works as I'd expect when I run the app and test manually as well as using Cypress for integration testing, but the test fails because it only renders this (falling back to <code>else { return null; }</code>):</p>
  <pre class="lang-html prettyprint-override"><code>&lt;body&gt;
    &lt;div&gt;
      &lt;div
        class=&quot;container&quot;
      /&gt;
    &lt;/div&gt;
  &lt;/body&gt;
  </code></pre>
  <p>I've tried adding another <code>await wait();</code> between the <code>.click()</code> and <code>expect</code> with the same result, and I tried what was proposed in <a href="https://stackoverflow.com/a/51045733/">this answer to a similar question</a> without success.</p>
  <p>I've tried some other approaches that seem to force the test to wait naively (like using <code>setTimeout</code>) and <code>await waitForElement(() =&gt; screen.getByRole('heading'))</code>. Interestingly enough, those cause the test to error out with a <code>Error: Request failed with status code 404</code>, which is even more baffling.</p>
  <p>How can I write a test that will render the routed component correctly?</p>