简体   繁体   中英

How to mock multiple promise .then in react hooks and check for state set in one .then

The question could be seen as similar to this one but is not working really the same way as that one is checking for a function to be called while im looking for a state to change.

The code i have is this one (headers and body are not really important in this case):

const useGetToken = () => {
    const [token, setToken] = useState();
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState();

    const fetchToken = useCallback(() => {
        setLoading(true);

        fetch('http://localhost.something', {
            headers,
            body,
        })
            .then((response) => {
                response.json();
            })
            .then((response) => {
                setToken(response.access_token);
            })
            .catch((e) => {
                setError(e);
            })
            .finally(() => {
                setLoading(false);
            });
    }, []);

    return { fetchToken, token, error, loading };
};

what I am trying to find is a way to test that the output I have is the correct one in case of success and in case of error.

Seems like I can mock until the first.then but then i dont know how to mock the second one.

import { renderHook, act } from '@testing-library/react-hooks';

describe('useGetToken', () => {
  it('should fetch and return a token', () => {
    global.fetch = jest.fn().mockImplementation(() =>
      Promise.resolve({
        json: () => ({ access_token: 'aToken' }),
      }),
    );

    const { result } = renderHook(() => useGetToken());

    // also how to check for the fetchToken function to equal to itself i dont know how to do 
    // or maybe i can check if it is just a function
    expect(result.current).toEqual({ token: 'aToken', loading: false, error: false });
  });  
});

managed a way to fix it changing with async await and the correct act. also changed the double.then in the file to this

.then((response) => {
   const parsedResponse = response.json();
   setToken(parsedResponse.access_token);
})

cause i didnt need two

import { renderHook, act } from '@testing-library/react-hooks';
import useGetToken from '../useGetVfsToken';

describe('useGetToken', () => {
  it('should fetch when fetchToken is called', async () => {
    global.fetch = jest.fn().mockImplementation(() =>
      Promise.resolve({
        json: () => ({ access_token: 'aToken123' }),
      }),
    );

    const { result } = renderHook(() => useGetToken());

    expect(window.fetch).not.toHaveBeenCalled();

    await act(async () => {
      result.current.fetchToken();
    });

    expect(window.fetch).toHaveBeenCalledTimes(1);
    expect(result.current.token).toEqual('aToken123');
    expect(result.current.loading).toEqual(false);
    expect(result.current.error).toBeUndefined();
  });

  it('should have an error', async () => {
    const error = 'an error text';

    global.fetch = jest.fn().mockImplementation(() => Promise.reject(error));

    const { result } = renderHook(() => useGetToken());

    await act(async () => {
      result.current.fetchToken();
    });

    expect(result.current.error).toEqual(error);
    expect(result.current.loading).toEqual(false);
  });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM