Reputation: 322
So in my factory I have a loop which requests HTTP calls and adds them to a promise array.
I then do a $q.all
on the result to build a model.
When I come to test this however I can't get HTTP to make all the calls, it only makes the last one, I need it to make all the calls and build the model.
Below is very cut down code, ( I use 7 dates, but wanted to keep things short)
Factory Code
function getLatestData(){
var dateArray= ['2017-09-21','2017-09-22']
for (i = 0; i < 2; i++) {
var url = 'data-server/date/[i]'
promises.push(getData(url)); // getData is a simple $http function call.
}
return $q.all(promises).then(function(response){
buildModel(reponse);
});
}
So when I come to test this, I've got something like (I did try a loop but that failed).
httpBackend.expectGET('data-server/date/2017-09-21' ).respond(mockData[0]);
httpBackend.expectGET('data-server/date/2017-09-22' ).respond(mockData[1]);
rootScope.$apply();
modelFactory.getLatestData().then(function(response){
expect(response).toEqual(mockModelData);
})
So I console.log the get URL and I see all the URL requests are the same, they don't seem to be updating which results in this error
Error: Unexpected request: GET 'data-server/date/2017-09-22'
Expected GET 'data-server/date/2017-09-21'
because it's always the last httpBackend.expectGET
that's taken.
What am I missing?
Upvotes: 1
Views: 1569
Reputation: 322
My problem was mocking. I left this out of my example because I thought it wasn't relevant and added complication, but to build the dates I used the momentJS Library.
so
var url = 'data-server/date/[i]'
is
var url = 'data-server/date/'+factory.getMoment().add(i,'d').format('YYYY-MM-DD');
The factory.getMoment is just a wrapper for moment, the idea being I could over ride this in the unit tests to provide me with a 'given' date object.
funciton getMoment(){
return moment();
}
Anyway in my tests, I had this
var mockDate = moment('2017-09-21');
spyOn(factory, 'getMoment').and.returnValue(moment('2017-09-21'));
httpBackend.expectGET('data-server/date/'+mockDate.format('YYYY-MM-DD').respond(mockData[0]);
httpBackend.expectGET('data-server/date/'+mockDate.add(1,'d').format('YYYY-MM-DD').respond(mockData[1]);
Thinking that each time this would be called, it would give me back this mock, guess I was wrong about that.
What I needed to do, as pointed out by a colleague, was to use jasmine's clock mock.
beforeEach(function () {
jasmine.clock().install();
})
afterEach(function () {
jasmine.clock().uninstall();
})
Then in my test I set up the date time with
mockDate = moment('2017-09-21'); // always use moment as JS date if badly broken and just can't be trusted!
jasmine.clock().mockDate(mockDate.toDate());
httpBackend.expectGET('data-server/date/'+moment().add(0, 'days').format("YYYY-MM-DD").respond(mockData[0]);;
httpBackend.expectGET('data-server/date/'+moment().add(1, 'days').format("YYYY-MM-DD").respond(mockData[1]);;
(the above is in a loop)
I've removed my spy and now I have the dates and requests working as I expected.
Hope this helps someone else who finds themselves scratching their head for days trying to figure out why their tests are not working!
Upvotes: 0