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

How can we enforce that the input consists of digits first, followed by a space, and then

Can regex (with javascript possibly) be used to mandate numbers, followed by a space, and then letters? I'm a bit lost on where to start with this... I understand that using an HTML5 pattern would work for this... [0-9]+[ ][a-zA-Z0-9]+ However, I ...

Is there a way to retrieve data from a servlet using jQuery without having to make a request?

Struggling with a specific scenario: Imagine having 2 jsp pages: page1 and page2 Upon clicking a button in page2, the button sends an ID to page1. Based on that ID, information is retrieved from the database and sent to a JavaScript file related to page ...

Maintaining the Readability of Promise Chains

Creating promise chains with arrays is a method I've become accustomed to. It's quite simple to follow along a chain of promises when each one fits neatly on its own line like so: myArray.map(x => convertX) .filter() .whatever() .etc() ...

Having trouble with Vue i18n and TypeScript: "The '$t' property is not recognized on the 'VueConstructor' type." Any suggestions on how to resolve this issue?

Within my project, some common functions are stored in separate .ts files. Is there a way to incorporate i18n in these cases? // for i18n import Vue from 'vue' declare module 'vue/types/vue' { interface VueConstructor { $t: an ...

A guide to verifying a user's age using JavaScript by collecting information from 3 separate input fields

On page load, only the year input is required for users to fill in. The user can enter their birth year first without providing the month and day. Currently, I have a function that checks if a person is over 16 years old by comparing their birth year with ...

Tips for restricting camera movement in threejs

Being new to working with threejs, I am struggling to set limits on the camera position within my scene. When using OrbitControls, I noticed that there are no restrictions on how far I can zoom in or out, which I would like to change. Ideally, I want the c ...

Is there a way to remove specific elements from an array without using jQuery?

I've recently started diving into Javascript, experimenting with Tampermonkey scripts for the past week. The webpage I'm currently working on features dynamic elements that appear randomly with each page load. Sometimes only one element like "he ...

Can curly braces be utilized in the style section of Vue.js?

Can I utilize curly braces in the style section of vue.js to set a value? For instance .container { background: url({{ image-url }}; color: {{ color-1 }} } ...

What is the optimal ranking system for learning in Mongodb using Node.js and Express? How can we best utilize these

1 - What is the recommended order for learning (Mongo db,Node.js,Express)? 2 - Is this platform compatible with both web and mobile devices? 3 - Can you explain the functionalities of the programs? 4 - I'm planning to integrate it into my Flutter m ...

The function findOne from Mongoose seems to be non-existent, all while utilizing the Passport library

Whenever I try to implement my local strategy using the passport lib, I keep encountering this error. TypeError: UserModel.findOne is not a function I've spent hours searching for a solution that addresses this issue but haven't been successful ...

Issue in Wordpress: ReferenceError - '$' is not defined

Currently utilizing WordPress and attempting to access the following code snippet. I am encountering an error on the last line }(jQuery)); (function($) { $(function () { // Slideshow 3 $("#slider3").responsiveSlides({ auto: true, pag ...

When triggering the event: Was anticipating a spy, however received a Function instead

Upon running my test, I encountered the following error message: Error: Unhandled Promise rejection: <toHaveBeenCalledWith> : Expected a spy, but received Function. it('should change the value of myComponent', () => { spyOn(component ...

NodeJS making seven successful Ajax requests

I'm delving into the world of JavaScript, NodeJS, and electron with a goal to create a presenter-app for remote control over powerpoint presentations. My setup involves an electron server structured like this: const electron = require('electron ...

Angular/JS - setTimeout function is triggered only upon the occurrence of a mouse click

I'm currently working on a website that calculates the shortest path between two points in a grid utilizing AngularJS. Although I have already implemented the algorithm and can display the colored path, I am facing an issue where the color changes ti ...

Encountering a 404 error when trying to navigate to the next route using the Link component

Having issues with my login route. I've added a Link to the login route inside a button tag in my Navbar component, but when I try to access the route, I'm getting a 404 error page. --app ----pages ------component --------Navbar.js ----- ...

Is there a way to display an alert using JavaScript that only appears once per day?

I've created a website that displays an alert to the user upon logging in. Currently, the alert is shown each time the user logs in, but I'm looking to make it display only once per day at initial page loading. How can I achieve this? Below i ...

Guide to implementing controllers in vuejs2

Hey there, I recently started using vuejs2 with a project that is based on laravel backend. In my vuejs2 project, I wrote the following code in the file routes.js export default new VueRouter({ routes: [{ path: '/test', component: ...

When properties are passed and then mapped, they become undefined

While I experience no errors when directly mapping the array, passing the same array through props results in an error stating "Cannot read property 'map' of undefined." Brands Array const brands = [ { key: 1, Name: "Nike", }, { ...

Creating with NodeJS

I'm encountering an issue where my code is not waiting for a response when trying to retrieve data from a database. The connection is fine and everything works well, but Express isn't patient enough for the data to come through. Despite trying v ...

The v-on handler is encountering an error: "ReferenceError: i18n is not defined"

I'm currently working on a Vue.js project to create a multi-language website, but I'm struggling with how to access and utilize the i18n constant. I've attempted using the eventBus approach, but it doesn't seem to be the right solution ...