Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: Mock object injected to controller trough router's resolve

I'm trying to test a controller that receives an object trough router's resolve:

app.js:

...
.when('/confirm', {
  templateUrl: 'views/confirm.html',
  controller: 'ConfirmCtrl',
  resolve: {
    order: function(Order) {
      return Order.current;
    }
  }
})
...

ConfirmCtrl.js:

angular.module('angularGeolocationApp').controller('ConfirmCtrl',
function($scope, order, ...) {

  $scope.order = order

  ...

});

My Test looks like this:

'use strict';

describe('Controller: ConfirmCtrl', function () {

  // load the controller's module
  beforeEach(module('angularGeolocationApp'));

  var ConfirmCtrl,
    scope;

  // Initialize the controller and a mock scope
  beforeEach(inject(function ($controller, $rootScope) {
    scope = $rootScope.$new();
    ConfirmCtrl = $controller('ConfirmCtrl', {
      $scope: scope
    });
  }));

  it('should get an order object', function () {
    expect(_.isObject(scope.order)).toBeTruthy();
  });

  ...
});

However first expectation fails:

PhantomJS 1.9.2 (Mac OS X) Controller: ConfirmCtrl should get an order object FAILED
    TypeError: Attempted to assign to readonly property.
        at workFn (/Users/jviotti/Projects/Temporal/angular/angular-geolocation/app/bower_components/angular-mocks/angular-mocks.js:2107)
    Expected false to be truthy.

My assumption is that as I'm unit testing the isolated controller, the router doesn't have a change to run the resolve function and assign the correct value.

Is there a way to mock that order dependency?

I know I can get rid of the resolve stuff and inject Order and instantiate $scope.order to Order.current in the controller itself, but I'd like to keep the resolve approach.

like image 596
jviotti Avatar asked Dec 13 '13 18:12

jviotti


1 Answers

Just put your own order into the constructor of the ctrl like this.

describe('Controller: ConfirmCtrl', function () {

  // load the controller's module
  beforeEach(module('angularGeolocationApp'));

  var ConfirmCtrl,
      scope,
      order


  // Initialize the controller and a mock scope
  beforeEach(inject(function ($controller, $rootScope) {
    order = {};
    scope = $rootScope.$new();
    ConfirmCtrl = $controller('ConfirmCtrl', {
      $scope: scope,
      order: order
    });
  }));

  it('should get an order object', function () {
    expect(_.isObject(scope.order)).toBeTruthy();
  });

  ...
});

regards

like image 179
kfis Avatar answered Sep 29 '22 20:09

kfis