1

I have been fiddling around with AngularJS and Jasmine on my new project. I have rather extensive experience with Jasmine, but haven't used it in combination with AngularJS before. I'm trying to write a very very very simple unit test, but I haven't been able to get it working. I'm just doing a very simple test, based on the documentation:

describe("Controller tests", function () {

    describe("LoginController", function () {

        var scope = {};

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

        it("should prepare the login page", function () {
            scope.prepareLoginPage();
        });

    });

});

But, it's not working at all. The LoginController is a very basic function, nothing special about it at all. When I try the Jasmine HTML runner, I get the following output:

TypeError: Object [object Object] has no method 'apply'
TypeError: Object [object Object] has no method 'apply'
    at jasmine.Block.execute (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:1064:23)
    at jasmine.Queue.next_ (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2096:37)
    at jasmine.Queue.start (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2049:10)
    at jasmine.Spec.execute (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2376:16)
    at jasmine.Queue.next_ (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2096:37)
    at jasmine.Queue.start (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2049:10)
    at jasmine.Suite.execute (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2521:16)
    at jasmine.Queue.next_ (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2096:37)
    at jasmine.Queue.start (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2049:10)
    at jasmine.Suite.execute (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2521:16)
TypeError: Cannot call method 'prepareLoginPage' of undefined
TypeError: Cannot call method 'prepareLoginPage' of undefined
    at null.<anonymous> (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/angularjs/seabirds/controllersTest.js:18:29)
    at jasmine.Block.execute (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:1064:23)
    at jasmine.Queue.next_ (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2096:37)
    at jasmine.Queue.start (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2049:10)
    at jasmine.Spec.execute (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2376:16)
    at jasmine.Queue.next_ (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2096:37)
    at jasmine.Queue.start (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2049:10)
    at jasmine.Suite.execute (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2521:16)
    at jasmine.Queue.next_ (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2096:37)
    at jasmine.Queue.start (file:///Users/geroen_joris/Development/Source/LifeWatchINBO/SeaBirds/src/test/javascript/lib/jasmine-1.3.1/jasmine.js:2049:10)

The problem seems to lie in the beforeEach(), because the only syntax it will accept is:

beforeEach(function() { ... });

But even if I introduce this (which is contradictory to the AngularJS documentation), the controller and the scope still are not initialized. Anybody's got some pointers?

I am using Jasmine 1.3.1, and AngularJS 1.0.7 .

4
  • Where is $controller bound? Commented Aug 21, 2013 at 8:36
  • I made a mistake, passing the literal "LoginController', instead of the function (<insert facepalm moment>). Now, I'm passing the function to $controller ... but still not banana. @DavinTryon Could you elaborate on that? What do you mean, should I bind the $controller to a variable? Commented Aug 21, 2013 at 8:46
  • Ah, I believe I understand what you mean. I'm passing the $controller now in the function inside the inject(). Still no luck, though :( Commented Aug 21, 2013 at 8:55
  • Yeah, that is what I meant. Commented Aug 21, 2013 at 8:59

2 Answers 2

2

Clearly LoginController is not defined in the jasmine's specs scope. You should define you controller inside the application's module:

angular.module("myApp, []).controller("LoginController", function($scope) {});

..and instantiate it inside the spec with $controller("LoginController", {}).

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

4 Comments

Based on your suggestions, I made a few modifications: - in controllers.js I added these lines: var app = angular.module("seaBirds", [], function () {}); app.controller("LoginController", function ($scope, $http) { ... - in controllersTest.js var scope; var ctrl; beforeEach(angular.module("seaBirds")); beforeEach(inject(function ($rootScope, $controller) { scope = $rootScope.$new(); ctrl = $controller('LoginController', { $scope: scope, $http: {} }); })); But still no luck ...
Sorry for the horrible code, can't seem to format it correctly. But the LoginController is defined in the jasmine spec scope, it always has been.
Check this project github.com/9ci/angle-grinder/tree/master/app/scripts/… maybe it would give you an idea how the controllers should be defined and accessed in the jasmine's specs.
I haven't used CoffeeScript before, but as far as I can tell, you have the same setup as I have right now. Basicly: (1) you have a module definition; (2) you add a controller to that module; (3) you do a beforeEach(angular.module(<module name>); (4) you do an inject(...), where you instantiate the controller. As far as I can tell, our setup is exactly the same, albeit that I'm using "regular" JavaScript :) Damn, never thought I'd be this stuck, just writing a basic test ...
0

OK, I figured out what was going wrong. I was under the assumption that you could run the tests just like any other Jasmine tests, meaning: with the SpecRunner.html file.

This is, however, NOT true. You can only run AngularJS tests using Karma. While this may seem logical, I find it truly non logical, to be honest. The biggest point to make is that you even see that you are loading a JASMINE_ADAPTER (in your karma configuration file), which is basically overwriting parts of the Jasmine testing framework. To be quite honest, I find this a very bad solution, and expected differently from the AngularJS team. If you start overriding the internals of a framework the way they did, you are hacking your way towards a solution, which is not a road you want to go down in the long run.

I have been writing JS tests for some time now, and found Jasmine to be very lightweight, and easy to implement. One of my previous projects, we used KnockoutJS. I implemented Jasmine at the time, to be able to do TDD for JS. It was easy, and worked perfectly. So for this assignment, I opted to use AngularJS as a technology, since I was quite taken with the way it works, after fiddling around a little bit with it. I admit, I did not try to write unit tests, because they were all Jasmine based, and it seemed like a no-brainer. Important lesson learned, at my part.

Now, I need to install Node.JS, Karma and PhantomJS to be able to run these tests on our build server.

In my book, AngularJS just lost a lot of points. I'm even in doubt if the investment for the whole testing setup is worth the choice of the framework. I do admit, AngularJS is superior to a lot of its competition on many levels - but nothing, and really nothing, is as important as being able to write fully tested software, preferably TDD style. Oh yes, Karma seems to be the bomb, with all the automatic checking of directories and all that - but think about it: you need to drag in all of its dependencies (which are not trivial) to be able to use it. Pure Jasmine works out of the box, headless in a Maven build, with a minimal amount of configuration.

Hmpf. Not amused.

3 Comments

..this is really weird. In my projects I'm able to run jasmine specs form the console (via karma) and via jasmine spec runner without any problems. Definitely you have something wrong in the code.
@luacassus: nope, nothing wrong with the code. Can't be, I don't have any code, I just wrote a very basic test (with only the inject function). I can only run my AngularJS tests via Karma. Well, supposedly, if I'd load the JASMINE_ADAPTER into the SpecRunner.html, it might work - haven't tried that at this point, but I'm using Karma anyway. BTW: to finish it all up, this is also something to take into account with the Karma runner: stackoverflow.com/questions/14762605/… . Hooray for well documented solutions.
AngularJS was developed by Google. Of course they're not going to expand the documentation properly. There are a lot of extensions to AngularJS because the base code doesn't cover most of the things you'd like to do with it fluidly without a lot of extra base code. Take the Angular-UI-Grid, for instance. Tons of data, organized and presented beautifully, but still requiring a lot of backend work just to get cells/rows to be clickable...github.com/angular-ui/ui-grid/issues/2228#issuecomment-73802274. Still a work in progress...Thanks, C§

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.