testing express router with several different handlers

I have been testing my guard middleware and everything appears to be functioning correctly, but my expect statement is failing.

/// auth.test.js

const request = require('supertest');
const express = require('express');
const app = require('../../app');
const authMiddleware = require('./auth.middleware');

const mockRes = () => {
  const res = {};
  res.status = jest.fn().mockReturnValue(res);
  res.sendStatus = jest.fn().mockReturnValue(res);
  res.send = jest.fn().mockReturnValue(res);
  return res;
};

describe('Authorization', () => {
  const guardedRouter = express.Router();

  guardedRouter.get(
    '/guardedandauthenticated',
    [authMiddleware.authenticate, authMiddleware.authorize('admin')],
    (req, res, _next) => {
      console.log('seems to be working');
      res.status(200);
      console.log('res is 200000000');
    },
  );

  let accessToken = '';
  beforeAll(async () => {
    const res = await request(app).post('/auth/login').send({
      username: 'admin',
      password: 'admin',
    });
    expect(res.status).toBe(200);
    accessToken = res.body.accessToken;
  });


  it('should allow access to authorized roles', () => {
    const response = mockRes();
    // @ts-ignore
    guardedRouter.handle(
      {
        headers: { authorization: `Bearer ${accessToken}` },
        url: '/guardedandauthenticated',
        method: 'GET',
      },
      response,
    );
    // THIS EXPECTATION IS FAILED
    expect(response.status).toHaveBeenCalledWith(200);
  });
});

/// auth.middleware.js

module.exports.authorize = role => {
  return async (req, res, next) => {
    if (!req.user) {
      return res.status(403).send({
        message: 'Unauthorized! No token provided!',
      });
    }
    if (req.user.role === undefined) {
      const privileges = await userService.getUserPrivileges(req.user.id);
      req.user.role = privileges.map(f => f.privilege_name);
    }
    const userRoles = req.user.role;

    const rolesToCheck = Array.isArray(role) ? role : [role];
    if (!rolesToCheck.every(r => userRoles.includes(r))) {
      return res.status(403).send({
        message: `Unauthorized! Required privileges are: ${userRoles.toString()}`,
      });
    }
    return next();
  };
};

/// jest outcome

expect(jest.fn()).toHaveBeenCalledWith(...expected)

Expected: 200

Number of calls: 0

I have made some cleanups in the code, similar assertions are passing successfully, and the code appears to be operational. It's possible that the way I set up the router is incorrect, or maybe I'm missing something crucial. The console messages within the router are showing up in the jest output, indicating that it is functioning correctly. Thanks in Advance,

Answer №1

It turned out that the issue was related to Jest, where you need to explicitly inform Jest when your test is done.

  it('should allow access to authorized roles', async done => {
    const res = { statusCode: 100 };
    res.status = function (code) {
      res.statusCode = code;
      return res;
    };
    // @ts-ignore
    guardedRouter.handle(
      {
        headers: { authorization: `Bearer ${accessToken}` },
        url: '/guardedandauthenticated',
        method: 'GET',
      },
      res,
    );
    setTimeout(() => {
      done();
      expect(res.statusCode).toBe(200);
    }, 300);
  });

I added a done callback to the test case to check the value after the handler finishes execution. However, using a timer for this verification doesn't seem like the ideal solution. The problem lies in the fact that the handle function calls three functions, one of which is asynchronous, making it difficult to determine the correct outcome without setting a delay. I'm looking for a solution that doesn't rely on timers, so if anyone has any suggestions, please share them!

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

The nodemailer module in Node.js encountered an issue while trying to send an email, resulting

Looking to confirm registration, I want to send an email from my server (kimsufi). To accomplish this, I am utilizing nodemailer which can be found at https://github.com/andris9/Nodemailer Encountering the following error: Error occurred Sendmail exited ...

Troubleshooting: Why are my images not displaying in webpack and node.js setup?

My problem: I'm facing an issue with background images in my project. I have included two images and used file-loader to bundle them through webpack. While the images display correctly in the app during development using webpack-dev-server, they disap ...

Insert a JSX element into the body of a webpage using React JSX

Is there a way to dynamically add elements to the end of the body using vanilla JavaScript? const newRecipe = <div id = "container"> <div className="recipe App" id="four" onClick={this.toggleRecipeList.bind(this)}>{this.state.recipeName} < ...

Fetching information from WebMethod with Jquery Ajax in c#

I have a jQuery variable that contains the following values: var data = [['Vikas', 75], ['Sumit', 55], ['Rakesh', 96], ['Shivam', 123], ['Kapil', 34], ['Rana', 104]]; Now, according to my requir ...

Show a message on form submission rather than redirecting

I'm working on a simple sign-up form and I want to show a success message directly on the page instead of redirecting to another page after submission. Is it better to display the message as a pop-up, an alert, or just on the page itself? <form a ...

Manipulating object properties within an array through iteration

Here is the array I am working with: var data = [ {"firstname":"A","middlename":"B","lastname":"C"}, {"firstname":"L","middlename":"M","lastname":"N"}, {"firstname":"X","middlename":"Y","lastname":"Z"} ]; I need to update the values for all keys - firstn ...

AngularJS UI.Router ActiveState implemented with a dropdown menu feature

I am currently working on creating a menu with dropdown functionality for multiple links within my application. My goal is to have the dropdown menu display as "active" when one of the links below is active. I have managed to make either the link in the ...

Exploring Angular 4: Embracing the Power of Observables

I am currently working on a project that involves loading and selecting clients (not users, but more like customers). However, I have encountered an issue where I am unable to subscribe to the Observables being loaded in my component. Despite trying vario ...

Delete dynamic elements from an array once they are no longer present in the DOM

In this code snippet, I have implemented a button that adds a new object to both the document and an array. When you click on each object, it gets removed from the document. However, the challenge here is how can we also remove it from the array? You can ...

Utilizing null values within the map function in React JS

I am currently developing an application using React JS. The app displays a list of users along with the status of books (available, taken, or requested) for each user. However, I'm encountering an issue where even after filtering out the books based ...

Issue with popup display in React Big Calendar

I'm currently working on a calendar project using React-Big-Calendar, but I've run into an issue with the popup feature not functioning properly. <div className={styles.calendarContainer} style={{ height: "700px" }}> <C ...

Adding a border to dynamically generated content while excluding the outer borders using CSS - an easy guide

My current project involves establishing a grid system that dynamically populates content, resulting in an uncertain number of elements being created. At the moment, each element is placed within a flexbox container with 3 elements per row. If there are mo ...

Invoke the express function on the client using the callable method

When I'm listening on a local port with my browser, the following method will return Hello world. //Node app.get('/', (req,res)=>{ res.send('Hello world') }); I've successfully exported the app as a ca ...

What are the steps to connect to multiple databases with ExpressJS?

I have a server with 3 databases containing identical tables. The databases are named DB1, DB2, and DB3. When working with a specific database, I utilize the following code in app.js: var cnxDB = require('./routes/cnxDB'); app.post('/user ...

How to add a new row to a Kendo grid with a unique custom styling

I am looking for a way to insert new data into a Kendo grid, but I want the added row to have a custom class so that I can style it with a different background color. How can I achieve this? I have searched through all the documentation but couldn't f ...

Working with TypeScript to set a value for an object's field

I have two objects of the same model: interface Project { _id?: string title: string description: string goal: string tasks?: Task[] createdAt?: Date updatedAt?: Date } The first object contains all fields from the interface, while the secon ...

What is the best way to conceal a canvas or another item?

Within my main canvas, there are three smaller canvases and a text element. <canvas id="Background" width="350" height="300" style="border:6px solid black; position: absolute; left: 10px; top: 10px;"> </canvas> <canvas id="Canvas1" width ...

The jQuery ajax request was unsuccessful in connecting to the remote server

I've tried researching and troubleshooting, but I still can't figure out why the Ajax code is not functioning correctly. Here is my JavaScript code: $(document).ready(function(){ $("#tform").submit(function() { var varUserName ...

Format specific words or characters in a text input

In HTML, when I want to display strings in a Text Input or TextArea, I am looking for a way to have specific substrings render with a box around them. I envision these boxed substrings as being treated as a single entity, similar to how highlighting or tex ...

Error in Typescript: The property 'children' is not included in the type but is necessary in the 'CommonProps' type definition

Encountering this error for the first time, so please bear with me. While working on a project, I opened a file to make a change. However, instead of actually making any changes, I simply formatted the file using Prettier. Immediately after formatting, t ...