title: Testing api call inside useEffect using react-testing-library
body: <p>I want to test api call and data returned which should be displayed inside my functional component. I created List component which performs api call. I would like the returned data to be displayed in the component and I use the useState hook for this. Component looks like this:</p>
  <pre class="lang-js prettyprint-override"><code>const List: FC&lt;{}&gt; = () =&gt; {
      const [data, setData] = useState&lt;number&gt;();
      const getData = (): Promise&lt;any&gt; =&gt; {
          return fetch('https://jsonplaceholder.typicode.com/todos/1');
      };
  
      React.useEffect(() =&gt; {
          const func = async () =&gt; {
              const data = await getData();
              const value = await data.json();
              setData(value.title);
          }
          func();
      }, [])
  
      return (
          &lt;div&gt;
              &lt;div id=&quot;test&quot;&gt;{data}&lt;/div&gt;
          &lt;/div&gt;
      )
  }
  </code></pre>
  <p>I wrote one test in which I mocked the fetch method. I check if the fetch method has been called and it actually happens. Unfortunately, I don't know how I could test the value returned from response. When I try console.log I just get null and I'd like to get 'example text'. My guess is that I have to wait for this value returned from Promise. Unfortunately, despite trying with methods act and wait, I don't know how to achieve it. Here is my test:</p>
  <pre class="lang-js prettyprint-override"><code>it('test', async () =&gt; {
      let component;
      const fakeResponse = 'example text';
      const mockFetch = Promise.resolve({json: () =&gt; Promise.resolve(fakeResponse)});
      const mockedFetch = jest.spyOn(window, 'fetch').mockImplementationOnce(() =&gt; mockFetch as any )
      await wait( async () =&gt; {
          component = render(&lt;List /&gt;);
      })
      const value: Element = component.container.querySelector('#test');
      console.log(value.textContent);
      expect(mockedFetch).toHaveBeenCalledTimes(1);
  })
  
  </code></pre>
  <p>I would be really thankful for any suggestions.</p>
  <h3>Second Attempt</h3>
  <p>Also tried using <code>data-testid=&quot;test&quot;</code> and <code>waitForElement</code>, but still receiving null value.</p>
  <p>updated component deltas:</p>
  <pre><code>  const List: FC&lt;{}&gt; = () =&gt; {
  -     const [data, setData] = useState&lt;number&gt;();
  +     const [data, setData] = useState&lt;string&gt;('test');
        const getData = (): Promise&lt;any&gt; =&gt; {
            return fetch('https://jsonplaceholder.typicode.com/todos/1');
        };
    
        React.useEffect(() =&gt; {
            const func = async () =&gt; {
                const data = await getData();
                const value = await data.json();
                setData(value.title);
            }
            func();
        }, [])
    
        return (
            &lt;div&gt;
  -             &lt;div id=&quot;test&quot;&gt;{data}&lt;/div&gt;
  +             &lt;div data-testid=&quot;test&quot; id=&quot;test&quot;&gt;{data}&lt;/div&gt;
            &lt;/div&gt;
        )
    }
  </code></pre>
  <p>and updated test:</p>
  <pre class="lang-js prettyprint-override"><code>it('test', async () =&gt; {
      const fakeResponse = 'example text';
      const mockFetch = Promise.resolve({json: () =&gt; Promise.resolve(fakeResponse)});
      const mockedFetch = jest.spyOn(window, 'fetch').mockImplementationOnce(() =&gt; mockFetch as any )
      const { getByTestId } = render(&lt;List /&gt;);
      expect(getByTestId(&quot;test&quot;)).toHaveTextContent(&quot;test&quot;);
      const resolvedValue = await waitForElement(() =&gt; getByTestId('test'));
      expect(resolvedValue).toHaveTextContent(&quot;example text&quot;);
      expect(mockedFetch).toHaveBeenCalledTimes(1);
  })
  </code></pre>