Austin
Austin

Reputation: 3080

Unit Test a AngularJS Directive's Controller (Karma, Chai, Mocha)

Having trouble reaching my directive's scope for a unit test. Getting generic compile errors when trying to run the unit test.

My app compiles (gulp) and runs fine, and I can unit test non-directive's just fine as well. I am just not sure how to get the test's to work with a directive, I am just trying other people's solutions with some educated guesses.

Main page's HTML and JS

<div company-modal="companyOptions" show-close="false"></div>

.

(function() {
    'use strict';

    angular
        .module('app')
        .controller('companyModalCtrl', ['$scope', selectionPage]);

        function selectionPage($scope) {
            $scope.companyOptions = {};
        }
})();

Here is the first portion of my directive (it is very big so just including the important-top part.

(function() {
  'use strict';

  angular
    .module('app')
    .directive('companyModal',
      companyModal
    );

  function companyModal() {
    return {
      restrict: 'A',
      replace: false,
      transclude: true,
      templateUrl: '/src/login/company.html',
      scope: {
        options: '=companyModal',
        showClose: '='
      },
      bindToController: true,
      controller: companySelection,
      controllerAs: 'csmvm'
    };
  }

  companySelection.$inject = ['$state'];

  function companySelection($state) {
    var csmvm = this;
    var url;
    csmvm.emailList = [];

Here is my attempt at the Unit Test

'use strict';

describe('Company', function () {

  var scope;
  var controller;
  var elem;

  beforeEach(module('app'));
  beforeEach(inject(function ($controller, $rootScope, $compile) {
    scope = $rootScope.$new();

    elem = angular.element('<div company-modal="companyOptions" show-close="false"></div>');
    $compile(elem)($rootScope);
    /* 
      controller = elem.controller('companyModal as csmvm');
      controller = $controller(controller, 
      {
        $scope : scope
      });
    */
    controller = $controller(elem.controller('companyModal as csmvm'), {
      $scope: scope
    });

    scope.csmvm.emailList.email = "[email protected]";

  }));

  describe('Invite', function () {
    it('should be an array for emailList', function () {
      expect(scope.csmvm.emailList).to.be.an('array');
    });

  });

});

My problem (and sorry being very undescriptive) is that I just keep getting run-time errors from the test. Such as:

Failed Tests: Company "before each" hook: workFn 18) the object { "message": "'undefined' is not an object (evaluating '(isArray(Type) : Type).prototype)".

And again, my app compiles (gulp) and runs fine, and I can unit test non-directive's just fine as well

Upvotes: 1

Views: 1198

Answers (1)

user1364910
user1364910

Reputation:

You need to run expectations towards the isolated scope of your directive.

Right now, scope is referring to the scope where the directive was compiled.

But your directive creates a new isolate scope, and you are not running expectations towards it.

Two ways of doing it:

function isolateScope (el) {
  return el.isolateScope();
}

/** or **/

var el, scope, isolateScope; 

beforeEach(inject(function ($compile, $rootScope) {
  scope = $rootScope.$new();
  el = $compile('<directive></directive>')(scope);
  scope.$digest();
  isolateScope = el.isolateScope();
});

With all of that said, I would remove the controller out of your directive spec suite and test that in isolation. It makes for far cleaner / modular unit tests. Try to break them up as best you can.

Upvotes: 1

Related Questions