Home > Net >  How to mock an internal axios instance of a class you're testing
How to mock an internal axios instance of a class you're testing

Time:10-05

I am using Jest to test a client class, which internally uses axios. It exposes methods that reach out to an API and call its endpoints. The client is initialized in the constructor of the class, and expects an API key. Here is an example:

export class ExampleClient {
  private client: AxiosInstance;
  private defaultCountry: Countries;
  private defaultLanguage: Languages;

  constructor(config: Config) {
    const { apiKey, defaultCountry, defaultLanguage } = config;

    this.defaultCountry = defaultCountry || Countries.USA;
    this.defaultLanguage = defaultLanguage || Languages.English;
    this.client = axios.create({
      baseURL: 'https://example-api.com',
      headers: {
        'Content-Type': 'application/json',
        'X-Api-Key': apiKey,
      },
    });
  }
}

Now, I don't want to use a real API key here, but I'd still like to be able to check if the key gets attached to the headers correctly, and also see if the endpoints are properly called. I would also like to test the mapping, as the client also maps the endpoint responses to more readable objects.

I apologize if the question has been resolved in another thread, but I couldn't seem to find anything.

CodePudding user response:

You can mock "axios" with jest mocking. You can test if has received headers and if they are setted.

An example:

// axios.test.ts

import { Test } from "./Test";

jest.mock("axios");

describe("Axios", () => {
  it("test axios", () => {
    let headerExpected: { content: string } = { content: "nothing" };

    // implementation of axios.create
    const mockAxios = jest.requireMock("axios");
    mockAxios.default.create = jest
      .fn()
      .mockImplementation((props: { headers: { content: string } }) => {
        headerExpected = props.headers;
      });

    const test = new Test();
    test.test1({ content: "test" });

    expect(headerExpected.content).toEqual("test");
  });

});

// Test.ts

import * as axios from "axios";

export class Test {
  private client!: axios.AxiosInstance | undefined;

  test1(header: { content: string }): void {
    this.client = axios.default.create({
      headers: header,
    });
  }
}

But, maybe, this type of test dont give you enough value.

Regards!

CodePudding user response:

I snooped around and found this package called 'axios-mock-adapter' - link here. After that I passed the private client object to the adapter by accessing it with square braces. This gave me the freedom to inspect the history of requests that went through the adapter, and also to configure the responses. Here is an example:

import MockAdapter from 'axios-mock-adapter';

it('should set API key in request header', async () => {
    const sdk = new ExampleClient({ apiKey: 'test_api_key' });
    const adapter = new MockAdapter(sdk['client']);
    adapter.onGet('/search').reply(200, { results: [], total_results: 0 });

    await sdk.search('test_value');
    const lastRequest = adapter.history.get[0];

    expect(lastRequest.headers).toBeDefined();
    expect(lastRequest.headers?.['X-Api-Key']).toEqual('test_api_key');
  });

Hope this helps someone!

  • Related