I am trying to do a simple mock of angular's $http with sinon in a Mocha test.
But my spy never has any results in it no matter what I try.
searchResource.typeAhead is my function under test. It calls $http based on its arguments and I want to make sure the request is correct.
searchResource.typeAhead returns a promise, but I tried putting the checking code in .then() and it never executes.
suite('Search Resource', function() {
var injector = angular.injector(['cannonball-client-search', 'cannonball-client-core']);
var searchResource = injector.get('SearchResource');
suite('#typeAhead()', function () {
setup(function () {
this.server = sinon.fakeServer.create();
this.server.respondWith('GET',
config.endpoints.search.typeAhead,
[200, {'Content-Type': 'application/json'}, '[{ "id": 12, "comment": "Hey there" }]']);
this.spyhttp = sinon.spy(injector.get('$http'));
});
teardown(function () {
this.server.restore();
});
test('positive', function (done) {
searchResource.typeAhead(
'expl',
[{entityType: 'itementity'}],
[{createdBy: 'Eric'}, {createdBy: 'Tal'}],
10
);
this.server.respond();
expect(this.spyhttp.calledWith({
method: 'get',
url: config.endpoints.search.typeAhead +
'?query=expl&filter=entityType:itementity&orfilter=createdBy:Eric&orfilter=createdBy:Tal&limit=10'
})).to.be.true();
done();
});
});
});
The problem lies outside of Sinon mocking.
If angular.injector
is used directly instead of suggested angular.mock.module
and angular.mock.inject
helpers, the one is on his own with it and his knowledge of Angular injector.
The obvious downside is that the injector won't be torn down automatically after each spec (while it would be when angular.mock.module
is used), so all nested specs operate on the same instance of Angular injector.
At this point
var searchResource = injector.get('SearchResource');
SearchResource
service instance was already injected with unmocked $http
, that's the end of the story. Even if it wouldn't, there's no chance that Angular will ever know that this.spyhttp
spy should be used instead of original $http
service. Its methods can be spied after the instantiation
sinon.spy($http, 'get');
but not $http
function itself.
The strategy for testing with angular.injector
may be
var $httpSpy;
var injector = angular.injector([
'cannonball-client-search',
'cannonball-client-core',
function ($provide) {
$provide.decorator('$http', function ($delegate) {
return ($httpSpy = sinon.spy($delegate));
});
}
]);
// injector.get('$http') === $httpSpy;
Notice that this will make Sinon spy on $http
function, not on its methods.
If the question is about how Angular mocks should be approached with Sinon, then it's as easy as that. Otherwise this may indicate an XY problem, and the other answer addresses it directly ($httpBackend
and the way $http
embraces it are there exactly to make the burden of mocking XMLHttpRequest requests non-existent).