I'd like to override some values at test-time, specifically setting my retries for an http service to 1 (immediate failure, no retries). Our project uses node-config
. According to the docs I can override with NODE_CONFIG
env variable:
node myapp.js --NODE_CONFIG='{"Customer":{"dbConfig":{"host":"customerdb.prod"}}}'
Well I would prefer to do this in my test, but not for all tests. The code says that you can allow config mutations by setting ALLOW_CONFIG_MUTATIONS
.
process.env.ALLOW_CONFIG_MUTATIONS = "true";
const importFresh = require('import-fresh');
importFresh("config");
process.env.NODE_CONFIG = JSON.stringify({httpServices:{integration:{enrich: {retryInterval: 1, retries: 1}}}});
expect(process.env.NODE_CONFIG, 'NODE_CONFIG not set').to.exist();
expect(process.env.NODE_CONFIG, 'NODE_CONFIG not set').to.match(/retryInterval/);
expect(process.env.ALLOW_CONFIG_MUTATIONS, 'ALLOW_CONFIG_MUTATIONS not set').to.equal("true");
const testConfig = require("config");
console.dir(testConfig.get("httpServices.integration.enrich"));
expect(testConfig.get("httpServices.integration.enrich.retryInterval"), 'config value not set to 1').to.equal(1);
Result:
{ url: 'https://internal-**********',
retryInterval: 5000,
retries: 5 }
`Error: config value not set to 1: Expected 5000 to equal specified value: 1`
How do I get this override to work?
(expect is from Hapi.js Code library)
Create a config directory and add a config/default. json file to it. This will be the default config file and will contain all your default environment variables. We'll access it in our app by importing config and using the get method to access the variables.
The node configuration file (db2nodes. cfg), located in the instance owner's home directory, contains configuration information that tells the Db2 database system which servers participate in an instance of the partitioned database environment.
You can create an. env file in the application's root directory that contains key/value pairs defining the project's required environment variables.
config_data. An optional object that defines the class parameters to be used by nodes in the group.
I'm one of the maintainers of node-config
. Your bug is that you used require
the second time when you should have used importFresh
again.
Your first use of "importFresh()" does nothing different than require()
would, because it is the first use of require()
.
After setting some variables, you call require()
, which will return the copy of config
already generated and cached, ignoring the effects of the environment variables set.
You only needed to use importFresh()
once, where you currently use require()
. This will cause a "fresh" copy of the config object to be returned, as you expected.
Simply changing config
's property worked for me.
For example:
const config = require( 'config' );
config.httpServices.integration.enrich.retryInterval = 1;
// Do your tests...
UPD: Make sure that overrides are done before anyone calls the first config.get()
, because the config
object is made immutable as soon as any client uses the values via get()
.
Joining late, but other answers did not fit with the testing standard in my project, so here is what I came up with
Use mocks..
node-config uses a function get
to get the configuration values.
By mocking the function get
you can easily modify any configuration you see fit..
My personal favorite library is sinon
Here is an implementation of a mock with sinon
const config = require('config');
const sinon = require('sinon');
class MockConfig {
constructor () {
this.params = {};
this.sandbox = sinon.sandbox.create();
}
withConfValue (confKey, confValue) {
this.params.confValues[confKey] = confValue;
return this;
}
reset () {
this.params.confValues: {};
return this;
}
restore() {
this.sandbox.restore();
}
apply () {
this.restore(); // avoid duplicate wrapping
this.sandbox.stub(config, 'get').callsFake((configKey) => {
if (this.params.confValues.hasOwnProperty(configKey)) {
return this.params.confValues[configKey];
}
// not ideal.. however `wrappedMethod` approach did not work for me
// https://stackoverflow.com/a/57017971/1068746
return configKey
.split('.')
.reduce((result, item) => result[item], config)
});
}
}
const instance = new MockConfig();
MockConfig.instance = () => instance;
module.exports = MockConfig;
Usage would be
const mockConfig = require('./mock_config').instance();
...
beforeEach(function () {
mockConfig.reset().apply();
})
afterEach(function () {
mockConfig.reset().clear();
})
it('should do something') {
mockConfig.withConfValue('some_topic.some_field.property', someValue);
... rest of the test ...
}
The only assumption this approach makes is that you adhere to node-config way of reading the configuration (using the get
function) and not bypass it by accessing fields directly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With