CSchulz
CSchulz

Reputation: 11030

Why is a provider for a service in a test required (Unknown provider)?

I am trying to figure out, why my test tries to find a provider for my service.

beforeEach(function () {
    module('loggingModule', inject(function ($q, _loggingService_) {
        var deferred = $q.defer();
        var loggingService = _loggingService_;
        deferred.resolve('somevalue'); //  always resolved, you can do it from your spec

        // jasmine 2.0
        spyOn(loggingService, 'removeAndGetNext').and.returnValue(deferred.promise);
    }));
});

The loggingService is part of the loggingModule and registered as service there.

Calling my test fails with

Unknown provider: loggingServiceProvider <- loggingService

If I inject my service into a controller with constructor injection it works.

Why does the test need a provider?

Upvotes: 1

Views: 46

Answers (1)

Krzysztof Safjanowski
Krzysztof Safjanowski

Reputation: 7438

First setup Angular module with beforeEach(module('loggingModule')) than incject some dependencies beforeEach(inject(function() {})), like that:

angular.module('loggingModule', [])
  .service('loggingService', function($q) {
    this.methodUnderTest = function(attr) {
      return this.removeAndGetNext(attr)
    }
    this.removeAndGetNext = function() {
      // return $q.resolve('foo')
    }
  })

describe('Module `loggingModule`', function() {
  var loggingService
  var promise
  var $rootScope

  beforeEach(module('loggingModule'))

  beforeEach(inject(function($q, _loggingService_, _$rootScope_) {
    loggingService = _loggingService_
    $rootScope = _$rootScope_
    promise = $q.defer()
    spyOn(loggingService, 'removeAndGetNext').and.returnValue(promise.promise)
  }))

  it('.methodUnderTest() calls .removeAndGetNext()', function(done) {
    var mockArgument = 'some arguments'
    var mockResponse = 'some resolved value'

    loggingService.methodUnderTest(mockArgument).then(function(r) {
      expect(r).toBe(mockResponse)
      expect(loggingService.removeAndGetNext).toHaveBeenCalledWith(mockArgument)
      done()
    })
    
    promise.resolve(mockResponse)
    $rootScope.$apply()
  });
})
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-mocks.js"></script>

Upvotes: 1

Related Questions