BrokenEyes
BrokenEyes

Reputation: 322

Unit Test Multiple HTTP Requests

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

Answers (1)

BrokenEyes
BrokenEyes

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

Related Questions