andrew
andrew

Reputation: 255

AngularJS Karma test - Resolve object passed into controller is undefined when testing

We are using ui-router 0.2.10.

I am injecting a resolve object as a parameter into my controller, which is then setting a scope variable in the controller. It works perfectly on the app like so:

state provider

$stateProvider.state('myState', {
      resolve:{
         foo:  function(){
            return 'bar';
         },
      url: '/',
      templateUrl: 'index.html',
      controller: 'FooCtrl'
   })

controller

app.Controllers.controller('FooCtrl', ['$scope', '$state', 'foo',
    function ($scope, $state, $log, Zone, foo) {
        $scope.testVar = foo
        console.log($scope.testVar);
    }])

'Bar' is then logged to the console as expected in Chrome.

But when running tests using Karma, the resolve object is now undefined, which fails the test. Here is the test code:

describe('controllers', function(){

  var $rootScope, 
      $scope,
      $state

  beforeEach(module('app'))

  beforeEach(inject(function($injector) {
    $state = $injector.get('$state')
    $rootScope = $injector.get('$rootScope')
    $scope = $rootScope.$new()
    $controller = $injector.get('$controller')
  }))

  it('FooCtrl should exist', inject( function() {
    $state.go('myState')
    $rootScope.$apply()

    $controller = $controller('FooCtrl', {
      '$scope': $scope
    })
    $rootScope.$apply()

    assert.equal($scope.testVar, "bar", "these strings are equal")
  }))
})

This error is presented (the resolve object in my case is called resolvedRouteModels):

[$injector:unpr] Unknown provider: fooProvider <- foo
    http://errors.angularjs.org/1.3.0-build.2921+sha.02c0ed2/$injector/unpr?p0=fooProvider%20%3C-%20foo

Any help would be much appreciated, and please let me know if you have encountered this problem.

Upvotes: 6

Views: 2821

Answers (2)

mahad
mahad

Reputation: 111

my assumption is your Angular set up is perfect, if that's the case, you might want to test your code this way. I've used Jasmine 2 syntax.

describe('Foo Controller', function() {
    var  $scope, $state, controller, Zone, foo, $log;
    beforeEach(module('app'));

    beforeEach(inject(function($controller) {
        $scope = {};
        $state = {};
        $log = {};
        Zone = {};
        foo = {};
        controller = $controller;
    }));

    it('should log the value foo', function() {
        spyOn(console, 'log');
        controller('FooCtrl', { $scope, $state, $log, Zone, foo });
        expect($scope.testVar).toEqual({});
        expect(console.log).toHaveBeenCalledWith({});
    });

    it('should log the value foo', function() {
        spyOn(console, 'log');
        // You could change the value of foo i.e.
        foo = 'create more spies than fbi';
        controller('FooCtrl', { $scope, $state, $log, Zone, foo });
        expect($scope.testVar).toEqual('create more spies than fbi');
        expect(console.log).toHaveBeenCalledWith('create more spies than fbi');
    });

});

Once again I hope this helps. Peace.

Upvotes: 0

Sunil D.
Sunil D.

Reputation: 18193

When you instantiate your controller, Angular usually can figure out how to satisfy the controller's dependencies. In this case, it doesn't know about UI-Router's "resolve" functionality.

One way to address this is to supply this dependency yourself in the test, the same way you are passing in the scope to the controller:

var foo = 'bar'; // whatever
$controller = $controller('FooCtrl', {$scope: $scope, foo: foo} );

Note, you could also create a mock $state object and pass that into the controller the same way, if you wanted to incorporate that into your tests.

Upvotes: 11

Related Questions