32

See here for example: http://www.johnpapa.net/angularjss-controller-as-and-the-vm-variable/

As the title suggests, I'm following along on this tutorial [http://tech.pro/tutorial/1473/getting-started-with-angularjs-unit-testing] to setup unit testing and all is fine EXCEPT for the fact I can't seem to access the vm variable as my $scope.

dashboard.js

var controllerId = 'dashboard';
angular.module('app')
    .controller(controllerId, ['common', 'datacontext', dashboard]);


function dashboard(common, datacontext) {
    var getLogFn = common.logger.getLogFn;
    var log = getLogFn(controllerId);

    var vm = this;      
    vm.title = 'Dashboard';

dashboard.Spec.js

describe("app module", function() {
    beforeEach(module("app"));

    describe("dashboard", function() {
        var scope,
            controller;

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

        it("should assign Dashboard as title", function() {
            controller("dashboard", {
                $scope: scope
            });
            expect(scope.title).toBe("Dashboard");
        });
    });
});

What I've tried: it works (the test passes) when I name '$scope' directly in the controllers dependencies and set the "title" property to it. However, I'd like to keep the pattern as is.

I've also tried passing in $scope directly in dependencies and naming the controller parameter as "vm"...

Karmas failing test message is: Expected undefined to be 'Dashboard'

appreciate any help!

isherwood
  • 58,414
  • 16
  • 114
  • 157
proggrock
  • 3,239
  • 6
  • 36
  • 51

2 Answers2

58

Ah, obvious now...I can access the vm variable through making a reference to the controller that's created in the test:

 it("should assign Dashboard as title", function () {
       var vm = controller("dashboard", { $scope: scope });
       expect(vm.title).toBe("Dashboard");
    });
proggrock
  • 3,239
  • 6
  • 36
  • 51
  • 2
    why do you have to inject `$scope` to the controller in test when this is not required by the controller? I thought the whole idea of using ControllerAs is to stopping using scope? – Junaid Oct 20 '14 at 15:27
  • 1
    @Junaid you're correct but I think for unit test you have to be more explicit because you dont have scope inheirtant or $window. (which controllerAs syntax seems to use when you use console.log(this)) – Armeen Moon Oct 26 '14 at 16:10
  • I just managed to do this without the `$scope` variable. That is, in `beforeEach`, I did `controller = $controller`, and in the actual test I did `var vm = controller("dashboard")` -- no `$rootScope` or `$scope` anywhere – Tom Mar 04 '15 at 20:53
  • @Tom I did the exact same way as you described. However, I always got the error indicated that $scope is required. So, I have to do as `var vm = controller('dashboard', { $scope: {}});` – lvarayut Mar 31 '15 at 06:43
25

you can also do this:

it("should assign Dashboard as title", function () {
    var controller = controller("dashboard as vm", { $scope: scope });

    expect(scope.vm.title).toBe("Dashboard");
});
Kris Ivanov
  • 10,476
  • 1
  • 24
  • 35