16

I am using the Angular.js $httpBackend to test some services that wrap $http calls (this is in ngMock, not ngMockE2E).

It seems that things like expect and when are sensitive to the order of URL query parameters. E.g. if I do $httpBackend.when('POST','/apiCall?X=1&Y=2').respond(/* ... */) or $httpBackend.expectPOST('/apiCall?X=1&Y=2'), I get URL mismatches if I have Y=2&X=1 in the URL instead of X=1&Y=2.

I want to write my tests in such a way that the service being tested will be free to change the order of URL query string parameters without breaking the tests. I haven't been able to find anything to solve this in the $httpBackend documentation. What's the right way to do this?

Eugene Osovetsky
  • 6,443
  • 2
  • 38
  • 59

2 Answers2

9

angular will sort the keys of the params object used in conjunction with $http.

$http({
    url:"/myurl",
    method:"GET",
    params:{
       Y:1
       X:2
    }}); 

Angular will do the following effectively: Object.keys(myParams).sort() and append the keys in that order. which ends up being '/myurl?X=2&Y=1'

I would suggest consistently using query parameters not directly in the url, but instead in the parameter params: that angular will then process.

Another solution would be to use Regular Expressions in your tests, something like

$httpBackend.expectPOST(/\/myurl\?((X|Y)=\d{1,}&?){2}/) regexper

The fact that you can use RegExp's is really hard to spot since the documentation redesign, as the colors do not blend.

Community
  • 1
  • 1
calebboyd
  • 5,744
  • 2
  • 22
  • 32
  • Thanks - using params when doing the $http call seems promising, so I'll upvote, though I'm still hoping for an elegant solution purely on the testing side (using regexes seems like overkill here, not to mention severely affecting the readability of the test...) – Eugene Osovetsky Mar 13 '14 at 03:54
  • Yeah, I agree Regex's are not fun to read or [change](https://imgflip.com/i/7i79q) – calebboyd Mar 13 '14 at 14:42
  • Here's the relevant code that sorts the keys: https://github.com/angular/angular.js/blob/86c6be82e5508762912eb08e228410f5c1ed4d91/src/ng/http.js#L1055 – Elliot Winkler Sep 04 '14 at 21:57
7

you can use the $httpParamSerializer service to achieve this:

$httpParamSerializer({ param: 1, param2: 2 });

This will return you a matching stringified querystring matching angulars $http service with params.

raygerrard
  • 812
  • 11
  • 13