Sporadic UnhandledPromiseRejectionWarning surfacing while utilizing sinon

Upon inspection, it appears that the objects failApiClient and explicitFailApiClient should be of the same type. When logging them, they seem to have identical outputs:

console.log(failApiClient) // { getObjects: [Function: getObjects] }
console.log(explicitFailApiClient) // { getObjects: [Function: getObjects] }

After reading this question, I learned how to handle this situation correctly. However, the reason why the generated failApiClient triggers a warning while explicitFailApiClient does not is still unclear.

I have simplified this scenario to its core for replication purposes and to showcase functional alternatives:

import * as sinon from 'sinon';
import 'source-map-support/register';

class LocalObject {
}

const fakeObject = new LocalObject();

const getFakeApi = (result: Promise<LocalObject[]>) = ({getObjects: () => result});

const successObjectClient = getFakeApi(Promise.resolve([fakeObject]));

// Both lines below should behave similarly, yet one causes a test error
const failApiClient = getFakeApi(Promise.reject(new Error()));

const explicitFailApiClient = {
  getObjects(): Promise<LocalObject[]> {
    return Promise.reject(new Error());
  }
};

describe('successApiClient', () => {
  before(() => {
    sinon.spy(successObjectClient, 'getObjects');
  });

  it('does not generate a warning', async () => {
    // do nothing
  });

});

describe('failApiClient', () => {
  before(() => {
    sinon.spy(failApiClient, 'getObjects');
  });

  it('should not produce a warning', async () => {
    // do nothing
  });
});

describe('explicitFailApiClient', () => {
  before(() => {
    sinon.spy(explicitFailApiClient, 'getObjects');
  });

  it('does not trigger a warning', async () => {
    // do nothing
  });
});

The outcome of running

~/...> tsc && npm test
:

> <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0e67607a6b7c606f62236f7e674e3f203e203e">[email protected]</a> test /Users/./Projects/./node/internal-api
> grunt test

Running "test" task

Running "env:dev" (env) task

Running "simplemocha:unit" (simplemocha) task


(node:72101) UnhandledPromiseRejectionWarning: Error
    at Object.<anonymous> (/Users/./Projects/./node/internal-api/src/test/unit/models/mvp.test.ts:21:57)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (/Users/./Projects/./node/internal-api/node_modules/coffee-script/lib/coffee-script/register.js:45:36)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Module.require (module.js:596:17)
    at require (internal/module.js:11:18)
    at /Users/./Projects/./node/internal-api/node_modules/mocha/lib/mocha.js:222:27
    at Array.forEach (<anonymous>)
    at Mocha.loadFiles (/Users/./Projects/./node/internal-api/node_modules/mocha/lib/mocha.js:219:14)
    at Mocha.run (/Users/./Projects/./node/internal-api/node_modules/mocha/lib/mocha.js:487:10)
    […]

(node:72101) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise […]
  successApiClient
    ✓ does not have a warning

  failApiClient
    ✓ should not have a warning

(node:72101) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously […]

  explicitFailApiClient
    ✓ does not have a warning


  3 passing (14ms)


Done.

Answer №1

The two scenarios are not the same.

When looking at the code snippet, it's clear that in the first case JS immediately executes the statement Promise.reject as an argument, resulting in the early warning UnhandledPromiseRejectionWarning.

const failApiClient = getFakeApi(Promise.reject(new Error()));

In contrast,

const explicitFailApiClient = {
  getObjects(): Promise<LocalObject[]> {
    return Promise.reject(new Error());
  }
};

The Promise.reject in this second scenario is evaluated only when

explicitFailApiClient.getObjects()
is invoked.

A Different Approach

To address this issue differently, another solution can be implemented using Sinon's resolves and rejects.

const getFakeApi = {getObjects: (result) => result};
const getFakeApiStub = sinon.stub(getFakeApi, 'getObjects');

describe('successApiClient', () => {
  before(() => {
    getFakeApiStub.resolves([fakeObject]); // success and resolves
  });

  it('avoids triggering a warning', async () => {
    // no action is required
  });

});

describe('failApiClient', () => {
  before(() => {
    getFakeApiStub.rejects(new Error()); // force it to fail
  });

  it('should not raise a warning', async () => {
    // no action is needed
  });
});

Reference: https://sinonjs.org/releases/v6.3.5/stubs/#stubresolvesvalue

I hope this offers some assistance

Answer №2

There are three possible outcomes for promises: unresolved, resolved, or rejected. The "then" method is used to handle a resolution, while the "catch" method is used to handle a rejection. It seems like you're throwing a rejection without catching it.

You can try

SomePromiseRejection().catch(err => DoSomeStuff(err))

Therefore, make sure to include a .catch block after calling explicitFailApiClient.

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

Retrieve the source code of the current page using JavaScript and the Document Object Model (DOM)

Is there a way to retrieve the source of the current page using JavaScript and DOM? Do I need to utilize AJAX for this task? ...

Issue with React Routes only occurring in the production website

I'm encountering an issue on my personal website that only occurs in production, but not in my local environment. Here's the situation: I have set up the routes as follows const Routes = () => ( <Router> <Route exact path=&quo ...

A table featuring an HTML select element that allows users to choose from preset options or manually enter

My goal is to incorporate a select box where users can either choose from a set list of options or input their own custom value. The select element is nested within a table. Unfortunately, using datalist is not a viable solution for me in this case. I have ...

jQuery opacity transition not functioning properly while all other animations are working fine

I've encountered quite a peculiar issue: Using jQuery v11 on the latest version of Chrome localhost, I can successfully apply jQuery.animate() to various elements and features on my website, including opacity. However, there is one particular element ...

Adjusting table to include hashed passwords for migration

How can I convert a string password into a hash during migration? I've tried using the following code, but it seems the transaction completes after the selection: const users = await queryRunner.query('SELECT * FROM app_user;'); user ...

Implementing JavaScript functionality upon page load with ASP.NET

I have come across a situation where I am trying to integrate working code (jQuery/Javascript) that makes an API call and sends data to it. The API service then responds with a success or failure message based on the data insertion into the API db. Everyth ...

Enumeration field with Conditional logic

I am currently developing a Content Management System (CMS) using strapi for a client, and I want to provide them with the ability to control the questions included in a questionnaire. Each question will be categorized under different sections in the quest ...

Is it possible to have a single listener for all events within the jQuery event namespace?

Is it possible to create a handler that can listen to ALL events within a specific namespace in jQuery using $.fn.on, off, and trigger functions? For example: $(window).on(".event_namespace", function(e){ //handler }); $(window).trigger("testEvent.e ...

The assignment of ajax success data to variables results in an error because data[0] is not defined

Having some trouble retrieving and assigning data from a database in JavaScript using AJAX to call a PHP script with a MySQL query. Although the AJAX request is successful, when trying to store the data into variables, they appear as undefined or NaN in th ...

SDK for generating templates with JavaScript/jQuery

I am in the process of developing an SDK in JavaScript/jQuery that can generate templates based on user input, such as profile templates and dialog templates. These templates require data from an AJAX call to be created. User input should include certain ...

Is Jquery Steps causing interference with the datepicker functionality?

I am currently using the jquery steps plugin for creating a wizard on my website. However, I am experiencing some issues with the functionality of the datepicker and qtip inside the steps. Even after switching the .js references, the problem still persists ...

Modifying the nested data organization in Sequelize

I'm looking to adjust the data structure retrieved from an ORM query involving four tables. The product and category tables have a many-to-many relationship, with the product_category table serving as a bridge. Additionally, there's a fourth tabl ...

Angular 2's Multi-select dropdown feature allows users to select multiple options

Recently, I encountered an issue with customizing CSS for angular2-multiselect-dropdown. I found the solution in this link: https://www.npmjs.com/package/angular2-multiselect-dropdown. I have included my code below. Any assistance in resolving this matter ...

Arrange elements within an array according to a specific property and the desired sorting sequence

Looking for a way to sort an object array in Angular 16+ based on status. The desired status order is: [N-Op, Used, Unknown, Op] Here's the sample data: const stockList = [ { 'heading': 'SK', 'status': &a ...

Verify the presence of an email in the database utilizing a custom express-validator for node, express, and mysql

//Endpoint to update the user's email address. apiRouter.post('/update-email', [ check('newEmail') .isEmail().withMessage('Please enter a valid email address') .custom(newEmail=> { db.query(`SELECT user ...

Accessing the OSRM API allows users to determine the distance to the closest emergency station

I am currently working on a typescript project where I need to calculate the distance to the nearest police station and fire station. My approach involves utilizing typescript for this task. Initially, I attempted to use the following URL that I discovere ...

Manipulating Images with jQuery: Adding and Removing Images Without Affecting Text

Below is the code I'm working with: <input type = checkbox id = "purple" name = "box" > Purple </input> <div id = birdcage></div> This is the JavaScript section: $("#purple").click(function(){ if ($("#purple").is(":chec ...

Unable to set the height for ul/div elements

I'm struggling to make my navbar appear when I click the "menu button". The div seems to be present in the code, but with a height of 0. Here's the relevant section of the code causing the issue. Any suggestions on how I can resolve this? var ...

Using JSON files in React applications is essential for accessing and displaying static data. Let's

If I want to refer to a file locally in my JS code instead of on a remote server, how can I do that? I know the file needs to be in the public folder, but I'm unsure how to reference it in the JavaScript provided above. class App extends Component { c ...

npm Error: The installation script for [email protected] has encountered a failure

I encountered an error while attempting to execute "ionic start MyApp" in the Windows terminal. This is a new machine and I have already reinstalled nodejs and ionic, but the same error persists. Can someone lend a hand? npm WARN tar invalid entry & ...