hapi.js

Cannot stub shared object from custom plugin for unit tests


I am using a custom plugin to share a few persistence methods between some hapi modules:

const Mongoose = require('mongoose');
const Promise = require('bluebird');    
const Models = require('./persistence/mongodb/models');
exports.register = (server, options, next) => {
    Mongoose.Promise = Promise;
    Mongoose.set('debug', 'true');
    const mongoConnectionUri = process.env.MONGO_URI || 
           'mongodb://localhost/foo';
    Mongoose.connect(mongoConnectionUri, { useMongoClient: true })
    .then(() => {
        // eslint-disable-next-line no-param-reassign
        server.app.db = Models;
    });

next();
};

It is accessed as such, and works fine:

module.exports.doSomething = async (request, reply) => {
    const Models = request.server.app.db;
    const data = await Models.persistenceMethod();
    reply(data);
}

However, I am struggling to mock persistenceMethod(). I tried with Sinon or monkey-patching:

test('retrieves data', async () => {
    server.app.db = {
        persistenceMethod: () =>
            // eslint-disable-next-line no-unused-vars
            new Promise((resolve, reject) => resolve({ foo: 'bar' }))
    };

    const expectedPayload = [ { foo: 'bar' } ];
    const response = await server.inject({'GET', '/api/getFoo'});
    const payload = response.payload;
    expect(response.statusCode).to.equal(200);
    expect(JSON.parse(payload)).to.deep.equal(expectedPayload);
});    

But it seems that server.app.db and request.server.app.db are two different objects altogether. I tried monkey-patching server.root.app.db as well, but to no avail.

Is there a way to stub the db object, or do I need to use proxyquire to inject a fake database plugin?


Solution

  • I still haven't found the solution to the original problem, but instead, I am injecting a mock database plugin using Glue:

    exports.register = (server, options, next) => {
    // eslint-disable-next-line no-param-reassign
    server.app.db = {
        persistenceMethod: () => new Promise((resolve, reject) => {
            resolve({foo: 'bar'});
        })};
        next();
    };
    

    I would prefer not touching the manifest for Glue, but it's the best I can do for now.