In an effort to be more Angular 2.0 like I've decided to eliminate defining a controller in the traditional way:
e.g.
return {
restrict: 'E',
controller: 'MyCtrl',
controllerAs: 'vm',
bindToController: true,
scope: {},
templateUrl: 'path/to/tempate.html'
}
Here we can see that the controller name is passed as a string meaning that we have something like this defined somewhere:
app.controller('MyCtrl', function(...));
In a traditional test I'd just inject $controller
service into the test to retrieve the MyCtrl
controller. But I've decided to do this:
return {
restrict: 'E',
controller: MyCtrl,
controllerAs: 'vm',
bindToController: true,
scope: {},
templateUrl: 'path/to/tempate.html'
}
Here the only difference is that what is being passed to the controller declaration is a function called MyCtrl. This seems all well and good but do you go about retrieving this controller and testing it?
I tried doing this:
var $compile, $rootScope, $httpBackend, element, ctrl;
beforeEach(module('app'));
beforeEach(function() {
inject(function(_$compile_, _$rootScope_, _$httpBackend_) {
$compile = _$compile_;
$rootScope = _$rootScope_.$new();
$httpBackend = _$httpBackend_;
element = $compile('<directive></directive>')($rootScope);
ctrl = element[0].controller;
});
});
But in the above I get undefined coming back for the controller. Has anyone else made this move to be more like Angular 2.0? What differences have had to be made when it comes to testing?
Thanks
P.S The idea of the change in syntax is to make it easy to upgrade to Angular 2.0 when the time comes for us to do it.
EDIT
I've spent the last day or two trying to retrieve the controller and the only way that works seems to be just passing the controller in the traditional way. Here's a list of the ways I've tried (see the comments to determine what each outputs)
(function() {
'use strict';
/*
This part is used just for testing the html rendered
*/
describe('flRequestPasswordReset template: ', function() {
var $compile, $rootScope, $templateCache, template, element, ctrl;
var path = 'templates/auth/fl-request-password-reset/fl-request-password-reset.html';
beforeEach(module('app'));
beforeEach(module(path));
beforeEach(inject(function(_$compile_, _$rootScope_, _$templateCache_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
$templateCache = _$templateCache_;
// Using nghtml2js to retrieve our templates
template = $templateCache.get(path);
element = angular.element(template);
$compile(element)($rootScope.$new());
$rootScope.$digest();
// $rootScope has a reference to vm which is what my
// controllerAs defines but only contains one of the variables
// This returns undefined
ctrl = element.controller('flRequestPasswordReset');
}));
it('should be defined', function() {
expect(element).toBeDefined();
});
});
describe('flRequestPasswordReset: template with controller: ', function() {
var $compile, $rootScope, $httpBackEnd, element, ctrl;
var path = '/templates/auth/fl-request-password-reset/fl-request-password-reset.html';
beforeEach(module('app'));
beforeEach(inject(function(_$compile_, _$rootScope_, _$templateCache_, _$httpBackend_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
$httpBackEnd = _$httpBackend_;
$httpBackEnd.expectGET(path).respond({});
element = angular.element('<fl-request-password-reset></fl-request-password-reset>');
$compile(element)($rootScope.$new());
$rootScope.$digest();
// Uses alternate name for directive but still doesn't get the
// controller
ctrl = element.controller('fl-request-password-reset');
}));
it('should be defined', function() {
expect(element).toBeDefined();
});
});
/*
This part is used for testing the functionality of the controller by itself
*/
xdescribe('flRequestPasswordReset: just controller', function() {
var scope, ctrl;
beforeEach(module('app'));
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope;
// Instantiate the controller without the directive
ctrl = $controller('FlRequestPasswordResetController', {$scope: scope, $element: null});
}));
it('should be defined', function() {
expect(true).toBe(true);
});
/*
This works because I moved the controller back to the old way
*/
});
}());
According to my understanding of this question under pkozlowski.opensource answer you can use pass the controller as a function only if you don't encapsulate it inside the directive. This way it's exposed globally. This is a bad thing as it pollutes the global namespace however he seems to suggest wrapping it up when the application is built.
Is my understanding of this correct?