Não é possível testar os métodos de postagem com o Jest devido a erro não pode ler mockImplementation of undefined

9

Eu tenho um serviço de API onde tenho métodos diferentes para fazer chamadas para as APIs. Testei com êxito todas as solicitações GET, mas estou tendo problemas para testar as solicitações POST.

Este é o método:

export default class ApiService {
  static makeApiCall = <T>(
    url: string,
    oneCb: <T>(d: Data) => T,
    secondCb: (d: T) => void,
    errorCb?: (a: ErrorModel) => void,
    method = 'get',
    data = {},
  ): Promise<void> => {
    const config: AxiosRequestConfig = {};
    if (method === 'post') {
      config.headers = header;
      return ApiClient.post(url, data, config)
        .then(res => callback(normalizeCallback(res.data))).catch(error => someHandler(error));            
    } else {
      return ApiClient.get(url)
        .then(res => callback(normalizeCallback(res.data))).catch(error => someHandler(error));
    }
  };

  // ONLY ONE POST METHOD TO MAKE IT MORE CLEAR
  static someArchiveMethod = (
    callback: (a: SuccessModel) => void,
    errorCallback: (error: ErrorModel) => void,
    cardId: string
  ): Promise<void> => {
    return ApiService.makeApiCall<SuccessfulResponse>(
      'appreciationCard/archive',
      Normalizer.successfulResponse,
      callback,
      errorCallback,
      'post',
      { cardId }
    );
  };

  // HERE BELOW THE GET METHODS
  static getPeople = (cb: (a: PeopleModel[]) => void, page?: number, limit?: number): Promise<void> => {
    const queryDetails = { page, limit };
    return ApiService.makeApiCall<PeopleModel[]>(
      `people?${toQueryString(queryDetails)}`,
      Normalizer.normalizePeople,
      callback
    );
  };
};

É assim que estou testando tudo relacionado aos GETs:

describe('apiService', () => {
  beforeAll(() => {
    expect(ApiClient.defaults.headers.common.Authorization).toBe('Bearer test token');
    // @ts-ignore
    ApiClient.get.mockImplementation((url: string) => {
      return Promise.resolve({ data: mockData });
    });
  });

  it('should call api client method', () => {
    ApiService.makeApiCall(
      'testUrl',
      data => data,
      res => res,
      err => err,
      'get'
    );

    expect(ApiClient.get).toBeCalledTimes(1);
    expect(ApiClient.get).toBeCalledWith('testUrl');
  });

  it('should call callbacks consequently', done => {
    ApiService.makeApiCall('testUrl', firstCallback, secondCallback).then(() => {
      expect(firstCallback).toBeCalledTimes(1);
      expect(firstCallback).toBeCalledWith(mockData);
      expect(secondCallback).toBeCalledTimes(1);
      expect(secondCallback).toBeCalledWith(firstCallback(mockData));
      done();
    });
  });
});

describe('api service error flow', () => {
  beforeAll(() => {
    // @ts-ignore
    ApiClient.get.mockImplementation((url: string) => {
      console.log('error result');
      return Promise.reject(mockError);
    });
  });

  it('should handle error', done => {
    console.error = jest.fn();

    const firstCallback = jest.fn((data: any) => data);
    const secondCallback = jest.fn((data: any) => data);

    ApiService.makeApiCall('testUrl', firstCallback, secondCallback).then(() => {
      expect(firstCallback).toBeCalledTimes(0);
      expect(secondCallback).toBeCalledTimes(0);
      expect(console.error).toBeCalledTimes(1);
      expect(console.error).toBeCalledWith('ApiClient testUrl', mockError);
      done();
    });
  });
});

describe('apiService methods', () => {
  beforeAll(() => {
    ApiClient.get.mockImplementation((url: string) => {
      expect(ApiClient.defaults.headers.common.Authorization).toBe('Bearer test token');

      return Promise.resolve({ data: mockData });
    });
  });

  it('getPeople method call with one param', () => {
    ApiService.getPeople(jest.fn(), 1, 1).then(() => {
      expect(ApiClient.get).toBeCalledWith('people?page=1&limit=1');
    });
  });
})

Pensei que só alterando todos os casos de ApiClient.getque ApiClient.postele vai trabalhar para testar as solicitações POST. Mas quando eu tento fazer isso, diz isso can not read mockImplementation of undefined. Tentei alterar os métodos nos testes para usar o postparâmetro, a fim de sobrescrevê-lo, method = 'get'mas não tenho sucesso, recebo este erro

TypeError: apiClient_1.default.post não é uma função

Alguma ideia?

Reagindo
fonte
Um dos motivos seria que ApiClientnão possui método post.
Tomas
Olá, o @Tomas olha para esta linha -> return ApiClient.post(url, data, config) .then(res => callback(normalizeCallback(res.data))).catch(error => someHandler(error));e funciona corretamente quando tento fazer uma solicitação de postagem. Quero dizer, tenho 17 pedidos de posts funcionando como devem. Então, por que nos testes não funcionam então?
Reagindo em
@Reacting Compartilhe o exemplo "post" do teste de unidade
Oron Ben-David
@ OronBen-David Mencionei na pergunta que tentei exatamente o mesmo que no getteste, mas mudei todas as instâncias gete configurei post.
Reagindo em
Eu entendo, mas será mais claro mencionar o código que não está funcionando
Oron Ben-David

Respostas:

5

Eu investiguei seu problema. Antes de tudo, quero dizer que seu código tem alguns problemas, como chamar retorno que você não definiu, definição pouco clara ApiClientetc.

Por isso, criei um exemplo de Repl para reproduzir seu problema no qual simplifiquei um pouco o código, mas todos os elementos principais estão lá.

Por favor, dê uma olhada https://repl.it/@SergeyMell/Some-Jesting

Ele funciona com sucesso para ambos gete postmétodos sem problemas. Aqui estão os principais pontos que você deve prestar atenção:

  1. Usando axioscomo ApiClient. (Não ficou claro em sua pergunta, então eu assumi que sim)
    const ApiClient = require('axios');
  2. Ativando zombarias axios(suponha que você faça o mesmo)
    jest.mock('axios');
  3. Colocando zombarias para ambos gete postsolicitações de maneira semelhante (igual à sua maneira)

    ApiClient.get.mockImplementation((url) => {
      return Promise.resolve({ data: mockData });
    });
    
    ApiClient.post.mockImplementation((url) => {
      return Promise.resolve({ data: mockData });
    });

Portanto, verifique meu exemplo, verifique as diferenças com seu código e me informe sobre algumas informações adicionais que você possa precisar.

Sergey Mell
fonte
0

Por favor, tente mudar mockImplementationparamockImplementationOnce

Oron Ben-David
fonte