Ari Porad
Ari Porad

Reputation: 2922

How to test express config?

I've been trying to figure out how to test the configuration for an express server (ex. middleware, etc.). I haven't been able to find any examples, and I'm unsure if the best way to test it is to simply match the expected list of middleware to the actual list of middleware, do something else entirely, or even if it's just config that shouldn't be tested at all.

I should also add that I'm not as interested in how exactly to do it, but rather more in the higher level concept. But I'm using mocha and supertest if it helps.

EDIT: Sorry, I should have been more clear. I'm trying to test the file that adds & configures all the middleware. Not the middleware itself.

Upvotes: 0

Views: 485

Answers (1)

Rob Raisch
Rob Raisch

Reputation: 17357

It's not clear what you wish to test:

  • If you need to test an existing middleware plugin, most provide tests as part of their distribution. From the node-modules/MODULE-NAME directory, simply invoke npm test.

  • If you wish to test your own middleware, you'll need to write those tests yourself, perhaps using tests supplied in existing middleware as examples.

  • If you wish to test which middleware plugins are currently configured in express, there are none unless you explicitly add them in your express instance.

  • If you wish to test a request through the middleware chain, you can add your own middleware spies to the request chain where you need them.

And finally, if you wish to test express itself, there are ample tests in its test directory, as there are in most express middleware distributions, which is one of the selling points to node: all of its modules provide source for you to explore.

UPDATED

Thanks for the clarification.

Since express' app.use() will throw an exception if you call it with no arguments or pass it either an undefined argument or a null, you can be pretty sure any function you pass will be added to the middleware processing cascade.

So, assuming:

var express=require('express'),
    app=express(),
    undefinedVariable;

Calling any of:

app.use();
app.use(undefinedVariable);
app.use(null);

will fail with:

.../node-modules/express/lib/application.js:209
throw new TypeError('app.use() requires middleware functions');
      ^
TypeError: app.use() requires middleware functions
    at EventEmitter.use (.../node-modules/express/lib/application.js:209:11)
    at Object.<anonymous> (.../index.js:7:5)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:906:3

Now, if you really want to test if a middleware function has been added to the request processing cascade, you'll need to check for a known side-effect of calling that function, as in:

var util = require('util'),
    assert = require('assert'),
    express = require('express');

// define some helper functions

For the purposes of this explanation, we'll use this custom middleware to simulate a standard express middleware. (This function simply adds a new value to express' standard request object. This new value is the "side-effect" for which we will be testing.)

/**
 * Custom middleware that sets req.hasCustomMiddleware to true.
 *
 * @param {object} req - express-style request
 * @param {object} res - express-style response
 * @param {function} next - express middleware callback
 */
var customMiddleware = function(req,res,next){
  req.hasCustomMiddleware = true;
  next();
};

Next, this factory function will throw an exception (via assert) with the supplied msg if its test function does not return true. (We'll use this factory as a shorthand way to automatically create a type of testing middleware in a well-defined manner.)

/**
 * Creates a new middleware function that asserts test.
 *
 * @param {string} msg - msg to use if/when assertion fails
 * @param {function} test - function that tests for expected values.
 * @returns {Function}
 */
var middlewareAssertionFactory = function(msg, testFunc) {
  assert('string' === typeof msg && msg);
  assert('function' === typeof testFunc);
  return function(req, res, next) {
    assert(testFunc(req, res), util.format('"%s" middleware assertion failed', msg));
    next();
  };
};

Now we need a function to assure that the side-effect value in which we're interested exists and has the expected value.

/**
 * Test Function for expected value(s).
 *
 * @param {object} req - express-style request
 * @param {object} res - express-style response
 * @returns {boolean} - true if expected values exist
 */
var expectedValueTestFunction = function(req, res) {
  return 'object' === typeof req && (req.hasCustomMiddleware ? true : false);
};

Which we then use to create a middleware testing function by passing it to our middlewareAssertionFactory function.

var customMiddlewareTester = middlewareAssertionFactory('req.hasCustomMiddleware exists and is true', expectedValueTestFunction);

Finally we configure our express app to use our customMiddleware and customMiddlewareTester functions (which must be added in that order), add a simple default route and start our server.

// config express app

var app = express();

// add our custom middleware
app.use(customMiddleware);

// and our test for the expected side-effect
app.use(customMiddlewareTester);

// add a simple route

app.get('/', function(req, res) {
  res.send('hello world!');
});

// fire up a server

var server = app.listen(3000, function() {
  var addr = server.address();
  console.log('app listening at http://%s:%s', addr.address, addr.port);
});

With this server running, a request to http://localhost:3000/ will return

hello world!

But if we change our test function to return false to simulate the case where our expected value doesn't exist or does not have the expected value, as in:

var expectedValueTestFunction = function(req, res) {
  return false;
};

And make the same request, we'll see:

AssertionError: "req.hasCustomMiddleware exists and is true" middleware assertion failed
  at .../index.js:42:9
  at Layer.handle [as handle_request] (.../node_modules/express/lib/router/layer.js:95:5)
  at trim_prefix (.../node_modules/express/lib/router/index.js:312:13)
  at .../node_modules/express/lib/router/index.js:280:7
  at Function.process_params (.../node_modules/express/lib/router/index.js:330:12)
  at next (.../node_modules/express/lib/router/index.js:271:10)
  at customMiddleware (.../index.js:16:7)
  at Layer.handle [as handle_request] (.../node_modules/express/lib/router/layer.js:95:5)
  at trim_prefix (.../node_modules/express/lib/router/index.js:312:13)
  at .../node_modules/express/lib/router/index.js:280:7

Using this strategy, you should be able to construct tests for any express middleware that causes a change to either the standard request or response objects, which I believe include most (if not all) of them.

Upvotes: 1

Related Questions