Simple ways to simulate Axios requests in tests

My implementation includes the use of axios with a custom HttpClient class

export default class HttpClient {
  constructor(baseUrl: string) {
    const axiosInstance = axios.create({
      validateStatus(status: number) {
        return status === 200 || status === 201;
      },
    });

    axiosInstance.interceptors.request.use((config) => {
      if (AuthUtil.getAuthHeader()) config.headers = AuthUtil.getAuthHeader();
      return config;
    });

    return new Proxy(this, {
      get(_, prop) {
        return (url: string, ...args: any) => {
          url = baseUrl + url;
          return Reflect.get(axiosInstance, prop)(url, ...args);
        };
      },
    });
  }

  get<T = any, R = AxiosResponse<T>>(_url: string, _config?: AxiosRequestConfig): Promise<R> {
    return Promise.resolve(null);
  }
.....
}

This snippet demonstrates how the HttpClient class is utilized in a service:

export default class UserManagementServiceImpl implements UserManagementService {
  private client = new HttpClient('/api/user');

  async getUser(): Promise<User> {
    const res = await this.client.get('/user');
    return res.data;
  }

During testing, I encountered an error that prevented the successful invocation of the service method. Here is my test scenario:

describe('User actions', () => {
  test('creates GET_TERMS_SUCCESS', async () => {
    jest.mock('axios', () => {
      return {
        create: jest.fn().mockReturnValue({
          interceptors: {
            request: { use: jest.fn(), eject: jest.fn() },
            response: { use: jest.fn(), eject: jest.fn() },
          },

          get: jest.fn().mockReturnValue({ data: user }),
        }),
      };
    });

    const user = await userService.getUser();
  });
});

// ERROR:
/*
Error: Error: connect ECONNREFUSED 127.0.0.1:80
*/

I have explored various solutions from community forums without success. Any guidance on resolving this issue would be greatly appreciated.

Answer №1

Latest Update [2022-May-18]

After some trial and error, I have finally cracked the code on how to seamlessly integrate axios-mock-adapter for mocking AxiosInstances created using axios.create().

During testing, we set up a local instance of AxiosStatic by returning it as the value of axios.create. This allows us to mock axios using axios-mock-adapter in the usual way.

import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import UserManagementServiceImpl from '../../../services/impl/UserManagementServiceImpl';

jest.mock('axios', () => {
  return {
    ...(jest.requireActual('axios') as object),
    create: jest.fn().mockReturnValue(jest.requireActual('axios')),
  };
});

const mockAdapter = new MockAdapter(axios);

test('hello', async () => {
  const userService = new UserManagementServiceImpl();

  mockAdapter.onGet('/api/user/user').reply(200, { name: 'name' });
  const r = (await userService.getUser()) as any;
  expect(r.name).toBe('name');
});

Past Answer

It seems that jest.mock() needs to be placed outside the test life cycle methods.

jest.mock('axios', () => {
  return {
    create: jest.fn().mockReturnValue({
      interceptors: {
        request: { use: jest.fn(), eject: jest.fn() },
        response: { use: jest.fn(), eject: jest.fn() },
      },

      get: jest.fn().mockReturnValue({ data: user }),
    }),
  };
});

describe('User actions', () => {
  test('test', async () => {
    const user = await userService.getUser();
  });
});

You can also delay mocking and defining functions as needed

jest.mock('axios')

describe('User actions', () => {
  test('test', async () => {
    (axios.create as jest.Mock<any, any>).mockReturnValue({
      interceptors: {
        request: { use: jest.fn(), eject: jest.fn() },
        response: { use: jest.fn(), eject: jest.fn() },
      },

      get: jest.fn().mockReturnValue({ data: { name: 'name' } }),
    });

    const user = await userService.getUser();
  });
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Enhance the Next.js higher-order authentication component by including extra data in the return

Below is the code snippet I am working with: export const requireAuth = (gssp: GetServerSideProps) => { return async (ctx: GetServerSidePropsContext) => { const { req } = ctx; let session = null; if (req?.headers?.cookie) { sessi ...

Establish an enumeration using universally recognized identifiers

I have a JavaScript function that requires a numerical input, as well as some predefined constants at the top level: var FOO = 1; var BAR = 2; The function should only be called using one of these constants. To ensure type safety in TypeScript, I am att ...

Can I integrate @types/pkg into my custom library to automatically have types included?

Imagine I am creating a library that utilizes types from the Definitely Typed repository (such as @types/pkg). Would it be feasible for my package to automatically include these types when installed, eliminating the need for consumers to separately instal ...

I am seeking guidance on how to manually provide data to an rxjs observable. Can anyone help me with this basic question?

I am interested in using an observable to communicate "exceptional states" to different parts of my Angular application, but I am struggling to grasp their functionality. In the code snippet below, I have created an observer object and turned it into an o ...

Is it not possible to type a Specific Object Type as a Record?

I am looking to create a generic Table Row interface that will only allow objects with primitive attribute values. However, when I try to assign a specific type of object to the row, it fails. Why is this happening and how can I make it work? My goal is to ...

After successfully logging into a Vue.js application running on an nginx server with Axios/Express, the app unexpectedly switches from using HTTPS to HTTP

I have encountered an issue in my Vue.js app where it switches from HTTPS to HTTP after the user logs in, and I am struggling to identify the root cause. The front-end of the Vue.js is being served using nginx and utilizes Axios to interact with an Express ...

What is preventing absolute paths from functioning properly in TurboRepo?

After setting up a fresh project on the most recent version of TurboRepo, I ventured into the 'apps' directory and established a new Vite project using the 'react-swc-ts' template. Making tweaks to the 'tsconfig.json' file wit ...

The issue I'm facing in Jest is the "SyntaxError: Unexpected token 'export'" even after configuring transformIgnorePatterns

When executing npm run test, which triggers the execution of jest, a test suite fails with the following error message: /home/anthony/nosync/development/openmeteo/enhydris-web-frontend/node_modules/vue-notifications/dist/vue-notifications.js:130 export def ...

Tips for preventing duplicate entries in an AG Grid component within an Angular application

In an attempt to showcase the child as only 3 columns based on assetCode, I want to display PRN, PRN1, and PRN2. Below is the code for the list component: list.component.ts this.rowData.push( { 'code': 'Machine 1', &apo ...

Encountering a 404 error with Angular 6 routing after refreshing the page when using an Nginx proxy

I currently have my angular application running within a docker container, exposed on port 83. Additionally, I have a separate spring-boot rest app running inside another docker container, exposed on port 8083. On the host server, there is an Nginx server ...

Is it possible to dynamically assign class properties from an array in JavaScript/TypeScript?

Greetings for the assistance in advance. Currently, I am working with TypeScript, but I believe any JS solution will suffice. I aim to create something akin to the following: class ExcelData { 'Id 1': items[0].id, 'Quantity 1': item ...

Troubleshooting: Unable to filter reducers in Redux when using the remove

I'm attempting to eliminate an element from an array using the filter method in this manner: removeDisplate: (state, action: PayloadAction<string>) => { console.log(action.payload); state.map((item) => { console.log(item.name); } ...

Creating a specialized TypeScript interface by extending a generic one

Create a customized interface using TypeScript that inherits from a generic interface by excluding the first parameter from all functions. Starting with the following generic interface: interface GenericRepository { insertOne<E>(entity: Type<E& ...

Struggling with TypeScript and JsObservable? Let us assist you!

Having previous experience with JSRender, JSViews, and JSObservables, I recently embarked on a new project using TypeScript. Unfortunately, I am struggling to understand how to properly utilize TypeScript in my project, especially when it comes to referenc ...

Show every item from a collection on individual lines within an Angular2 module

I am working with an Angular2 component that is responsible for displaying a list of speakers stored in some data. Currently, when I add the code below to my xyz.component.html, it shows the list as comma-separated strings. However, I would like each speak ...

In Vue 3, the v-model feature is utilized as parameter passing instead of using :prop and @emit

I've been trying to implement two-way binding using v-model in Vue.js based on this article. The idea is to pass values from a parent component to a child component with automatic event emission when the value changes in the child component. However, ...

Troubleshooting Axios and Laravel: Solving the "Bad Request" Console Error

I am currently working with Laravel 5.8, React, and Axios. I have created a login page, but when the login fails, I receive a "bad request" error in the console. Even though I am getting the correct response from the server, the console shows an error rela ...

Include a parameter in a type alias

Utilizing a function from a library with the following type: type QueryFetcher = (query: string, variables?: Record<string, any>) => Promise<QueryResponse> | QueryResponse; I aim to introduce an additional argument to this type without mod ...

Using Google Maps API offline in an Angular/Ionic application is a straightforward process that allows you to

Trying to solve a challenge with an Angular 12 Ionic app that utilizes the Google Maps API through the @angular/google-maps package. Our goal is to maintain map functionality even in areas with unreliable internet connectivity. We are exploring the idea of ...

Deactivate the underscore and include the fiscal year in AngularJS

I am currently faced with a scenario where the back end is returning the value as follows: 123222_D1.123 However, I need to display the date from the database (12-Jun-2020) as 2020-D1.123 in a drop-down menu. Currently, I am displaying the above value i ...