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.

+3


source to share


1 answer


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.

+4


source







All Articles