1
votes

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 .

2
Where is $controller bound?Davin Tryon
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?gjoris
Ah, I believe I understand what you mean. I'm passing the $controller now in the function inside the inject(). Still no luck, though :(gjoris
Yeah, that is what I meant.Davin Tryon

2 Answers

2
votes

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", {}).

0
votes

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.