Checking the status of a Promise within Promise.finally() without needing to await it in a live environment

In my development code, I am utilizing Promise.prototype.finally() (or try-catch-finally in an async function) to run additional code without altering the resolution or rejection status of the current promise.

However, when it comes to testing with Jest, I want to specifically check if the Promise within the finally block was not rejected.

edit: The catch section of my "production" code is where I handle errors, so I'm only concerned about re-thrown errors from there and not from finally.

Is there a way to test this? Or perhaps mock the Promise.prototype to reject the current promise upon exceptions from finally?

For example, when testing redux action creators like in the following code snippet, the tests pass even though there may be an unhandled Promise rejection warning:

https://codesandbox.io/s/reverent-dijkstra-nbcno?file=/src/index.test.js

test("finally", async () => {
  const actions = await dispatchMock(add("forgottenParent", { a: 1 }));
  const newState = actions.reduce(reducer, undefined);
  expect(newState).toEqual({});
});

const dispatchMock = async thunk => {...};

// ----- simplified "production" code -----

const reducer = (state = {}, action) => state;
const add = parentId => async dispatch => {
  dispatch("add start");
  try {
    await someFetch("someData");
    dispatch("add success");
  } catch (e) {
    dispatch("add failed");
    throw e;
  } finally {
    dispatch(get(parentId)); // tests pass if the promise here is rejected
  }
};
const get = id => async dispatch => {
  dispatch("get start");
  try {
    await someFetch(id);
    dispatch("get success");
  } catch (e) {
    dispatch("get failed");
    throw e;
  }
};
const someFetch = async id => {
  if (id === "forgottenParent") {
    throw new Error("imagine I forgot to mock this request");
  }
  Promise.resolve(id);
};

Answer №1

fetchDataFromServer(parentId); // check if an error is triggered here

No errors are thrown at that point. The function fetchDataFromServer(parentId) may result in a promise rejection (or a pending promise that may be rejected later), but this does not constitute an exception and will not disrupt the flow of control.

Perhaps you meant to write:

const updateData = parentId => async fetchData => {
  fetchData("loading");
  try {
    await fetchSomeData("data");
    fetchData("success");
  } catch (error) {
    fetchData("failed");
    throw error;
  } finally {
    await fetchDataFromServer(parentId);
//  ^^^^^
  }
};

It is worth noting that throwing exceptions from a finally block is generally discouraged.

Answer №2

update: for more versatile solutions, visit


One approach is to save the Promise in a variable that is accessible in a specific helper function used solely for testing purposes:

export const _getPromiseFromFinallyInTests = () => _promiseFromFinally
let _promiseFromFinally

const add = parentId => async dispatch => {
  ...
  } finally {
    // The current Promise remains unchanged as it is not awaited here
    _promiseFromFinally = dispatch(get(parentId));
  }
};

You can then modify the test to await this specific Promise during testing:

test("finally", async () => {
  ...
  // Ensure the test fails if the Promise from finally is rejected
  await _getPromiseFromFinallyInTests()
});

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

Is the position behind the object in Three JS?

Is there a way to determine if a position is behind a 3D character and not in front or to the side? I have a 3D character with predefined positions on the floor. I have attached a rough sketch to illustrate what I am trying to achieve (apologies for the po ...

Choose an option from the dropdown menu, then eliminate other choices that have the same value as the one selected

Our system involves using dropdown menus to select an airport and its terminal, followed by another dropdown menu to choose a specific service within that airport and terminal. For example, selecting Airport 1 and the International Terminal would then prom ...

When a change occurs in the <input/> element within a <div>, the onChange event in React will be triggered

Upon entering text into the input, the onChange function is triggered on this code snippet. How is it possible for the onChange event to occur on a div element? Is there documentation available that explains this behavior? class App extends Component { ...

After making an Ajax call using AngularJS in a PHP file, I expected to receive only a success or fail message. Instead, I received the entire HTML page code along

After making an Ajax call using AngularJS in a PHP file, I expected to receive only a success/fail message. However, I ended up receiving the full HTML page code along with tags. Here is my AngularJS code: $http.post('ajax_Location.php',{ &apos ...

How can I implement the delete button in a recently appended table row using the clone() function in jQuery?

Whenever I click the Add button, a new row gets appended to the HTML table. You can check out the jsFiddle link for reference: http://jsfiddle.net/fgLHN/3/ The code above functions smoothly for me. However, I'm facing an issue when trying to add a de ...

Finding the index and value of a specific HTML element with jQuery click event

I'm currently working on creating an Ajax function to delete items from a list using Jquery ajax. Here is the HTML structure: <ul> <li><a class="del"><span style="display:none;">1</span></a></li> <li& ...

When transitioning from one screen to another in React Native, the toast does not appear. Setting a setTimeout of 1000 fixes this issue temporarily, but I am looking for a way to display

visitSite("openshift") setTimeout(() => { displayMessage('Shift Assigned', 'success'); }, 1000); // HOWEVER, I prefer to have the functionality of displaying a success message and navigating between screens separated into distin ...

Creating a selection area with CSS that appears transparent is a straightforward process

I'm currently exploring ways to implement a UI effect on a webpage that involves highlighting a specific area while covering the rest of the page with a semi-transparent black overlay, all using CSS only. What is the most common approach to achieving ...

Obtain the selected dropdown value and transfer it to the controller seamlessly without the need to reload the page

Currently, I am facing an issue with two dropdown lists in a bootstrap modal - CATEGORY and SUBCATEGORY. The values in the SUBCATEGORY list depend on the selection made in the CATEGORY list. My goal is to retrieve the selected value ID and pass it to my co ...

Invoke a parent method from a nested child component in Vue

After setting up a project with vue-cli using the webpack template, I decided to incorporate a reusable bootstrap modal dialog in the App component. To achieve this, I created a method called showMessage in the App component that handles displaying the mod ...

Tips for fixing the issue of "module ./response not found" in Node.js Express

Whenever I execute the command $ npm start this error message appears > <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8feefcfce6e8e1e2eae1fbbccfbea1bfa1bf">[email protected]</a> start > nodemon server.js ...

Convert an array of objects into an array of objects with combined values

Here is an example of an array containing objects: array = [ {prop1: 'teste1', prop2: 'value1', prop3: 'anotherValue1' }, {prop1: 'teste2', prop2: 'value2', prop3: 'anotherValue2' }, {prop1: &apo ...

Invoking a function from a separate JavaScript file and finding out that an object is considered null

The source code for a word game is stored in Main.js file. Currently, I am attempting to introduce another file called Bookmarks.js (included on the web page prior to the Main.js file). This new file will contain an object var bookmarks = {}; that stays s ...

A guide to downloading files through your web browser

Currently, I am working on a project to download videos from the browser using youtube-dl for educational purposes. I have encountered an issue regarding downloading local mp4 files in the browser using axios. The download starts successfully; however, af ...

How to use Javascript to fetch HTML content from an external website

Is it possible to access and retrieve scores from for a specific week using AJAX or JSON technology? Each game on the website seems to have a unique class which could make retrieving score information easier. Any guidance or assistance would be greatly ap ...

How can I utilize jQuery to iterate through every anchor tag on an HTML page?

I am looking to reference all anchor tags on the page that have a parent h2 tag. To achieve this, I need to iterate through each anchor tag that has a parent h2 and add an attribute using jQuery. <body> <h1>not me</h1> <a href ...

Navigating through certain JSON information in AngularJS

I am facing a challenge with handling article information stored in a json file, where each article has a unique id. The format of the json data is as follows: [{"title":"ISIS No. 2 killed in US special ops raid", "id":"14589192090024090", ...

Why isn't pagination typically positioned inside of a tbody element rather than before or after it?

I've created a user table that is based on the number parameter. I added a filter that listens to input and performs an AJAX call each time with the filter applied to the name field. However, the pagination is initially displayed ABOVE the entire ta ...

Unable to resubmit form via ajax more than once

Greetings to all, I seem to be encountering some issues with a supposedly simple form submission using ajax. Upon the initial submission of the form by the user, everything proceeds smoothly: The content within the div changes as expected and the PHP proc ...

Ways to identify whether the ajax error is due to Access-Control-Allow-Origin restriction or if the file is genuinely absent

My question pertains to customizing error messages for Access-Control-Allow-Origin issues and outdated URLs. I want to display specific messages to the user based on different types of errors that may occur. Currently, my code looks like this: $.ajax( { ...