Post-Methoden können aufgrund eines Fehlers nicht mit Jest getestet werden. MockImplementation of undefined kann nicht gelesen werden

9

Ich habe einen API-Dienst, bei dem ich verschiedene Methoden habe, um die APIs aufzurufen. Ich habe alle GET-Anforderungen erfolgreich getestet, habe jedoch Probleme beim Testen der POST-Anforderungen.

Dies ist die Methode:

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

So teste ich alles, was mit den GETs zu tun hat:

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

Ich dachte , dass nur durch alle Instanzen zu ändern , ApiClient.getum ApiClient.postes zu arbeiten , um die POST - Anfragen zu testen. Aber wenn ich das versuche, sagt es das can not read mockImplementation of undefined. Ich habe versucht, die Methoden in den Tests so zu poständern , dass der Parameter verwendet wird, um den Parameter zu überschreiben, method = 'get'aber ich habe keinen Erfolg. Ich erhalte diesen Fehler

TypeError: apiClient_1.default.post ist keine Funktion

Irgendwelche Gedanken?

Reagieren
quelle
Einer der Gründe wäre, dass ApiClientes keine Methode gibt post.
Tomas
Hallo, @Tomas, schau dir diese Zeile an -> return ApiClient.post(url, data, config) .then(res => callback(normalizeCallback(res.data))).catch(error => someHandler(error));und sie funktioniert einwandfrei, wenn ich versuche, eine Post-Anfrage zu stellen. Ich meine, ich habe 17 Posts-Anfragen, die so funktionieren, wie sie müssen. Warum also in den Tests dann nicht funktionieren?
Reaktion
@Reacting Bitte teilen Sie das Beispiel für einen "Post" -Einheitentest
Oron Ben-David,
@ OronBen-David Ich erwähnte in der Frage, dass ich genau das gleiche wie im getTest versucht habe, aber ich habe stattdessen alle Instanzen von getund gesetzt post.
Reaktion
Ich verstehe, aber es wird klarer sein, den Code zu erwähnen, der nicht funktioniert
Oron Ben-David

Antworten:

5

Ich habe dein Problem untersucht. Zunächst möchte ich Ihnen mitteilen, dass Ihr Code einige Probleme aufweist, z. B. das Aufrufen eines Rückrufs, den Sie nicht definiert haben, eine unklare Definition ApiClientusw.

Also habe ich ein Repl-Beispiel erstellt, um Ihr Problem zu reproduzieren, in dem ich Ihren Code ein wenig vereinfacht habe, aber alle Hauptelemente vorhanden sind.

Bitte werfen Sie einen Blick auf https://repl.it/@SergeyMell/Some-Jesting

Es funktioniert erfolgreich für beide getund postMethoden ohne Probleme. Hier sind die wichtigsten Punkte, auf die Sie achten sollten:

  1. Verwenden axiosals ApiClient. (Es war nicht klar aus Ihrer Frage, also nahm ich an, dass es so ist)
    const ApiClient = require('axios');
  2. Scherz verspotten axios(Angenommen, Sie tun dasselbe)
    jest.mock('axios');
  3. Verspotten von beiden getund postAnfragen auf ähnliche Weise (wie bei Ihnen)

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

Überprüfen Sie daher bitte mein Beispiel, überprüfen Sie die Unterschiede zu Ihrem Code und teilen Sie mir einige zusätzliche Detalisierungen mit, die Sie möglicherweise benötigen.

Sergey Mell
quelle
0

Bitte versuchen Sie es zu ändern , mockImplementationummockImplementationOnce

Oron Ben-David
quelle