Reuse angular mocks in Jasmine tests using $ provide
I want to reuse my mocks instead of installing them in every unit test that has them as a dependency. But it's hard for me to figure out how to enter them correctly.
Here's my attempt at installing a unit test, which of course fails because the ConfigServiceMockProvider doesn't exist.
describe('LoginService tests', function () {
var LoginService;
beforeEach(module('mocks'));
beforeEach(module('services.loginService', function ($provide, _ConfigServiceMock_) {
$provide.value("ConfigService", _ConfigServiceMock_);
/* instead of having to type e.g. everywhere ConfigService is used
* $provide.value("ConfigService", { 'foobar': function(){} });
*/
});
beforeEach(inject(function (_LoginService_) {
LoginService = _LoginService_;
});
}
ConfigServiceMock
angular.module('mocks').service('ConfigServiceMock', function() {
this.init = function(){};
this.getValue = function(){};
}
I understand that maybe ConfigServiceMock.js can make the window global object and therefore doesn't need to be loaded like that. But I believe there must be a better way.
source to share
Try something like this:
describe('Using externally defined mock', function() {
var ConfigServiceMock;
beforeEach(module('mocks'));
beforeEach(module('services.configService', function($provide) {
$provide.factory('ConfigService', function() {return ConfigServiceMock;});
}));
beforeEach(module('services.loginService'));
beforeEach(inject(function (_ConfigServiceMock_) {
ConfigServiceMock = _ConfigServiceMock_;
}));
// Do not combine this call with the one above
beforeEach(inject(function (_LoginService_) {
LoginService = _LoginService_;
}));
it('should have been given the mock', function() {
expect(ConfigServiceMock).toBeDefined('The mock should have been defined');
expect(LoginService.injectedService).toBeDefined('Something should have been injected');
expect(LoginService.injectedService).toBe(ConfigServiceMock, 'The thing injected should be the mock');
});
});
According to this answer, you should put all your calls on module
before all your calls on inject
.
This introduces the catch-22 bit because you must have a reference to your ConfigServiceMock (via inject
) in the spec before you can set it on the LoginService (done in the call module
)
The workaround is to set the angular factory function as a ConfigService dependency. This will make angular be lazy to load the service, and by this time you will have your ConfigServiceMock link.
source to share