Why is $provide only available in the 'angular.mock.module' function, and $q only available in the 'angular.mock.inject' function?
You can't use $provide
within the inject
function because the former registers providers for the latter to use. Take a look:
describe('...', function() { beforeEach(function() { module(function($provide) { $provide.constant('someValue', 'foobar'); }); inject(function(someValue) { var value = someValue; // will be 'foobar'; }); });});
You can though write your test this way:
describe('...', function() { var serviceMock; beforeEach(function() { serviceMock = { someMethod: function() { ... } }; module(function($provide) { $provide.value('service', serviceMock); }); inject(function(service) { ... }); });});
In fact, you don't even need to implement the mocked service before injecting it with $provide
:
beforeEach(function() { serviceMock = {}; module(function($provide) { $provide.value('service', serviceMock); }); inject(function(service) { ... });});it('tests something', function() { // Arrange serviceMock.someMethod = function() { ... } // Act // does something // Assert expect(...).toBe(...);});
Here's a Plunker script illustrating mostly of the above.
This worked for me when I had to wrap a service which used $q
and seems quite clean:
var _ServiceToTest_;beforeEach(function () { module('module.being.tested'); module(function ($provide) { $provide.factory('ServiceToMock', function ($q, $rootScope) { var service = ...; // use $q et al to heart's content return service; }); }); inject(function (_ServiceToTest_) { ServiceToTest = _ServiceToTest_; });});it('...', function () { /* code using ServiceToTest */ });
The trick was to use $provide.factory
instead of $provide.value
.