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
getWeathermember is a method that gets weather, while it's promise property. It doesn't get weather, it's actually weather. Since it'sprototypeproperty, 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.
getWeatheralso uses promise construction antipattern;axiosalready 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-adapterwhen used like that.