Join the Stack Overflow Community
Stack Overflow is a community of 6.6 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

All,

I have a unit test suite for a AngularJS controller that follows the pattern beforeEach():

var ResourcesCtrl,
    scope, rootScope, loc, ctrl;

  // Initialize the controller and a mock scope
  beforeEach(inject(function ($controller, $location) {
    scope = {};
    rootScope = {};
    loc = $location;
    ctrl = $controller;
    scope.instanceName = 'TestInstance';


    ResourcesCtrl = $controller('ResourcesCtrl', {
      $scope: scope,
      $rootScope: rootScope,
      $location: loc
    });
  }));

Then a bunch of it() blocks with assertions/expect that all work as expected.

Now what I need to do, in just one of the test cases I'm adding, is change the value of scope.instanceName; however, it appears that even if I change its value inside the it() test case, that's not reflected in the scope of the controller. I have tried instantiating the controller with a new scope inside the test case, but that hasn't worked either.

So my question is the following: how can I change/override variables that were passed to the controller in the beforeEach() setup?

share|improve this question
up vote 5 down vote accepted

The problem here is that the call to $controller occurs in the beforeEach using whatever scope variables are available to it at that time. You want to be able to change the scope variable before the controller is called. One option is to use an init function which is called in each spec so that you can control exactly when the controller gets called:

beforeEach(inject(function ($controller, $location) {
  scope = {};
  rootScope = {};
  loc = $location;
  ctrl = $controller;
  scope.instanceName = 'TestInstance';

  this.init = function() {
    ResourcesCtrl = $controller('ResourcesCtrl', {
      $scope: scope,
      $rootScope: rootScope,
      $location: loc
    });
  }
}));

...

it("should do something", function() {
  scope.instanceName = "NewName";
  this.init();
  ...
});

Note that this means that this.init must be called in every spec in the file.

share|improve this answer
    
I wanted to avoid calling stuff in each spec, but, seems to do the trick. Thanks. – rdodev Apr 5 '14 at 15:48
    
An alternative to having the init function in every spec is grouping it blocks together using describe. – trysis May 13 '15 at 17:35
    
Does this work if inside the Controller you are setting the value and you want to override that to a new value? I tried to override the value like in your example, but when the Controller initializes, it changes it back to the original value. – Aaron Lelevier Dec 27 '15 at 14:34
    
@AronYsidoro in that case, you will have to modify the scope after the controller is run. If you are testing a method that the controller adds to the scope, then that should work fine. Run the controller, change the value, run the method, and check the returned value. If you're testing some other aspect of the controller, it might get tricky, depending on what you're doing. – alexsanford1 Jan 4 '16 at 19:18

in your beforeEach add $rootScope to the parameter list and assign the following variables like this

scope = $rootScope.$new();
rootScope = $rootScope;

since they come from angular's $rootScope you can call $apply() if needed.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.