I need to find a way to properly test a recursive, async JavaScript function by utilizing fake timers

I've been working with a basic recursive function that performs as expected when run. To thoroughly test its operation at each stage, I want to utilize Sinon's fake timers.

Unfortunately, it seems that the fake timers are only affecting the initial call of the recursive function.

I'm hoping someone might have a solution for ensuring that the fake timers are active throughout the entire process.

For example:

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

async function ensureCount(count, { attempt, delay }) {
  attempt = attempt || 0
  console.log('Attempt', attempt)

  if (attempt === count) {
    return
  }

  await wait(delay)
  await ensureCount(count, { attempt: attempt + 1, delay })
}

Testing method used (with guidance from this resource):

it('retries after a given delay', function() {
  const clock = sinon.useFakeTimers()
  const promise = ensureCount(2, { delay: 200 })

  clock.tick(200)
  // Add your assertions here.

  clock.tick(200)
  // Add your assertions here.

  clock.tick(200)
  // Add your assertions here.

  return promise
})

Expected console output (without fake timers):

Attempt 0
Attempt 1
Attempt 2
✔ retries after a given delay (405ms)

Actual console output (using fake timers):

Attempt 0
Attempt 1
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

The Issue:

Is there a method to make the fake timers apply to every iteration of the recursive call rather than just the first one?

Answer №1

Discovering that Sinon has a hidden gem in the form of a .tickAsync() function was a game-changer for me. (Shoutout to this helpful comment).

This revised code easily resolves the issue at hand:

it('handles retries with a delay', async () => {
  const clock = sinon.useFakeTimers()
  ensureCount(2, { delay: 200 })

  await clock.tickAsync(200)
  // Perform assertions.

  await clock.tickAsync(200)
  // Perform assertions.

  await clock.tickAsync(200)
  // Perform assertions.

  clock.restore()
})

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

Java Script Custom Print Preview: A unique way to showcase your content

Is there a way to create a custom print preview dialog similar to the browser's print preview using Java Script? I am working on a book reader application that requires customization of the print preview dialog for page counting, automatic pagination, ...

Error: Unable to execute $(...).stellar since it is not a recognized function

Having some trouble implementing the stellar plugin. I've included all the necessary js, but keep getting an error in the dev tools console: 'Uncaught TypeError: $(...).stellar is not a function'. Here's what I have in the head tags: ...

Retrieve an array from the updated scope

I need help with my code. How can I retrieve the names from an array and display them in my input box? Also, how do I get all the changed names back into the array? Thanks in advance! - Marco app.js var g[]; var names = ['John', 'Steve&apo ...

Passing multiple variables to another page via AJAX

As I develop a website, I encountered an issue with resetting the password script on a specific page. To resolve this, I am utilizing AJAX to pass both the old and new passwords while aiming to display the outcome on the same page. The code snippet for th ...

Why is my event.target.value not updating correctly in React useState?

My problem is that when I use useState, I am receiving incorrect numbers For example, if I print e.target.value it might display 1, but my selectedIndex shows 2. Similarly, when I have a selectedIndex of 0, it retrieves something different like 1. Any tho ...

Functionality that can be utilized repeatedly

I've been struggling to implement a feature for repeatable blocks in my web form. The issue I'm facing is that when I click the buttons, nothing happens even though they work fine when tested in the console. I've been stuck on this problem f ...

Despite being used within useEffect with await, asynchronous function fails to wait for results

In my component, I am utilizing a cookie value to determine which component or div block to display. The functionality works correctly in the end, but there is a brief moment where it seems like the cookie value is not being checked yet. During this short ...

The ng-model is not properly syncing values bidirectionally within a modal window

I am dealing with some html <body ng-controller="AppCtrl"> <ion-side-menus> <ion-side-menu-content> <ion-nav-bar class="nav-title-slide-ios7 bar-positive"> <ion-nav-back-button class="button-icon ion-arrow-le ...

Exploring Options for Enabling HTML in AngularUI Accordion-Group Content

I want to showcase content in an accordion-group that might contain HTML markup. This content is fetched from external sources. How can I achieve this? You can check out an example at Plnkr (content hard-coded for testing) Currently, the items are displa ...

Prisma auto-generating types that were not declared in my code

When working with a many-to-many relationship between Post and Upload in Prisma, I encountered an issue where Prisma was assigning the type 'never' to upload.posts. This prevented me from querying the relationship I needed. It seems unclear why P ...

Is there a way to stop mUI from displaying the dropdown menu once Chrome automatically fills in a user's address details?

I am currently developing a form for users to enter their address in order to collect a billing address for payment information. Our services are only available to customers within the United States, so we have implemented an autocomplete UI component with ...

The incorrect sequence of Angular/Protractor functions is causing issues within the tests

Trying to extract the values from a column in a grid and compare them before and after sorting can be tricky. I have two functions set up for this task - one to retrieve the initial column values, and another to check the order post-sorting. However, there ...

"if the condition is not met, the outcome will not be shown in the while

I have a looping structure that includes conditions for if, else if, and else. However, I have noticed that the else condition at the end of the loop is not being executed as expected. I am currently investigating why this might be happening. Here is the ...

Instructions for sorting an array of objects by Firebase Timestamp

I am looking for a way to order my messages based on timestamp in Firebase v9. In earlier versions, I was able to do this but now I seem to be facing some difficulties. Here is the data structure set up on Firestore: const [messages, setMessages] = useSta ...

The callback function in JavaScript seems to be missing without ever being executed

I have a SendMail function using nodemailer that successfully sends emails, but the callback function logging "mail sent" is not getting executed. Any suggestions on what might be causing this? var email = '<a href="/cdn-cgi/l/email-protection" cla ...

Error: Cannot execute 'x' as a function

I am currently developing an Express web application that initiates JavaScript scraping code upon the page's initial load. Below is the node web scraping code (scrape.js): const request = require('request-promise'); const cheerio = require( ...

Error encountered: MongoDB cast exception - nested subdocument

Check out this schema design: var messageSchema = new Schema({ receivers: [User], message: String, owner: { type: Schema.Types.ObjectId, ref: 'User' } }); var userSchema = new Schema({ name: String, photo: String }); var in ...

Encountering issues with the phaser framework while setting up a server on xampp, faced with errors in javascript and html

Recently, I've been working on a game using Phaser and encountered some issues while trying to run the code in XAMPP. The game's base is located at htdocs/itw/test.html, with the necessary pngs and json file stored in htdocs/itw/assets/. The pngs ...

Transfer text from one form to a text field on a different website

I've created a form that allows users to input numbers in a field and then directs the page to a specific URL. Here's the code snippet: <html> <head> <meta charset="utf-8"> <title>Tracking</title> </head& ...

What steps can be taken to resolve the error message "Module '../home/featuredRooms' cannot be found, or its corresponding type declarations"?

Upon deploying my site to Netlify or Vercel, I encountered a strange error. The project runs smoothly on my computer but seems to have issues when deployed. I am using TypeScript with Next.js and even attempted renaming folders to lowercase. Feel free to ...