unit testing with Jest and retrying HTTP requests in Node.js

I've been attempting to utilize the retry-axios library and verify the number of "get" calls made without success. Here's how I've set it up:

axios.config.ts

import axios, { AxiosInstance } from 'axios';
import * as rax from 'retry-axios';

export const axiosClient: AxiosInstance = axios.create({
  raxConfig: {
    retry: 3,
    onRetryAttempt: (err: any) => {
      const cfg = rax.getConfig(err);
      console.error(`Retry attempt #${cfg?.currentRetryAttempt}`);
    }
  },
});

rax.attach(axiosClient);

api.service.ts

import { axiosClient } from 'axios.config';

export class ApiService
{
 callApi = async (endPoint): Promise<any> => {   
    const response: AxiosResponse<any> = await axiosClient.get(endPoint);
    return response.data;
};

api.service.spec.ts

import { ApiService } from 'api.service';

    it('Should successfully call the end point if the first attempt fails and the second attempt succeeds.', async () => {
      const service = new ApiService();
      const apiResponse = { data: { content: [] } };
      jest.spyOn(axiosClient, 'get').mockRejectedValueOnce(() => { throw 500 });
      jest.spyOn(axiosClient, 'get').mockResolvedValueOnce(apiResponse);
      try {
        await service.callApi("endpoint");
      }
      catch (e) {
        expect(axiosClient.get).toHaveBeenCalledTimes(2);
      }
    });

No matter what I try, the assertion regarding the number of "get" calls always returns 1.

Below are some other attempts I made by throwing an error when mocking the rejection on the first attempt:

jest.spyOn(axiosClient, 'get').mockImplementationOnce(async () => { throw 500; });
jest.spyOn(axiosClient, 'get').mockImplementationOnce(async () => { throw new Error(500) ;});
jest.spyOn(axiosClient, 'get').mockRejectedValueOnce(async () => { throw new Error(500); });
jest.spyOn(axiosClient, 'get').mockRejectedValueOnce(() => { return {statusCode: 500}; });

Thank you. Please let me know if you require any further details.

Answer №1

Although this question may have been asked before, I recently dedicated 3 hours to finding a solution to the same issue. The answer lies in utilizing

import MockAdapter from "axios-mock-adapter"
:

it("Should retry", async () => {
    const mock = new MockAdapter(axios)
    mock.onGet().replyOnce(500, {})
    mock.onGet().replyOnce(200, validResponse)
    callTheApiAndCheckResponse()
})

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

Tips on preventing the need for null or undefined checks in JS/Typescript singletons that have an initialization function

Is there a way to streamline the process of handling props in an Object literal that is dynamically initialized only once? I'm looking for a pattern that would eliminate the need for repetitive null/undefined checks and throw errors when certain metho ...

TypeScript excels in typechecking when using two individual assignments, but may encounter issues when attempting typechecking with tuple

I am quite puzzled by a discovery I made and I am seeking to understand why TypeScript is displaying this behavior and what the underlying reason may be. Here is the code snippet: class A { constructor(public name : String, public x = 0, public y = 0) ...

Guide to resolving a Promise that returns an array in TypeScript

My goal is to retrieve an array in the form of a promise. Initially, I unzipped a file and then parsed it using csv-parse. All the resulting objects are stored in an array which is later returned. Initially, when I tried returning without using a promise, ...

Ways to set a default value for a function that returns an unknown type in TypeScript

In my code, I have a customizedHook that returns a value of type typeXYZ || unknown. However, when I try to destructure the returned value, I encounter an error TS2339: Property 'xyz' does not exist on type 'unknown', even though the da ...

Express displays html instead of json when error handling occurs

I recently followed a tutorial on Express.js to create a simple error handler. function clientErrorHandler(err, req, res, next) { if (req.xhr) { console.log('clienterrorhandler', err); res.status(500).send({ error: 'Something faile ...

Passing a React functional component with SVG properties to another component as a prop

My goal is to import a React functionComponent from an SVG and pass it as a prop to another component for rendering the svg. The code below compiles without errors, but crashes when trying to display the svg in the browser with the following message: Er ...

Changing Observable to Promise in Angular 2

Q) What is the best way to convert an observable into a promise for easy handling with .then(...)? The code snippet below showcases my current method that I am looking to transform into a promise: this._APIService.getAssetTypes().subscribe( assetty ...

Is there a way to verify if a React hook can be executed without triggering any console errors?

Is there a way to verify if a React hook can be invoked without generating errors in the console? For example, if I attempt: useEffect(() => { try { useState(); } catch {} }) I still receive this error message: Warning: Do not call Hooks i ...

Struggling to find a solution for directing to the featured homes page without the content overlapping with my navbar and search component. Any assistance would be greatly

Looking for assistance with routing to the featured homes page without the content overlapping my navbar and search component. I simply want it to direct to a new URL without importing the components unless specifically needed. Check out this link I suspe ...

Avoiding an endless spiral on a setter in JavaScript/TypeScript

Implementing TypeScript, I've been working on setting up a concept called a "trigger" : an object that includes both a checker function (which returns a Boolean) and a behavior function capable of performing various tasks. My aim is to execute the che ...

Python's yield functionality facilitates the creation of lightweight generators, allowing

Request is being sent from the front end to trigger the backend method. In Python Flask, the backend method utilizes a generator and yield to iterate through a list of 100000 elements, sending each element one by one to the front end. The goal is for the b ...

Compose a message directed to a particular channel using TypeScript

Is there a way to send a greeting message to a "welcome" text channel whenever a new user joins the server (guild)? The issue I'm running into is that, when I locate the desired channel, it comes back as a GuildChannel. Since GuildChannel does not hav ...

You cannot utilize Lesson as a JSX Component in Next JS TypeScript

Below is my updated page.tsx code: import Aspects from '@/components/Aspects'; import FreeForm from '@/components/FreeForm'; import Lesson from '@/components/Lesson'; import React from 'react'; import { Route, Route ...

Combining TypeScript and ReactJS with RequireJS: A guide to importing react-dom in TypeScript

I am currently working with TypeScript and React.js. Within Visual Studio 2015, I have set the project properties to use AMD as the module system for TypeScript build, meaning I am utilizing requirejs for importing modules. Within my main.tsx file, I am r ...

Enhance React component props for a styled component element using TypeScript

Looking to enhance the properties of a React component in TypeScript to include standard HTML button attributes along with specific React features such as ref. My research suggests that React.HTMLProps is the ideal type for this purpose (since React.HTMLA ...

Cannot execute npm packages installed globally on Windows 10 machine

After installing typescript and nodemon on my Windows 10 machine using the typical npm install -g [package-name] command, I encountered a problem. When attempting to run them through the terminal, an application selector window would open prompting me to c ...

What is the best way to define types for an array of objects with interconnected properties?

I need to define a type for an object called root, which holds a nested array of objects called values. Each object in the array has properties named one (of any type) and all (an array of the same type as one). Below is my attempt at creating this type d ...

The object's value may be 'undefined' after utilizing a switch case to ensure it is not undefined

Before I encountered the error Object is possibly 'undefined'.ts(2532) at testObject["x"], I had used case "x" in testObject. Why did this happen? Should I create my own type guard for it? interface TestObject { a?: number; ...

Error in TypeScript when using keyof instead of literal in type pattern.Beware of TypeScript error when not

let c = { [X in keyof { "foo" }]: { foo: "bar" } extends { X } ? true : false }["foo"]; let d = { foo: "bar" } extends { "foo" } ? true : false; c and d should both return true, but surprisingly, c is eval ...

Adding ngModel in the template causes the Angular component to load multiple times

I have been working on creating an Angular form and have successfully referenced the form in the Angular module. However, I am facing a problem where adding ngModel to an input textbox causes the Angular component to load multiple times on the page. Belo ...