No-fuss hapi server testing
It can be a pain to get your hapi server into your tests, especially when using otherwise wonderful tools such as glue. Labbable makes this process very simple, and encourages the best practice of testing an initialized (but not started) hapi server.
Plugin dependencies are only enforced at the time of server initialization. This means code that relies on a plugin being present (typically by the after
callback of server.dependency(deps, after)
) will only run during initialization. And if there are any dependencies missing, those errors will surface only during initialization. Your server's caches will also be started and onPreStart
server extensions will run.
Should you so desire, labbable can also pass an uninitialized server into your tests using options for labbable.ready()
.
In this case the server is immediately available and can be placed in module.exports
. Registering the Labbable.plugin
hapi plugin adds a server decoration server.labbableReady()
that can be used in a test to guarantee the server is initialized.
const Hapi = require('hapi');
const Labbable = require('labbable');
// Step 1.
// Simply export your server
const server = module.exports = new Hapi.Server();
server.connection();
// Step 2.
// Register the labbable plugin plus any others
server.register([Labbable.plugin], (err) => {
if (err) {
throw err;
}
// Step 3.
// Initialize your server
server.initialize((err) => {
if (err) {
throw err;
}
// Don't continue to start server if module
// is being require()'d (likely in a test)
if (module.parent) {
return;
}
server.start((err) => {
if (err) {
throw err;
}
console.log('Server started');
});
});
});
const Code = require('code');
const Lab = require('lab');
const MyServer = require('../server.js');
const lab = exports.lab = Lab.script();
const describe = lab.describe;
const it = lab.it;
const expect = Code.expect;
describe('My server', () => {
const server = MyServer;
before((done) => {
// Callback fires once the server is initialized
// or immediately if the server is already initialized
server.labbableReady((err) => {
if (err) {
return done(err);
}
return done();
});
});
// server is now available to be tested
it('initializes.', (done) => {
// server.isInitialized() can be used to check the server's init state
expect(server.isInitialized()).to.equal(true);
done();
});
});
In this case the server is composed by glue then made available asynchronously, so it can't be exported as in the previous example.
Instead we export an instance lababble
of Labbable, then call labbable.using(server)
as soon as the server is available. The method labbable.ready()
can then be used in a test to get a hold of server
once it's initialized.
const Glue = require('glue');
const Labbable = require('labbable');
// Step 1.
// Make an instance of Labbable
// to which we can pass the server
const labbable = module.exports = new Labbable();
const manifest = {/* ... */};
Glue.compose(manifest, (err, server) => {
if (err) {
throw err;
}
// Step 2.
// Show the server to our instance of labbable
labbable.using(server);
// Step 3.
// Initialize your server
server.initialize((err) => {
if (err) {
throw err;
}
// Don't continue to start server if module
// is being require()'d (likely in a test)
if (module.parent) {
return;
}
server.start((err) => {
if (err) {
throw err;
}
console.log('Server started');
});
});
});
const Code = require('code');
const Lab = require('lab');
const LabbableServer = require('../server.js');
const lab = exports.lab = Lab.script();
const describe = lab.describe;
const it = lab.it;
const expect = Code.expect;
describe('My server', () => {
let server;
before((done) => {
// Callback fires once the server is initialized
// or immediately if the server is already initialized
LabbableServer.ready((err, srv) => {
if (err) {
return done(err);
}
server = srv;
return done();
});
});
// server is now available to be tested
it('initializes.', (done) => {
expect(server).to.exist();
// isInitialized() can be used to check the server's init state
expect(LabbableServer.isInitialized()).to.equal(true);
done();
});
});
The Labbable
object is the container used to conveniently obtain a hapi server.
Creates a new Labbable
object.
options
- an optional object with the following,server
- a hapi server. When passed, the labbable instance is immediately made aware ofserver
.defaultTimeout
- the number of milliseconds to wait (for theserver
to be made initialized and/or available) until a timeout error is raised. When set to0
orfalse
no timeout will be set. Defaults to2000
(2 seconds).
server
- a hapi server. Makes the labbable instance aware ofserver
.
The labbable instance should be made aware of the hapi server as soon as possible. If the labbable instance is already aware of a server, this will throw an error.
options
- an optional object with the following,immediate
- a boolean that whentrue
passes along theserver
as soon as it is available tolabbable
(typically by callinglabbable.using(server)
). By default, labbable will wait until the server is both available and also initialized.timeout
- a number in milliseconds, to override thedefaultTimeout
option specified in the constructor.
cb
- a callback with the signaturecb(err, srv)
,err
- an error (such as a timeout).srv
- the hapi server instance that has been made initialized and/or available.
When cb
is not passed labbable.ready()
returns a Promise
that resolves with srv
as described above, or rejects with err
as described above.
Returns true
when labbable
is aware of a hapi server (typically by calling labbable.using(server)
) that has been initialized, and false
otherwise.
This is a hapi plugin. It gives the server two server decorations that provide identical functionality to an instance of labbable.
This is identical to labbable.ready()
, where the root server is already made available to labbable
.
Returns true
if server
is initialized and false
otherwise.