Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing api call inside useEffect using react-testing-library

Tags:

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:

const List: FC<{}> = () => {     const [data, setData] = useState<number>();     const getData = (): Promise<any> => {         return fetch('https://jsonplaceholder.typicode.com/todos/1');     };      React.useEffect(() => {         const func = async () => {             const data = await getData();             const value = await data.json();             setData(value.title);         }         func();     }, [])      return (         <div>             <div id="test">{data}</div>         </div>     ) } 

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:

it('test', async () => {     let component;     const fakeResponse = 'example text';     const mockFetch = Promise.resolve({json: () => Promise.resolve(fakeResponse)});     const mockedFetch = jest.spyOn(window, 'fetch').mockImplementationOnce(() => mockFetch as any )     await wait( async () => {         component = render(<List />);     })     const value: Element = component.container.querySelector('#test');     console.log(value.textContent);     expect(mockedFetch).toHaveBeenCalledTimes(1); })  

I would be really thankful for any suggestions.

Second Attempt

Also tried using data-testid="test" and waitForElement, but still receiving null value.

updated component deltas:

  const List: FC<{}> = () => { -     const [data, setData] = useState<number>(); +     const [data, setData] = useState<string>('test');       const getData = (): Promise<any> => {           return fetch('https://jsonplaceholder.typicode.com/todos/1');       };          React.useEffect(() => {           const func = async () => {               const data = await getData();               const value = await data.json();               setData(value.title);           }           func();       }, [])          return (           <div> -             <div id="test">{data}</div> +             <div data-testid="test" id="test">{data}</div>           </div>       )   } 

and updated test:

it('test', async () => {     const fakeResponse = 'example text';     const mockFetch = Promise.resolve({json: () => Promise.resolve(fakeResponse)});     const mockedFetch = jest.spyOn(window, 'fetch').mockImplementationOnce(() => mockFetch as any )     const { getByTestId } = render(<List />);     expect(getByTestId("test")).toHaveTextContent("test");     const resolvedValue = await waitForElement(() => getByTestId('test'));     expect(resolvedValue).toHaveTextContent("example text");     expect(mockedFetch).toHaveBeenCalledTimes(1); }) 
like image 262
hetious Avatar asked Jan 24 '20 07:01

hetious


1 Answers

Here is a working unit testing example:

index.tsx:

import React, { useState, FC } from 'react';  export const List: FC<{}> = () => {   const [data, setData] = useState<number>();   const getData = (): Promise<any> => {     return fetch('https://jsonplaceholder.typicode.com/todos/1');   };    React.useEffect(() => {     const func = async () => {       const data = await getData();       const value = await data.json();       setData(value.title);     };     func();   }, []);    return (     <div>       <div data-testid="test">{data}</div>     </div>   ); }; 

index.test.tsx:

import { List } from './'; import React from 'react'; import '@testing-library/jest-dom/extend-expect'; import { render, waitForElement } from '@testing-library/react';  describe('59892259', () => {   let originFetch;   beforeEach(() => {     originFetch = (global as any).fetch;   });   afterEach(() => {     (global as any).fetch = originFetch;   });   it('should pass', async () => {     const fakeResponse = { title: 'example text' };     const mRes = { json: jest.fn().mockResolvedValueOnce(fakeResponse) };     const mockedFetch = jest.fn().mockResolvedValueOnce(mRes as any);     (global as any).fetch = mockedFetch;     const { getByTestId } = render(<List></List>);     const div = await waitForElement(() => getByTestId('test'));     expect(div).toHaveTextContent('example text');     expect(mockedFetch).toBeCalledTimes(1);     expect(mRes.json).toBeCalledTimes(1);   }); }); 

unit test result:

 PASS  src/stackoverflow/59892259/index.test.tsx (9.816s)   59892259     ✓ should pass (63ms)  -----------|----------|----------|----------|----------|-------------------| File       |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s | -----------|----------|----------|----------|----------|-------------------| All files  |      100 |      100 |      100 |      100 |                   |  index.tsx |      100 |      100 |      100 |      100 |                   | -----------|----------|----------|----------|----------|-------------------| Test Suites: 1 passed, 1 total Tests:       1 passed, 1 total Snapshots:   0 total Time:        11.73s, estimated 13s 
like image 133
slideshowp2 Avatar answered Sep 27 '22 21:09

slideshowp2