Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs: angular-phonecat tutorial app fails first unit test

Just starting to learn Angularjs & unit-testing with jasmine...

Following tutorial on http://docs.angularjs.org/tutorial/step_02 to find that the very first unit test (which should pass because scope.phones.length is 3) fails.

INFO [karma]: Karma v0.10.2 server started at http://localhost:9876/
INFO [launcher]: Starting browser Chrome
INFO [Chrome 30.0.1599 (Mac OS X 10.8.5)]: Connected on socket BdjA1lVT9OOo8kgQKLYs
Chrome 30.0.1599 (Mac OS X 10.8.5) PhoneCat controllers PhoneListCtrl should create "phones" model with 3 phones FAILED
    ReferenceError: PhoneListCtrl is not defined
        at null.<anonymous> (/Applications/MAMP/htdocs/angular-phonecat/test/unit/controllersSpec.js:12:22)
Chrome 30.0.1599 (Mac OS X 10.8.5): Executed 2 of 2 (1 FAILED) (0.37 secs / 0.033 secs)

So basically, it is stating that PhoneListCtrl is not defined. However the app is working perfectly, and I don't really know where to start considering I am at the beginning of the tutorial!

Here is my unit test which is the default from the tutorial.

test/unit/controllerSpec.js

'use strict';

/* jasmine specs for controllers go here */
describe('PhoneCat controllers', function() {

  describe('PhoneListCtrl', function(){

    beforeEach(module('phonecatApp'));

    it('should create "phones" model with 3 phones', function() {
      var scope = {},
          ctrl = new PhoneListCtrl(scope);

      expect(scope.phones.length).toBe(3);
    });

    it('should create "phones" model with 3 phones', inject(function($controller) {
      var scope = {},
          ctrl = $controller('PhoneListCtrl', {$scope:scope});

      expect(scope.phones.length).toBe(3);
    }));

  });
});

app/js/controller.js

'use strict';

/* Controllers */

var phonecatApp = angular.module('phonecatApp', []);

phonecatApp.controller('PhoneListCtrl', function PhoneListCtrl($scope) {
  $scope.phones = [
    {'name': 'Nexus S',
     'snippet': 'Fast just got faster with Nexus S.'},
    {'name': 'Motorola XOOM™ with Wi-Fi',
     'snippet': 'The Next, Next Generation tablet.'},
    {'name': 'MOTOROLA XOOM™',
     'snippet': 'The Next, Next Generation tablet.'}
  ];
  $scope.hello = "Hello World";
});

config/karma.conf.js http://pastebin.com/PPWjSmyJ

like image 671
Gravy Avatar asked Oct 03 '22 16:10

Gravy


1 Answers

You have 2 unit tests in the example (2 it blocks). They look like they are supposed to do the same thing, but only the second actually creates your controller.

When you defined the controller in angular, it is not a globally available object that you can initialise with new Controller(...). You must request it from angular.

Your second test (which seems to be passing) does this by injecting the $controller service which will do perform any actions needed to set up and request the controller.

inject(function($controller) { ... });

It then creates the controller using this service like so

var scope = {},
    ctrl = $controller('PhoneListCtrl', {$scope:scope});

In your first test you try to just use the PhoneListCtrl variable directly. As the error says, this doesn't exist unless you define a variable with that name in your function.


I have just noticed that failing test in the tutorial. This is specifically for if you have defined a controller on the global namespace. For example

function PhoneListCtrl($scope) {
  $scope.phones = [
    {'name': 'Nexus S',
     'snippet': 'Fast just got faster with Nexus S.'},
    {'name': 'Motorola XOOM™ with Wi-Fi',
     'snippet': 'The Next, Next Generation tablet.'},
    {'name': 'MOTOROLA XOOM™',
     'snippet': 'The Next, Next Generation tablet.'}
  ];
  $scope.hello = "Hello World";
};
phonecatApp.controller('PhoneListCtrl', PhoneListCtrl);

The test would then work because you have function defined globally that is used as a controller, so you are able to test it without paying attention to the fact it is a controller. This means if you try to use other services you will have to inject them yourself and perform any actions that $controller would do for you.

like image 174
Andyrooger Avatar answered Oct 19 '22 00:10

Andyrooger