I need to test my own angular provider, and I need to test it in both config and run phase to check that config methods work and that the instantiated provider is indeed configu
Just in case you'd like to have a minification-proof version of your provider, things become slightly more complicated.
Here is the provider code:
angular
.module('core.services')
.provider('storageService', [function () {
function isLocalStorageEnabled(window) {
return true;
}
this.$get = ['$window', 'chromeStorageService', 'html5StorageService',
function($window, chromeStorageService, html5StorageService) {
return isLocalStorageEnabled($window) ? html5StorageService : chromeStorageService;
}];
}]);
The test case:
describe('Storage.Provider', function() {
var chrome = {engine: 'chrome'};
var html5 = {engine: 'html5'};
var storageService, provider;
beforeEach(module('core.services'));
beforeEach(function () {
module(function (storageServiceProvider) {
provider = storageServiceProvider;
});
});
beforeEach(angular.mock.module(function($provide) {
$provide.value('html5StorageService', html5);
$provide.value('chromeStorageService', chrome);
}));
// the trick is here
beforeEach(inject(function($injector) {
storageService = $injector.invoke(provider.$get);
}));
it('should return Html5 storage service being run in a usual browser', function () {
expect(storageService).toBe(html5);
});
});
In this case $get is an array and you can't just call it as a usual function providing dependencies as arguments. The solution is to use $injector.invoke().
That's strange that most tutorials and samples miss this detail.
here is a little helper that properly encapsulates fetching providers, hence securing isolation between individual tests:
/**
* @description request a provider by name.
* IMPORTANT NOTE:
* 1) this function must be called before any calls to 'inject',
* because it itself calls 'module'.
* 2) the returned function must be called after any calls to 'module',
* because it itself calls 'inject'.
* @param {string} moduleName
* @param {string} providerName
* @returns {function} that returns the requested provider by calling 'inject'
* usage examples:
it('fetches a Provider in a "module" step and an "inject" step',
function() {
// 'module' step, no calls to 'inject' before this
var getProvider =
providerGetter('module.containing.provider', 'RequestedProvider');
// 'inject' step, no calls to 'module' after this
var requestedProvider = getProvider();
// done!
expect(requestedProvider.$get).toBeDefined();
});
*
it('also fetches a Provider in a single step', function() {
var requestedProvider =
providerGetter('module.containing.provider', 'RequestedProvider')();
expect(requestedProvider.$get).toBeDefined();
});
*/
function providerGetter(moduleName, providerName) {
var provider;
module(moduleName,
[providerName, function(Provider) { provider = Provider; }]);
return function() { inject(); return provider; }; // inject calls the above
}
It's actually a lot simpler than it would at first seem to test a provider in AngularJS:
describe('Testing a provider', function() {
var provider;
beforeEach(module('plunker', function( myServiceProvider ) {
provider = myServiceProvider;
}));
it('should return true on method call', inject(function () {
expect( provider.method() ).toBeTruthy();
}));
});
```
The proof is in the Plunker: http://plnkr.co/edit/UkltiSG8sW7ICb9YBZSH