Ensure that you utilize the default error handler in Express when using Jest's await

Consider the setup provided below:

const express = require("express");
const app = express();

app.get("/", function(req, res, next) {
  // deliberately trigger an error
  return next("my error");
});

// created this middleware for demonstration purposes,
// approach should generally work for default error handling in express too
app.use(function(error, req, res, next) {
  if (error) {
    res.status(500).send({ error });
    throw new Error(error); // <- how to verify this?
  }
  next();
});

app.listen(8080, function() {
  console.log("server running on 8080");
}); //the server object listens on port 8080

And for testing purposes:

const request = require("supertest");
const app = require("../../app.js");

const spy = jest.spyOn(global.console, "error").mockImplementation();

it("triggers an error", async done => {
  const res = await request(app).get("/");

  expect(res.status).toBe(500);
  expect(res.error.text).toContain("my error");

  expect(spy).toHaveBeenCalled(); // none...

  done();
});

I have set up a Codesandbox with this sample code. Unsure about executing a node test within it though.

Answer №1

Avoid mixing async with done, as it may lead to test timeouts if done() is not reached.

Mainly, error handlers should not re-throw errors unless they are meant to be appended to another handler. The final error handler should handle both synchronous and asynchronous errors within it.

The issue lies in the fact that the default error handler is triggered asynchronously, so it needs to be specifically awaited:

it("raises an error", async () => {
  const spy = jest.spyOn(global.console, "error");
  const res = await request(app).get("/");

  expect(res.status).toBe(500);
  expect(res.error.text).toContain("my error");
  await new Promise(resolve = > setTimeout(resolve));
  expect(spy).not.toHaveBeenCalled(); // should not have been called
});

A more appropriate approach would be to ensure proper error handling:

it("raises an error", async () => {
  const defaultErrorHandler = jest.fn((err, req, res, next) => {});

  app.use(defaultErrorHandler);
  const res = await request(app).get("/");

  expect(res.status).toBe(500);
  expect(res.error.text).toContain("my error");
  expect(defaultErrorHandler).not.toHaveBeenCalled();
});

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

Unable to attach a comment using ajax

I'm currently attempting to implement a feature that allows users to add comments using ajax. Below is the ajax code I have written: $(document).ready(function(){ $("#add_comment").click(function(event){ event.preventDefault(); va ...

Tips for creating case-insensitive query string values in angularjs?

After reading about the case sensitivity of query string keys from here, I realized my query pertains to the case sensitivity of query string values. Is there a way to make query string values case insensitive? Is it possible to receive the same result wh ...

Utilizing Cordova and AngularJS to efficiently retrieve JSON data through XMLHttpRequest in a factory

I've encountered an issue while attempting to retrieve a JSON from an API using XMLHttpRequest within a factory. Despite the debug logs suggesting that everything is functioning correctly, I keep getting an "undefined" response. Below is the code for ...

When using Gzip compression in an AWS Lambda function deployed with API Gateway V2, users encounter the ERR_CONTENT_DECODING_FAILED error message in their web

I am looking to enable gzip compression for content delivery using AWS Gateway V2. However, AWS Gateway V2 does not have built-in compression capabilities, so I have implemented compression within the lambda before sending it over the wire. The issue I am ...

Tips for including parameters in an array of values when using getStaticPaths

I'm trying to retrieve the slug value that corresponds with each number in the getStaticPaths for my page structure: /read/[slug]/[number]. The code I have is as follows: export async function getStaticPaths() { const slugs = await client.fetch( ...

What is the best way to retrieve all Objects by a specific property in React when working with an array of Objects?

I am looking to create a multiple checkbox filter where selecting the 'Accessories' option will display items with the 'Accessories' value under the 'type' property. However, before I proceed with that, I need to ensure that I ...

When implementing express-session middleware, an error occurs stating "setImmediate is not defined, resulting in a crash."

My Node application encounters a problem when I attempt to integrate session middleware: app.use(session({secret: 'keyboard cat', cookie: { maxAge: 50000000 }})); Upon reaching a res.send in any route without any further adjustments, my applica ...

getStaticProps will not return any data

I'm experiencing an issue with my getStaticProps where only one of the two db queries is returning correct data while the other returns null. What could be causing this problem? const Dash = (props) => { const config = props.config; useEffect(() ...

Disappearance of newly added row in jquery

I am currently facing an issue with a code I have written for database updates. The problem arises after adding a new row, as it initially displays but then promptly disappears. This peculiar behavior occurs on the server end when I attempt to view the p ...

Using an if statement within a map function in a React component

I am facing a challenge with using an if statement inside a map function without changing the return value. Here is my code snippet: this.example = this.state.data.map((item) => { return( <div> {if(1 + 1 == 2){ dat ...

Eliminating memory leaks in a React web application

I'm facing an issue in my ReactJS web application with the following code: useEffect(() => { const fetchInfo = async () => { const res = await fetch(`${api}&page=${page}`); setLoading(true); try { const x = awa ...

How come the output of the multiplication is not visible in the template using JavaScript, but it is visible when inspecting the element in Chrome DevTools?

I have integrated some JavaScript into my Django project to handle system calculations. However, I find it odd that something as simple as the result of a multiplication is not reflected on the webpage template but only in the Chrome Dev Tools. Below are ...

The unique text: "User-defined input element disregards changes initiated through

I created a custom input component that functions correctly, but I have encountered an issue. When I attempt to update the value through a method, the model gets updated but the input value remains unchanged. Here is my component: https://codepen.io/ken-r ...

Concealing two out of three div elements inside a specified id container using jQuery

I have encountered an issue with my structure, which looks like this: http://jsfiddle.net/NEFhF/3/ This is how it should work: When I click on the "id contacts", the "field body" and the "field foot" should be hidden. However, the id and the field head b ...

jquery button returned to its default state

Jquery Form Field Generator |S.No|Name|Button1|Button2| When the first button is clicked, the S.No label and name label should become editable like a textbox. It works perfectly, but if I click the second button, the field becomes editable as expected, ...

Encountered a Node.js build error related to a Java module

Encountering issues while attempting to integrate the JAVA module into my NodeJS application on Ubuntu: NodeJS: v6.2.0 NPM: 3.8.9 Node-gyp: v3.3.1 Python: 2.7.12 GCC: 5.4.0 Despite having all the required dependencies, I consistently face errors when ...

What is the process for verifying a checkbox after it has been selected?

I simplified my code to make it easier to understand const [factor, setfactor] = useState(1); const [nullify, setNullify] = useState(1); const Price = 10; const Bonus = 15; const finalPrice = (Price * factor - Bonus) * nullify; // start ...

Attempting to format a number using a computed property and .toLocaleString() fails to execute

I am facing an issue with the formatting of a number displayed in a <p></p> element. The number is coming from a range input element that is bound to an amount data property using v-model. Even though I have a computed property to format the nu ...

Saving the author of a message from one function and transferring it to another

I'm currently working on a Discord bot that manages tickets as applications. I've almost completed it, but I want the bot to log the closed ticket when the -close command is used. I've experimented with different approaches, such as using a ...

Error in Typescript: Attempting to access the property 'set' of an undefined value

Currently, I am in the process of setting up a basic example of push notifications on Android using Nativescript and Typescript. Although my code may seem a bit messy, I am struggling with properly rewriting "var Observable = require("data/observable");" a ...