How to mock external API calls using jest?

Viewed 609

I am working on a NodeJS app and I am having trouble understanding & mocking external API calls. Here is my code:

contactController.ts

import { APIService } from '../client/ExternalRestClient';

const url = process.env.API_URL;
const apiKey = process.env.API_KEY;
const apiSecret = process.env.API_SECRET;

const client = new APIService(url, apiKey, apiSecret);

export default class contactController{
  public async getContact(id) {
    const response = await client.getContactById(this.contactID);
    return response;
  }
}

ExternalRestClient.ts

import { RestClient } from "./RestClient";

export default class APIService extends RestClient {
  private apiKey: string;
  private apiSecret: string;

  public constructor(
    url: string,
    _apiKey: string,
    _apiSecret: string
  ) {
    super(url);
    this.apiKey = _apiKey;
    this.apiSecret = _Secret;
  }

  public async getContactById(id) {
    const data = await this.axiosClient.get(
      `${this.url}/${id}`,
      {
        headers: {
          client_id: this.apiKey,
          client_secret: this.apiSecret,
        },
      }
    );
    return data;
  }
}

RestClient.ts

import axios, { AxiosInstance, AxiosResponse } from "axios";

declare module "axios" {
  interface AxiosResponse<T = any> extends Promise<T> {}
}

export abstract class RestClient {
  protected readonly axiosClient: AxiosInstance;
  protected readonly url: string;

  constructor(url: string) {
    this.url = url;
    this.axiosClient = axios.create({
      url,
    });
    this._initializeResponseInterceptor();
  }

  private _handleResponse = ({ data }: AxiosResponse) => data;
  protected _handleError = (error: any) => Promise.reject(error);

  private _initializeResponseInterceptor = () => {
    this.axiosClient.interceptors.response.use(
      this._handleResponse,
      this._handleError
    );
  };
}

I am trying to write a test for contactController. I tried using jest.mock('axios') but it didn't work out. This is how I was doing it:

import contactController from "../src/controllers/contactController"
import axios from "axios";

jest.mock("axios");


describe("Test", () => {
    describe("Individual ID", () => {
        it("Checking information retrived", async () => {
            const controller = new contactController();

            const expected = {
                "dataResponse": "success",
                "id": "1234",
                "hasMore": false
            };

            axios.get.mockResolvedValue(expected);
            return controller.getContact("1234").then(data => expect(data).toEqual(expected));
        });
    });
});

Can someone please advice how can I write the test for this contoller? I am not able to grasp or figure out how should I proceed.

Thakns.

1 Answers

You are mocking the axios.get method, while your code is using axios.create(...).get basically.

Perhaps there is a better solution, but I would try mocking .create like this:

axios.create.mockResolvedValue({ get: () => expected })

That should mock the create method to return an instance that returns expected result upon calling .get on it.

P.S.: I didn't try it myself, so perhaps you also have to add proper methods to the mock to make sure that this snippet doesn't fail with trying to access some method on undefined:

private _initializeResponseInterceptor = () => {
    this.axiosClient.interceptors.response.use(
      this._handleResponse,
      this._handleError
    );
  };
Related