React useEffect hook jest unit test não confirma que a função prop é chamada

Sep 21 2020

Estou tentando escrever um teste de unidade para verificar se uma função (passada como um prop) é chamada se outro prop for verdadeiro no gancho useEffect. O teste de unidade falha ao confirmar que a função (simulada) é chamada no gancho useEffect, mas pode confirmar que uma função que é spyOn de um módulo importado é chamada. Alguém sabe qual pode ser o problema? Obrigado!

import {getUser} from './Auth';
export function ComponentA({
  shouldRetryExport,
  someReduxDispatchFunc,
}) {

  const handleExport = useCallback(async () => {
    const user = await getUser();
    someReduxDispatchFunc();
  }, []);

  useEffect(() => {
    if (shouldRetryExport) {
      handleExport();
    }
  }, [shouldRetryExport]);

  return (<SomeComponent />)
});

Teste de unidade:

import * as Auth from './Auth';

it('should call someReduxDispatchFunc if getUserAuthorization is true', () => {
  const getAuthUserSpy = jest.spyOn(Auth, 'getUser');
  const someReduxDispatchFuncMock = jest.fn();
  const props = {
    someReduxDispatchFunc: someReduxDispatchFuncMock,
    shouldRetryExportWithUserReAuthorization: true,
  };
  enzyme.mount(<ComponentA {...props} />);

  expect(getAuthUserSpy).toHaveBeenCalled(); // works -> returns true
  expect(someReduxDispatchFuncMock).toHaveBeenCalled(); // doesn't work -> returns false
});

Parece que tem algo a ver com useCallback com useEffect. Se eu remover o useCallback e adicionar a lógica dentro de useEffect, ele pode capturar someReduxDispatchFuncMockfoi chamado.

Respostas

tmhao2005 Sep 21 2020 at 21:41

Não acho que o problema seja de useCallbackou useEffect. O problema é mais provável que seu retorno de chamada tenha uma função assíncrona, o que significa que precisa de tempo para ser resolvido.

Para isso, você deve fazer seu teste assíncrono e esperar que seja resolvido da seguinte forma:

it('should call someReduxDispatchFunc if getUserAuthorization is true', async () => {
  const getAuthUserSpy = jest.spyOn(Auth, 'getUser');
  const someReduxDispatchFuncMock = jest.fn();
  const props = {
    someReduxDispatchFunc: someReduxDispatchFuncMock,
    shouldRetryExport: true,
  };
  enzyme.mount(<ComponentA {...props} />);

  // wait for getting resolved
  await Promise.resolve();

  expect(getAuthUserSpy).toHaveBeenCalled();
  expect(someReduxDispatchFuncMock).toHaveBeenCalled();
});