Тестирование fetch.catch в пользовательском хуке - PullRequest
1 голос
/ 29 марта 2020

У меня есть этот пользовательский хук:

import React from 'react';
import { useMessageError } from 'components/Message/UseMessage';

export interface Country {
  code: string;
  name: string;
}

export default function useCountry(): Array<Country> {
  const [countries, setCountries] = React.useState<Country[]>([]);
  const { showErrorMessage } = useMessageError();

  React.useEffect(() => {
    fetch('/api/countries', {
      method: 'GET',
    })
      .then(data => data.json())
      .then(function(data) {
        // ..
      })
      .catch(() => showErrorMessage());
  }, []);

  return countries;
}

Я хочу протестировать обнаружение ошибки, если будет неправильный ответ. При этом должно появиться сообщение об ошибке благодаря showErrorMessage(). И у меня есть этот тест:

const showErrorMessage = jest.fn();

jest.mock('components/Message/UseMessage', () => ({
  useMessageError: () => ({
    showErrorMessage: showErrorMessage,
  }),
}));

import useCountry from 'components/Country/useCountry';
import { renderHook } from '@testing-library/react-hooks';
import { enableFetchMocks } from 'jest-fetch-mock';
enableFetchMocks();

describe('The useCountry hook', () => {
  it('should show error message', async () => {
    jest.spyOn(global, 'fetch').mockImplementation(() =>
      Promise.resolve({
        json: () => Promise.reject(),
      } as Response),
    );

    const { result, waitForNextUpdate } = renderHook(() => useCountry());
    await waitForNextUpdate();

    expect(fetch).toHaveBeenCalled();
    expect(showErrorMessage).toHaveBeenCalled();
    expect(result.current).toEqual([]);
  });
});

Но с этим я получаю ошибку:

Тайм-аут - Asyn c обратный вызов не был вызван в течение 5000 мс время ожидания, указанное в jest.setTimeout.Timeout - обратный вызов Asyn c не был вызван в течение времени ожидания 5000 мс, указанного в jest.setTimeout.Error

Что я здесь не так делаю? Я предполагаю, что это как-то связано с await waitForNextUpdate();, но я действительно не знаю наверняка и как с этим справиться.

1 Ответ

1 голос
/ 30 марта 2020

waitForNextUpdate() ожидает следующего обновления, но ваш хук не вызывает его, так как он вызывает только howErrorMessage(). Взгляните на эту песочницу

. В качестве простого решения можно добавить что-то, что вызывает обновление:

  React.useEffect(() => {
    fetch('/api/countries', {
      method: 'GET',
    })
      .then(data => data.json())
      .then(function(data) {
        // ..
      })
      .catch(() => { 
        showErrorMessage();
        // trigger update in any suitable way, for example:
        setCountries([]); 
      });
  }, []);

Но может быть лучше провести его рефакторинг в некоторых путь. Например, вы можете использовать отдельный хук и состояние для ошибок:

export default function useCountry(): Array<Country> {
  const [countries, setCountries] = React.useState<Country[]>([]);
  const [error, setError] = React.useState(null);
  const { showErrorMessage } = useMessageError();

  React.useEffect(() => {
    fetch('/api/countries', {
      method: 'GET',
    })
      .then(data => data.json())
      .then(function(data) {
        // ..
      })
      .catch(() => setError(true));
  }, []);

  React.useEffect(() => {
    if (error) {
      showErrorMessage()
    }
  }, [error]);

  return countries;
}
...