hapijs / glue

Server composer for hapi.js
Other
245 stars 62 forks source link

Testing a hapi service composed using glue #14

Closed olistic closed 9 years ago

olistic commented 9 years ago

When I wasn't using glue to compose the server, the way I tested my code was pretty straight-forward. I exported the Hapi server instance from the index.js file and then, in the test modules, I required it and used the server.inject method to test the endpoints of my API.

However, using glue my index turned into something like this, with the server instance being available asynchronously:

index.js:

var Glue = require('glue');
var manifest = require('./config/manifest.json');
var options = {
    relativeTo: process.cwd() + '/lib/modules'
};

Glue.compose(manifest, options, function (err, server) {
    server.start(function () {
        server.log('info', 'Server running at: ' + server.info.uri);
    });
};

So now, trying to figure out how may be the best way to export that server variable to make it accessible to the test modules, I've come up with this solution. I don't know if I'm doing the right thing, so I'm seeking advice:

index.js:

var Glue = require('glue');
var manifest = require('./config/manifest.json');
var options = {
    relativeTo: process.cwd() + '/lib/modules'
};

var compose = function (callback) {
    Glue.compose(manifest, options, function (err, server) {
        if (!module.parent) {
            server.start(function () {
                server.log('info', 'Server running at: ' + server.info.uri);
            });
        }

        if (typeof callback !== 'undefined') {
            callback(null, server);
        }
    });
};

// If this module is not being required by another one, compose the server.

if (!module.parent) {
    compose();
}

module.exports = compose;

Then the index.js would be required from the tests this way:

test/whatever.js:

var composedServer;

require('../')(function (err, server) {
    composedServer = server;
});

Any opinions would be very appreciated.

Thanks!

Matias

dstevensio commented 9 years ago

(not a glue or hapi contributor, just my 2 cents...)

If your endpoint functionality is all contained within the modules in lib/modules and your index.js literally just sets up the Glue compose work, I would avoid exporting/importing your server and instead replicate it in your tests. So your index.js would remain like so:

var Glue = require('glue');
var manifest = require('./config/manifest.json');
var options = {
    relativeTo: process.cwd() + '/lib/modules'
};

Glue.compose(manifest, options, function (err, server) {
    server.start(function () {
        server.log('info', 'Server running at: ' + server.info.uri);
    });
};

while your tests would be like this:

test/whatever.js:

var Glue = require('glue');
var manifest = require('../config/manifest.json');
var options = {
    relativeTo: process.cwd() + '/lib/modules'
};

Glue.compose(manifest, options, function (err, server) {
    server.start(function () {

      // tests here using server.inject as you did before

    });
};

That's assuming that there is no additional work happening in your index.js that you need to test. If you're just doing the calls to Glue there, the endpoints are being accurately tested in this method. It does add the overhead of changing references to the manifest in multiple places if changed in index.js so bear that in mind.

olistic commented 9 years ago

Yeah, my scenario is exactly as you described, so I will follow your advice and compose the server in the tests too. I think my index.js file has got a bit cluttered with my current solution, and it remains clearer with yours.

Thank you very much!

nakardo commented 9 years ago

I had the same issue recently, and composing the server inside a Promise worked well. It also gets along nicely with mocha by requiring it on the before hook.

oviava commented 8 years ago
Glue.compose(manifest, options, (err, server) => {
  if (!module.parent) {
    server.start(() => {
      console.log('Server started on port:', server.info.uri);
    });
  } else {
    module.exports = server;
  }
});

think this is the cheapest way

davidjamesstone commented 8 years ago

Sorry for reviving this thread.

Glue's compose callback is not executed asynchrouously. This is similar to Joi.validate.

This can be quite confusing at first (or was it just me?) given most error-first callbacks in nodejs are executed async.

Given this, I think oviava's comment above this is the simpliest way to go.

devinivy commented 8 years ago

I created a tool to specifically help with this: https://github.com/devinivy/labbable#with-glue

pintocarlos commented 7 years ago

The following article shows how to tests the plugins directly without having to depend on the server wrapped in the glue composer: http://ideasintosoftware.com/unit-testing-hapi-plugins/

I think this is by far the cleanest solution to testing your plugins, routes, and handler responses in a decoupled manner.

lock[bot] commented 4 years ago

This thread has been automatically locked due to inactivity. Please open a new issue for related bugs or questions following the new issue template instructions.