What methods can I use in Mocha with Sinon for testing multiple callbacks?

My code involves a function with asynchronous operations and multiple callbacks

var f = (cb1, cb2) => {
  return new Promise((resolve, reject) => { /* ... */ });
};

During testing, I wanted to use sinon to create spies

var cb1Spy = sinon.spy();
var cb2Spy = sinon.spy();

To ensure that both callbacks are called, I designed a test case

it('test', (done) => {
  var cbCount = 2;
  var checkIfDone = () => {
    if(--cbCount === 0){
      done()
    }
  };
  f(
    () => { cb1Spy; checkIfDone(); },
    () => { cb2Spy; checkIfDone(); }
  );
});

The test seems to work fine, but it doesn't feel like the optimal approach. Are there any best practices for this type of testing?

Answer №1

The Mocha done callback is specifically designed for testing asynchronous code and should not be used as a way to directly control success or failure.

To cause a test failure, it is recommended to throw Error objects with specific error messages indicating the reason for the failure. Assertions are statements that can be used to throw such errors if certain conditions are not met. There are numerous libraries available for this purpose, with chai being one of the most popular ones.

Sinon provides its own set of assertions that can be used with its test doubles. For example, to assert that the cb1Spy was called once, you can use:

sinon.assert.calledOnce(cb1Spy);

If you decide to use chai, there is a useful plugin called sinon-chai that allows you to write sinon assertions in a similar syntax to chai's assertions, providing a more consistent testing experience. With sinon-chai, your tests can look like this:

const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
const { expect } = chai;
chai.use(sinonChai);

describe('whatever', function() {
    it('test', function() {
        let cb1Spy = sinon.spy();
        let cb2Spy = sinon.spy();

        f(cb1Spy, cb2spy);

        expect(cb1Spy).to.have.been.calledOnce;
        expect(cb2Spy).to.have.been.calledOnce;
    });
});

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

Guide on converting this function into a computed property within Vue

Is it possible to concatenate a fixed directory path, which is defined in the data property, with a file name that is determined using v-for? I encountered an issue when attempting to do this using a computed property. The error message displayed was: ...

The virtual method 'android.location.Location' was called in error

I'm using WL.Device.Geo.acquirePosition(onGeoLocationSuccess, onGeoLocationFailure, options) from MobileFirst to retrieve a device's location. Initially, everything works smoothly as I successfully obtain the location. However, after clearing t ...

Please note: With React 18, the use of ReactDOM.render is no longer supported. Instead, we recommend using create

I encountered an issue while attempting to link my React application with a MongoDB database. Here is the code snippet where the problem occurred: //index.js ReactDOM.render( <React.StrictMode> <BrowserRouter> <App /> &l ...

Consider yourself a module for npm, just like a node

I'm currently working on a Javascript project that has been released as a node module. In some parts of the source code, I have used relative paths to import other files within the project: // <this_module_path>/action/foo.js import execution f ...

Set up webpack on your Mac using npm

Seeking help to install webpack using npm: sudo npm install -g webpack The following error message is encountered: node-pre-gyp WARN Using needle for node-pre-gyp https download node-pre-gyp WARN Pre-built binaries not installable for <a href="/cdn- ...

Background image fixed with scrolling effect

I've been struggling with a parallax effect on my website. After seeing it work smoothly on other websites, I tried to implement it myself but couldn't quite get it right. The background image keeps moving when I scroll the page and I want it to ...

Encountered a snag while executing Powershell with Selenium: Error message - unable to interact with

Looking to update a textarea with a value? The script below triggers an error stating "element not interactable". This occurs because the textarea is set to "display:none". However, manually removing the "NONE" word allows the script to successfully set th ...

Error: Material-UI prop type validation failed - Please specify either `children`, `image`, `src`, or `component` prop

Despite having an image prop in CardMedia, I kept encountering this error. Here is a snippet of the code: Error description: const Post = ({ post, setter }) => { const classes = useStyles(); return( <Card className={classes.card} ...

Increase the count if the item is already in the shopping cart - React

Is there a way to avoid adding the same product to the basket multiple times and instead just increment a counter? How can I effectively keep track of each item's count? this.state = { description: '', commaSalesPrice: '', ...

Infinite loop triggered by jQuery dropdown menu on page resize was causing an issue

I have been working on developing a navigation menu for a website that displays as a horizontal bar on larger screens, but transforms into a jQuery dropdown menu when the window width is less than 980px. During initial page load with a window width below ...

Retrieve an image from the database and associate it with corresponding features or news in PHP

I have retrieved a value from the database, displayed it as an image, and made it a link. So, I want that when a user clicks on the different image, they get the result from the query related to the image. I hope everyone understands. <?php // Connect ...

Seamless infinite background scrolling on the canvas without any disruptions

In my HTML5/JS project, I have implemented infinite background scrolling using multiple canvases. The challenge I am facing is that while the animation is smooth after rendering, there is a quick hiccup when transitioning to the next frame due to the need ...

The Node/NPM tool is mistakenly updating the package.json and package-lock.json files in my personal directory rather than the intended project directory

For a fun project with BabylonJS, I decided to create a new directory on my computer specifically for it located at ~/workspace/babylon-test. After setting up the directory, I navigated to it using the following commands: mkdir ~/workspace/babylon-test cd ...

A Typescript Function for Generating Scalable and Unique Identifiers

How can a unique ID be generated to reduce the likelihood of overlap? for(let i = 0; i < <Arbitrary Limit>; i++) generateID(); There are several existing solutions, but they all seem like indirect ways to address this issue. Potential Solu ...

Using JavaScript, generate an array of objects that contain unique values by incrementing each value by 1

I have an array of objects called arrlist and a parameter uid If the property value has duplicate values (ignoring null) and the id is not the same as the uid, then autoincrement the value until there are no more duplicate values. How can I achieve the a ...

When the onload event is triggered, the jscript function called var data is loaded, without any interruption in

I encountered an issue while trying to preview an image from a BBCode decoder. The code works fine, but I need the image to be inside an <a> href link, so that people can click on it and get the image source. Additionally, I want to display a message ...

Encountering a 500 Internal Server Error in Next.js immediately after invoking the useEffect Hook within a 404 Page

In my code, I utilize the useEffect hook to trigger a setTimeout function inside it in order to automatically redirect the user back to the home page after 3 seconds using the useRouter hook from Next.js and calling the push method on it. Everything works ...

What is the best way to create a Snap.svg map using AngularJS?

I am in the process of creating a web interface for an online board game. My goal is to load a Snap.svg map using Snap.load asynchronously. Once the map is loaded, I intend to attach a watch to a scope property and apply colors to the map based on that pr ...

Utilizing Mongoose for incorporating embedded documents within forms

Within my Mongoose schema named Question, I have a straightforward setup for storing questions and their corresponding answers. Answers are defined in a separate schema and stored as embedded documents within the Questions collection. Below is the outline ...

How can one use an express post request to direct the client to the login page forcefully?

I am implementing secure backend routes that run a verifyJWT function before retrieving data. Is there a way to automatically redirect the client to the login page if the token is expired or invalid? Using res.redirect("/login") did not have any effect on ...