I am experimenting with an express middleware that can either return next() or next("route")

After developing a middleware function that returns next() if a route's parameters are defined by queryItems, I came across a useful tool called node-mocks-http. However, it does not fake the next object. This led me to explore how this can be achieved. Below is an example where I manipulate the next callback and set my expect statement inside it.

middleware.hasOnlyQuery = function(queryItems){
  return function(req, res, next){
    if(typeof queryItems == "string") queryItems = [queryItems]
    if(_.hasOnly(req.query, queryItems)) return next()
    return next("route")
  }
}

Here are some tests for this functionality:

it("should only have shop query", function(done){
  var req = httpMocks.createRequest({
      method: 'GET',
      query: {
        foo: "bar"
      }
  });
  var res = httpMocks.createResponse()
  var fn = middleware.hasOnlyQuery(["foo"])(req, res, function(err){
    expect(err).to.equal()
    return done()
  })
})

it("should not only have shop query", function(done){
  var req = httpMocks.createRequest({
      method: 'GET',
      query: {
        foo: "bar",
        bar: "foo"
      }
  });
  var res = httpMocks.createResponse()
  var fn = middleware.hasOnlyQuery(["foo"])(req, res, function(err){
    expect(err).to.equal("route")
    return done()
  })
})

I'm curious if there is a simpler or more efficient way to achieve this. Perhaps converting it into a promise so that I can utilize chai-as-promised?

Note: You can find the custom underscore mixin here.

Answer №1

I'm a big fan of using Sinon for conducting tests like the ones shown below:

// Here is the first test code snippet
...
var res = httpMocks.createResponse()
var spy = sinon.spy();
middleware.hasOnlyQuery(["foo"])(req, res, spy);
expect(spy.calledWithExactly()).to.be.true;

// And here is the second test
...
expect(spy.calledWithExactly('route')).to.be.true;

Answer №2

To enhance the flow, consider implementing various responses that 'next' can trigger.

function executeNext(done){
  return function(err){
    expect(err).to.equal(undefined)
    return done()
  }
}

function proceedToRoute(done){
  return function(err){
    expect(err).to.equal("route")
    return done()
  }
}

function handleNextError(done){
  return function(err){
    expect(err).to.be.an('object')
    return done()
  }
}

This allows for concise usage in a single line of code

middleware.containsSpecificQueries(["foo", "bar"])(req, res, executeNext(done))

Answer №3

Transform the middleware into a promise for compatibility with express-promise-router.

middleware.hasOnlyQuery = function(queryItems){
  return function(req, res){
    if(typeof queryItems == "string") queryItems = [queryItems]
    if(_.hasOnly(req.query, queryItems)) return Promise.resolve('next')
    return Promise.resolve('route')
  }
}

The updated test using chai-as-promised and bluebird:

it("should trigger correct next callback", function(done){
  Promise.all([
    middleware.hasOnlyQuery(["foo"])(reqFoo, res).should.eventually.equal("next"),
    middleware.hasOnlyQuery(["foo", "bar"])(reqFoo, res).should.eventually.equal("route"),
    middleware.hasOnlyQuery(["foo", "alpha"])(reqFoo, res).should.eventually.equal("route"),
    middleware.hasOnlyQuery(["foo"])(reqFooBar, res).should.eventually.equal("route"),
    middleware.hasOnlyQuery(["foo", "bar"])(reqFooBar, res).should.eventually.equal("next"),
    middleware.hasOnlyQuery(["foo", "alpha"])(reqFooBar, res).should.eventually.equal("route")
  ]).then(function(){
    done()
  })
})

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

Include a novel item into the JSON string that is being received

Recently, I attempted to parse an incoming JSON string and insert a new object into it. The method I used looked like this: addSetting(category) { console.log(category.value); //Console.log = [{"meta":"","value":""}] category.value = JSON.parse(c ...

What is the best way to retrieve the innerHTML content of an anchor tag with Cheerio?

Looking to extract data from an HTML page, a simplified example is provided below. Upon running the code, I anticipate the output to be [ "foo", "baz", "quux", ] but instead encounter an error message stating "TypeError: anch ...

Enhance User Experience by Implementing Event Listeners for Changing Link Visibility Using mouseover and getElementsBy

I am new to JavaScript and struggling to find a solution. Despite searching online for fixes, none of the solutions I've found seem to work for me. I have spent hours troubleshooting the issue but I must be missing something crucial. Can someone plea ...

Utilizing MongoDB and Express to access collections within a controller

Is there a way to access the collection in the controller using mongodb and express? I came across this code snippet in the mongodb documentation db.getCollection("countries");, but how do you import the database name: db into a controller? serv ...

Condensed JQuery condition code for "if" statement

This piece of code is designed to sequentially display 10 questions and control the visibility of each question using the CSS class .hideme. It also sends metrics data to Google Analytics. Although it functions properly, I feel like the code is too leng ...

Oops! An error has occurred: The requested method 'val' cannot be called on an undefined object

I am struggling with this issue. This is the code that I am currently working on: http://jsfiddle.net/arunpjohny/Jfdbz/ $(function () { var lastQuery = null, lastResult = null, // new! autocomplete, processLocation = function ...

Load image in browser for future display in case of server disconnection

Incorporating AngularJS with HTML5 Server-Side Events (SSE) has allowed me to continuously update the data displayed on a webpage. One challenge I've encountered is managing the icon that represents the connection state to the server. My approach inv ...

Seeking a solution for resizing the Facebook plugin comments (fb-comments) using Angular when the window is resized

Is it possible to dynamically resize a Facebook plugin comment based on the window or browser size? I want the fb-comment div to automatically adjust its size to match the parent element when the browser window is resized. <div id="socialDiv" class="c ...

I encounter an error message stating "Cannot read property 'push' of undefined" when trying to add an item to a property within an interface

I have a model defined like this : export interface AddAlbumeModel { name: string; gener: string; signer: string; albumeProfile:any; albumPoster:any; tracks:TrackMode[]; } export interface TrackMode { trackNumber: number; ...

Create a spinner control on an HTML webpage with the help of JavaScript

I am attempting to create a spinner control on my webpage, and I have tried the following code: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.o ...

How can one generate an array containing all attributes found in the HTML of a website?

I have a project idea where I want to be able to input a hyperlink address and then get a list of attribute contents as the output. For instance, if I input a Netflix genre hyperlink for Adventure Movies, I'd like to receive a list with all the movie ...

Guide on Implementing jQuery Plugin with Vue, Webpack, and Typescript

I am currently exploring the integration of the jQuery Plugin Chosen into my vue.js/Webpack project with TypeScript. After some research, I discovered that it is recommended to encapsulate the plugin within a custom Vue component. To kick things off, I m ...

Updating row values in an Angular table

I have a reusable table with the [cellData]="row" attribute to populate each cell on the table (see sample table in the screenshot). My question is, how can we replace the null values on the template with "---" so that instead of displ ...

express/create-react-app Error: Request proxy failed due to connection reset (ECONNRESET)

After setting up a react app using create-react-app and an express server with express-generator, I encountered a peculiar issue. The react app is live on http://localhost:3000, while the express server runs on http://localhost:8080. Within my component, I ...

Reopen a Kendo UI dialog

Currently, I am utilizing Kendo UI, and my goal is to display a modal dialog when a button is clicked. The issue I am facing is that it works perfectly the first time around. However, upon closing the dialog and attempting to reopen it by clicking the butt ...

Retrieve class attributes within callback function

I have integrated the plugin from https://github.com/blinkmobile/cordova-plugin-sketch into my Ionic 3 project. One remaining crucial task is to extract the result from the callback functions so that I can continue working with it. Below is a snippet of ...

Combine the values of properties in an object

I have a JavaScript object that contains various properties with string values. I want to concatenate all the property values. Here's an example: tagsArray["1"] = "one"; tagsArray["2"] = "two"; tagsArray["Z"] = "zed"; result = "one,two,zed" To prov ...

displaying small images from cloud storage once login is verified

My experience with S3 is limited, but from what I understand, the browser requests an image, then the server has to establish a connection with S3 to retrieve the image similar to a file system. The stream is then obtained and sent to the browser. I'm ...

A concise way to write an else if statement in Javascript and jQuery

Is there a way to make this code more concise? It works perfectly fine, but it's too lengthy. Basically, the code involves two dropdown lists where the user selects options, and based on their selection, values appear in two textboxes. The catch is th ...

"Encountered an error: User.findAll function cannot be found

Here is the content of my user.js file: var sequelize = require('sequelize'); var bcrypt = require('bcrypt'); module.exports = function(sequelize, DataTypes) { const User = sequelize.define('users', { user_id: { ...