I'm trying to mock a call to an external service from NodeJS express. I can't get axios-mock-adapter to intercept the actual axios call (http://api.openweathermap.org) and to return a mocked response. When the assert is done it fails because to values are different. The temperature from the call is the actual outside temperature and not the mocked one. Don't know if I'm totally off or if I'm to close to the solution that I cant see it. Kind of new to JavaScript and NodeJS.
Please Stackoverflow, you are my only help.
This is my code:
File to test:
WeatherTools.prototype.getWeather = new Promise(function(resolve, reject) {
axios.get(config.weather.openWeatherLocationURL, {
params: {
id: config.weather.openWeatherMapLocation,
APPID: config.weather.openWeatherMapApiKey,
units: config.weather.openWeatherUnit
}
}
).then(function(axiosResponse) {
resolve(axiosResponse.data);
}).catch(function(axiosError) {
reject(axiosError);
});
});
Test file:
const assert = require('assert');
const weatherTool = require('./weatertools');
const axios = require('axios');
let MockAdapter = require('axios-mock-adapter');
const TestData = require('./testData.js');
let mock = new MockAdapter(axios);
describe("Testing weather tools", () => {
beforeEach(function() {
mock
.onGet(config.weather.openWeatherLocationURL, {
params: {
id: config.weather.openWeatherMapLocation,
APPID: config.weather.openWeatherMapApiKey,
units: config.weather.openWeatherUnit
}
}).reply(200, TestData.location().mockedResponseData);
});
it('given a correct call to openWeather a valid response should be returned xxx', function(done) {
weatherTool.WeatherTools.getWeather.then(function(actual) {
assert.strictEqual(actual.temp.currentTemp, TestData.location().expected.temp.currentTemp);
done();
})
});
});
Config file:
config.weather.openWeatherMapApiKey = 'theSecretApiKeyOfMine';
config.weather.openWeatherMapLocation = '1234567';
config.weather.openWeatherUnit = 'metric';
config.weather.openWeatherLocationURL = 'http://api.openweathermap.org/data/2.5/weather';
The problem is in tested code. It's expected that
getWeather
member is a method that gets weather, while it's promise property. It doesn't get weather, it's actually weather. Since it'sprototype
property, it eagerly performs a request on class definition, i.e. as soon as the class is imported. This also means that data cannot be updated in future, even if there's a need to do this.Since the request is eagerly performed, it won't be affected by Axios mock.
getWeather
also uses promise construction antipattern;axios
already returns a promise, there's no need to construct another one withnew Promise
.It should be:
So it could be fetched like
weatherToolsInstance.getWeather().then(...)
. It's expected that it will be mocked withaxios-mock-adapter
when used like that.