No se pueden probar los métodos de publicación con Jest debido a un error, no se puede leer la simulación de implementación indefinida

9

Tengo un servicio de API donde tengo diferentes métodos para hacer llamadas a las API. He probado con éxito todas las solicitudes GET pero tengo problemas para probar las solicitudes POST.

Este es el 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
    );
  };
};

Así es como estoy probando todo lo relacionado con los GET:

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');
    });
  });
})

Pensé que solo cambiando todas las instancias de ApiClient.geta ApiClient.postfuncionará para probar las solicitudes POST. Pero cuando intento hacer eso dice eso can not read mockImplementation of undefined. Traté de cambiar los métodos en las pruebas para usar el postparámetro para sobrescribir el parámetro, method = 'get'pero no tengo éxito, obtengo este error

TypeError: apiClient_1.default.post no es una función

¿Alguna idea?

Reaccionando
fuente
Una de las razones sería que ApiClientno tiene método post.
Tomás
Hola, @Tomas mira esta línea -> return ApiClient.post(url, data, config) .then(res => callback(normalizeCallback(res.data))).catch(error => someHandler(error));y funciona correctamente cuando intento hacer una solicitud de publicación. Quiero decir que tengo como 17 solicitudes de publicaciones funcionando como deben. Entonces, ¿por qué en las pruebas no funcionan entonces?
Reaccionando el
@ Reaccionar Comparta el ejemplo de prueba de unidad "post"
Oron Ben-David
@ OronBen-David Mencioné en la pregunta que intenté exactamente lo mismo que en la getprueba, pero cambié todas las instancias gety configuré en su postlugar.
Reaccionando el
Entiendo, pero será más claro mencionar el código que no funciona
Oron Ben-David

Respuestas:

5

He investigado tu problema. En primer lugar, quiero decir que su código tiene un par de problemas, como la devolución de llamada que no definió, la definición poco clara, ApiClientetc.

Entonces, creé un ejemplo de Repl para reproducir su problema en el que simplifiqué un poco su código pero todos los elementos principales están ahí.

Por favor, eche un vistazo https://repl.it/@SergeyMell/Some-Jesting

Funciona con éxito para ambos gety postmétodos sin problemas. Estos son los puntos principales en los que debe prestar atención:

  1. Utilizando axios como ApiClient. (No estaba claro en su pregunta, así que asumí que es así)
    const ApiClient = require('axios');
  2. Poner simulacros de bromas axios(Supongamos que haces lo mismo)
    jest.mock('axios');
  3. Poner simulacros a ambos gety postsolicitudes de manera similar (igual a tu manera)

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

Por lo tanto, verifique mi ejemplo, verifique las diferencias con su código y avíseme sobre algunos detalles adicionales que pueda necesitar.

Sergey Mell
fuente
0

Intenta cambiar mockImplementationamockImplementationOnce

Oron Ben-David
fuente