Reputation: 4203
I'm trying to retrieve the controller via $scope in my jasmine test, but fail miserably. Anybody know why?
When using the controllerAs syntax, the controller object is put on the $scope object using the name specified in controllerAs. So by running the code below in a browser using ng-app='MyApp' to bootstrap to angular, I can use chrome-dev tools to locate and select the directive element, and type $0.scope().myDirCtrl
in the console. This does yield the controller object, so why can't I retrieve the controller object in my unit test?
Running the snippet below will kick off a standalone jasmine browser testing environment. The spec for the test is listed at the bottom of the snippet. The code I'm having issues with is this:
expect($scope.myDirCtrl).toBeDefined();
/* --------------------------------------
Source code
--------------------------------------*/
(function(angular) {
'use strict';
// Setup the template -----------------
angular.module('MyApp.tpls', [])
.run(['$templateCache', function($templateCache) {
$templateCache.put('partials/myDirective.html',
'<div>{{myDirCtrl.testValue}}</div>');
}]);
// Setup the app ----------------------
angular.module('MyApp', ['MyApp.tpls'])
.directive('myDirective', myDirective)
.controller('MyDirectiveController', MyDirectiveController);
function myDirective() {
return {
restrict : 'E',
templateUrl : 'partials/myDirective.html',
transclude : true,
controllerAs : 'myDirCtrl',
bindToController: true,
scope : {},
controller : 'MyDirectiveController'
};
}
MyDirectiveController.$inject = ['$scope'];
function MyDirectiveController($scope) {
var ctrl = this;
ctrl.testValue = 'Only a test';
}
})(angular);
/* --------------------------------------
Test specifications
--------------------------------------*/
(function (module) {
'use strict';
// Define the tests -------------------
describe('My directive test', function () {
var $compile, $rootScope, $scope;
beforeEach(module('MyApp'));
beforeEach(inject(function(_$compile_, _$rootScope_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
$scope = $rootScope.$new();
}));
it('scope should contain a controller reference', function () {
var element = $compile(angular.element('<my-directive></my-directive>'))($scope);
$scope.$digest();
expect($scope.myDirCtrl).toBeDefined();
});
});
})(module);
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/jasmine.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/jasmine.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/jasmine-html.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.3.4/boot.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular-mocks.js"></script>
Upvotes: 0
Views: 300
Reputation: 13309
The problem is that $scope
in your spec is not the same scope that is used in a MyDirectiveController
. Directive creates one more scope for a controller, which becomes a child of your spec scope. You should be able to check it with the help of Angular internal properties in your test:
it('scope should contain a controller reference', function () {
var element = $compile(angular.element('<my-directive></my-directive>'))($scope);
$scope.$digest();
// controller is actually in a child scope
console.log($scope.$$childHead.myDirCtrl);
expect($scope.myDirCtrl).toBeDefined();
});
But I would not suggest to rely on these private Angular properties like $$childHead
, because they are considered private and are not the part of public API. I think this Q/A AngularJS - Access to child scope could help you to resolve this issue.
Upvotes: 1