Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I mock my config file for testing?

I have a Koa app I just started and I need to test something that grabs data from a config file.

I need to test with specific data, but I'm not sure how to modify what data the test receives from the config file.

Example:

app.js

var router = require('koa-router');
var config = require('./config.js');
var db     = require('./db.js');
var auth   = require('./auth');
var app    = require('koa')();

router.get('/', function *() {
  if(auth(this.req, config.credentials.secret)) { // Authenticates request based on a hash created using a shared secret
    this.body = "Request has been authenticated";
  }
});

app.use(router.routes());
app = module.exports = http.createServer(app.callback());

app.listen(3000);

appSpec.js

var request = require('supertest');
var app = require('../app.js');

describe('app', function() {
  it('should authenticate all requests against config shared secret', function() {
    var secret    = 'some_secret';
    var validHash = /* hash created from test secret and query */;

    request(app)
      .get('/')
      .query({query: 'some_query'})
      .query({hash: validHash})
      .expect(403, done);

  });
});

This spec will fail because the app will use the secret from the config file(empty string) instead of my test secret.

like image 537
Hal Carleton Avatar asked Feb 11 '16 21:02

Hal Carleton


2 Answers

Alright, I played around with some different ways to handle this.

The best option I found, for my particular use case, was proxyquire. It's an npm package that lets you override dependencies in any file that you require in your test suites.

So if I am testing this module:

./controllers/myController.js

var config = require('../config.js');

module.exports = function() {
 // Do some stuff
};

I would do something like this:

./test/controllers/myControllerSpec.js

var proxyquire = require('proxyquire');
var config = {
  credentials: {
    secret: 'my_secret'
  }
  // other fake config stuff
};
var myController = proxyquire('../../controllers/myController.js', {'../config.js', config});

describe('myController', function() {
  // TESTS
});

and this instance of myController will use my test config.

This won't work for end to end testing, unless the only place you import your config is the main app file.

like image 141
Hal Carleton Avatar answered Nov 19 '22 04:11

Hal Carleton


I use node-config for my config files and configuration loading based on machine or env variable.

You can specify your config in a variety of formats (.json, .js, yaml, etc.) Using the default settings, you need to create a config folder in your app root and a default.<format> with your default config.

To override that for testing you can create a test.<format> file in your config directory. When you set your NODE_ENV=test, then node-config will see load your default config file and then it will load your test config file and if there are any conflicts for the values, your test config file will override the values in your default file.

Here are the full docs for setting up Configuration Files in node-config

Below is an example using node-config with a .js config file format.

./config/default.js

module.exports = {
  credentials: {
    secret: ''
  }
}

./config/test.js

module.exports = {
  credentials: {
    secret: 'abcdef123456'
  }
}

app.js

var router = require('koa-router');
var config = require('config');
var db     = require('./db.js');
var auth   = require('./auth');
var app    = require('koa')();

var credentials = config.get('credentials');

router.get('/', function *() {
  if(auth(this.req, credentials.secret)) { // Authenticates request based on a hash created using a shared secret
    this.body = "Request has been authenticated";
  }
});

app.use(router.routes());
app = module.exports = http.createServer(app.callback());

app.listen(3000);
like image 5
peteb Avatar answered Nov 19 '22 06:11

peteb