1

I'm trying to write tests for some AngularJS code, but can't even get a hello world to run. Suppose my code looks like this:

var myApp = angular.module("myApp", [])

myApp.controller("MyCtrl", function ($scope) {
    $scope.hello = "world"
})

Then the angular docs here suggest that something like this (using jasmine) should work:

describe("my controller", function () {
    it("should say hello", function () {
        var $scope
        inject(function ($rootScope, $controller) {
            $scope = $rootScope.$new()
            $controller('MyCtrl', {$scope: $scope})
        })
        expect($scope.hello).toBe("world")
    }
}

Unfortunately, inject does not exist, and there are no hints in the docs as to where to get it. Thus the approach in the docs doesn't work.

Looking slightly farther afield, we find $injector, which can be created by angular.injector. From those docs, it's fairly clear that inject(f) should be $injector.invoke(f). So we stick this at the top of our code and make the change:

$injector = angular.injector(["myApp"])

Unfortunately, this gives the error "Uncaught Error: Unknown provider: $controllerProvider from myApp", which my google-fu seems unable to elucidate.

I had been using this ($injector) previously when I was only testing services, and it works perfectly. It is only when mixed with a controller definition that I get the error. It can handle the controller definition, or the $injector, but not both. To me this suggests some kind of priority conflict or double-initialization, but I can't figure it out.

So what does the "Unknown provider..." error mean, and how do I get my hello world controller test working? If someone can help sort me out, that would be great.

3
  • You have missed beforeEach(module('myApp')); in docs Commented Feb 1, 2014 at 19:39
  • Don't you forget to include an angular-mocks.js file which provide global module and inject functions? Commented Feb 1, 2014 at 19:40
  • @just-boris Thanks. They sure made that hard to find, but it solved the problem. Unfortunately it still doesn't work; I get "Uncaught TypeError: Object [object Object] has no method 'off'" from a line in angular-mocks.js Commented Feb 1, 2014 at 20:13

1 Answer 1

2

I created for you an skeleton you could use for that concrete controller.

describe('my controller', function() {
  var $scope;

  beforeEach(module('app'));

  beforeEach(inject(function($rootScope, $controller) {
    $scope = $rootScope.$new();
    $controller('MyCtrl', { $scope: $scope });
  }));

  it('should contain world', function() {
    expect($scope.hello).toBe('world');
  });

});

Before each test, you inject your app module and before each test, you creates a new scope and instantiates your controller. Then you just need to write as much tests as you need.

We create a new scope in every tests to have a fresh state. We don't want to modify some $scope in one test and then have another one failing because you modified your $scope earlier.

Plunker: http://plnkr.co/edit/4hHqdsvnVwyUhiezpdhW?p=preview

Write a comment if you have any question.

Sign up to request clarification or add additional context in comments.

3 Comments

You missed the part where we need angular-mocks.js. Otherwise, I did this, but now it gives me Uncaught TypeError: Object [object Object] has no method 'off', originating from line 1973 in angular-mocks: injector.get('$rootElement').off();. Do you know what that means?
Actually I am not missing it. It is in the plunker, just below angular. I need to see all your test, from your snippet I can't help you. I need more info.
Whoops, you are right. Sorry. Your code works for me, thank you. The issue I was getting looks like it was due to versioning: I had angular and angular-mocks from different versions. Works now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.