DrakaSAN DrakaSAN - 4 months ago 50
Node.js Question

Prevent proxyquire to call original code?

I am trying to test around a mongoose model.

I use proxyquire to mock it integrally, but since the original file register the model, I get

OverwriteModelError: Cannot overwrite `EEG` model once compiled.


Since everything I need is already injected by proxyquire, how can I tell it to not load the model?

Code to test:

var mongoose = require('mongoose');

var db = {},
Test = require('./model/Test.js'),
config = require('./config.json');

var dbURL = config.medical.url,
dbName = config.medical.name;

function connect(callback) {
db = mongoose.createConnection(dbURL + dbName);
db.on('error', (err) => {
callback(err);
});
db.once('open', function () {
callback();
});
}

function save(data, callback) {
new Test({
data
}).save((err) => {
callback(err);
});
}

module.exports = {
connect: connect,
save: save
}


model/Test.js:

var mongoose = require('mongoose');

//Should not get called when proxyquired
module.exports = mongoose.model('Test', mongoose.Schema({
date: Date,
data: String
}));


test/test.js:

//...
describe('save', (done) => {
it('Expect to successfully save the Test', (done) => {
var stub = {
Test: function Test() {
this.save = (callback) => {
callback();
}
}
},
test = proxyquire('./../test.js', {
'./model/Test.js': stub.Test
});

test.save({data: 'data'}, (err) => {
try {
expect(err).to.not.be.ok;
done();
} catch(err) {
done(err);
}
});
});

it('Expect to throw any error raised', (done) => {
var stub = {
Test: function Test() {
this.save = (callback) => {
callback('ERROR');
}
}
},
//This line raise a error because Test is already compiled
test = proxyquire('./../test.js', {
'./model/Test.js': stub.Test
});

test.save({data: 'data'}, (err) => {
try {
expect(err).to.not.be.ok;
done();
} catch(err) {
done(err);
}
});
});
//...


A alternative method I found would be to proxyquire mongoose in Test, and mock it to prevent the registration, but it would be a lot of code, and I have other test where this model get called 4 or 5 layers deep, so proxyquiring every level would be really cumbersome, while I can mock the highers function.

Answer

Coming back after having found a workaround. I've put the model in a external file, then used this code for test/test.js:

        let stub = {
            mongoose: {
                model: () => {
                    return function Test() {
                        this.save = (callback) => {
                            callback();
                        }
                    }
                },
                Schema: () => {}
            }
        },
        test = proxyquire('./../model/Test.js', {
            'mongoose': stub.mongoose
        }),
        code = proxyquire('./../code.js', {
            'mongoose': mongoose,
            './model/Test.js': test
        });

Basically proxyquire the model to mock mongoose, then proxyquire the code and give it the mocked model.