Javascript Question

hapi.js Lab testing, server.js always returns 404 status

I'm in the process of evaluating hapi.js. All was going well until I started writing tests. Basically I'm trying to test the status code as the first step. however I cannot proceed further. Server.inject always returns 404. I tested the same code by running the server and sending http requests using fiddler ( an http request simulation tool like postman ). This is successful. I don't know what I'm doing wrong. I'm following the exact steps as in many tutorials online. The test code is as follows.

var Lab = require("lab");
var server = require("../server/index.js").server;
var lab = exports.lab = Lab.script();
var code = require("code");

lab.test("home", function (done) {
var options = {
method: "GET",
url: "/"
}
server.inject(options, function (response) {
var result = response.result;
code.expect(response.statusCode).to.equal(200);
done();
});
});


The assertion never seems to be passing successfully, I have made sure the routes are available.

EDIT: As Matt Harrison has correctly pointed out, I'm in fact loading the routes asynchronously.

How to test in these scenarios?

Answer

Everything looks ok with your test. To prove it, if you put this in your index.js file it should work:

var Hapi = require('hapi');
var server = new Hapi.Server();

server.connection({ port: 4000 });

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        reply('ok');
    }
});

exports.server = server;

Without seeing what's happening in your index.js file I can only make an educated guess. But here goes anyway…

One possibility is that you're adding the GET / route asynchronously and it isn't in the routing table when your test gets run. Why might this happen? Some plugins don't call the register callback immediately because they need time to set themselves up. If you're registering your routes in this callback they're not loaded when your test gets run. For example this will fail with 404 for your test:

var Hapi = require('hapi');
var server = new Hapi.Server();

server.connection({ port: 4000 });

var fakePlugin = function (server, options, next) {

    setTimeout(next, 500);
};

fakePlugin.attributes = { name: 'fake' };

server.register(fakePlugin, function (err) {

    server.route({
        method: 'GET',
        path: '/',
        handler: function (request, reply) {

            reply('ok');
        }
    });
});

exports.server = server;

SOLUTION:

To solve this issue, you just need to delay your tests until all plugins have finished loading. There's a few possible ways to do that. Here's one I like:

Add a before to your test that delays running tests until server emits a pluginsLoaded event:

...

lab.before(function (done) {

    server.on('pluginsLoaded', done);
});

...

And you just need to make sure you emit that in your index.js:

server.register(..., function (err) {

    server.route({
        ...
    });

    server.emit('pluginsLoaded');
});
Comments