How to test a directive's controller using angularJS-karma-jasmine?
angularjs, angularjs-directive, jasmine, javascript, karma-jasmine
Solution
Compile the element, and after calling `$digest()`, you will have access to the scope which contains `carousel` object with `awesomeThings` array:
describe('waCarousel Unit', function() {
var scope;
beforeEach(module('carouselApp'));
beforeEach(inject(function($rootScope, $compile) {
var element = '<test></test>';
scope = $rootScope.$new();
element = $compile(element)(scope);
scope.$digest();
}));
it('should have a list of awesomeThings', function() {
expect(scope.carousel.awesomeThings.length).toBe(3);
});
});
Also, here are some useful links to testing directives in angular:
- Testing Directives
- Testing AngularJS directive controllers with Jasmine and Karma
- Introduction to Unit Test: Directives
Problem
Goal: Write a passing test for the `waCarousel` directive scope variable: `self.awesomeThings`. Expect this test pass when `self.awsomeThings.length.toBe(3)` to is true? Question: How can I properly write this test? rather how do I inject a directives controller? Directive: ``` angular.module('carouselApp') .directive('waCarousel', function() { return { templateUrl: '../../../views/carousel/wa.carousel.html', controller: function($scope) { var self = this; self.awesomeThings = [1, 2, 3]; return $scope.carousel = self; } } }); ``` Unit Test: ``` describe('waCarousel Unit', function() { // am I missing a $controller & namespace variable init? var $compile, $rootScope; // Load the myApp module, which contains the directive beforeEach(module('carouselApp')); // Store references to $rootScope and $compile and $controller // so they are available to all tests in this describe block beforeEach(inject(function(_$compile_, _$rootScope_, _$controller_){ // The injector unwraps the underscores (_) from around the parameter names when matching $compile = _$compile_; $rootScope = _$rootScope_; $controller = _$controller_; // WaCarouselCtrl = $controller('WaCarouselCtrl', { // $scope: scope // }); })); it('should have a list of awesomeThings', function() { // This wont pass expect(scope.awesomeThings.length).toBe(3); }); }); ``` This is how I would do it for a typical view and not directive: ``` describe('Controller: MainCtrl', function() { // load the controller's module beforeEach(module('carouselApp')); var MainCtrl, scope; // Initialize the controller and a mock scope beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); // !!*** this is how I would inject the typical controller of a view **!! // MainCtrl = $controller('MainCtrl', { $scope: scope }); })); it('should attach a list of awesomeThings to the scope', function() { expect(scope.awesomeThings.length).toBe(3); }); }); ``` How do I merge these two concepts so that I can expect `self.awesomeThings.length).toBe(3)`? UPDATE: