Healforgreen
Healforgreen

Reputation: 579

Jasmine angular directive being compiled as an object

I am unit testing an Angular directive, and this test has worked in the past with Angular 1.4.9. I recently upgraded to 1.5.0, so I am thinking this problem/(unexpected result) may be due to angular-mocks.

describe('The buttonToggle directive', function() {
  var $compile,
    btElement = '<button-toggle></button-toggle>',
    compiledElement,
    btElementPath = 'button-toggle.html',
    $scope;

  beforeEach(inject(function(_$compile_, $templateCache, $rootScope) {
    $compile = _$compile_;
    $scope = $rootScope.$new();
    var template = $templateCache.get(btElementPath);
    $templateCache.put(btElementPath, template);
    var element = angular.element(btElement);
    compiledElement = $compile(element)($scope);
    console.log(compiledElement);
    $scope.$digest();
    console.log(compiledElement);
  }));

  it('should compile', function() {
    expect(compiledElement.html()).toContain('btn');
  });
});

compiledElement is just being put into an object. Here is the return value from console.log:

{0: <button-toggle class="ng-scope"></button-toggle>, length: 1}

I don't understand why this is happening. It should be compiled into the button-toggle.html contents.

EDIT: Forgot to inject the buttonToggle module in a beforeEach. Do I also need to main application module injected? If I insert it then I get an undefined is not an object (evaluation compiledElement.html).

The module injections:

beforeEach(module('ocapp.buttonToggle'));
beforeEach(module('ocapp'));

EDIT 2: I no longer think it's an angular-mocks version issue. My directive is depending upon a controller defined in a separate file, and it's not being resolved.

button-toggle.directive.js

(function() {
  'use strict';

  angular
    .module('ocapp.buttonToggle')
    .directive('buttonToggle', buttonToggle);

  function buttonToggle(ButtonToggleController) {
    return {
      restrict: 'E',
      templateUrl: 'app/button-toggle/button-toggle.html',
      replace: true,
      scope: {
        on: '='
      },
      controller: ButtonToggleController
    };
  }
})();

button-toggle.html is in the same directory as all of the other files used here, perhaps I don't need the extended path in teh templateUrl property?

EDIT 3: I've worked through all of the other problems and am back to square one.

button-toggle.directive.spec.js

describe('The buttonToggle directive', function() {
  var $compile,
    btElement = '<button-toggle></button-toggle>',
    compiledElement,
    btElementPath = 'app/button-toggle/button-toggle.html',
    $scope,
    $httpBackend;

  beforeEach(module('ocapp.buttonToggle'));
  //beforeEach(module('ocapp'));

  beforeEach(inject(function(_$compile_, $templateCache, $rootScope, $injector) {
    $compile = _$compile_;
    $scope = $rootScope.$new();
    $httpBackend = $injector.get('$httpBackend');
    $httpBackend.whenGET(btElementPath).respond(200, '');
    var template = $templateCache.get(btElementPath);
    $templateCache.put(btElementPath, template);
    var element = angular.element(btElement);
    compiledElement = $compile(element)($scope);
    console.log(compiledElement);
    $scope.$digest();
  }));

  it('should compile', function() {
    expect(compiledElement.html()).toContain('btn');
  });
});

See this question and accepted answer for how to define an external controller from the same module in a directive.

button-toggle.directive.js

(function() {
  'use strict';

  angular
    .module('ocapp.buttonToggle')
    .directive('buttonToggle', buttonToggle);

  function buttonToggle() {
    return {
      restrict: 'E',
      templateUrl: 'app/button-toggle/button-toggle.html',
      replace: true,
      scope: {
        on: '='
      },
      controller: 'ButtonToggleController'
    };
  }
})();

Upvotes: 2

Views: 771

Answers (1)

Healforgreen
Healforgreen

Reputation: 579

It turned out to not be an Angular version issue, but rather a missing dependency.

  1. Install karma-ng-html2js-preprocessor with npm.
  2. Edit karma.conf.js.
  3. Change directive's templateUrl to 'button-toggle.html'.
  4. Test should look like below.

karma.conf.js additions

preprocessors: {
   '**/*.html': ['ng-html2js']
},

ngHtml2JsPreprocessor: {
   stripPrefix: 'app/button-toggle/'
   moduleName: 'templates'
},

button-toggle.directive.spec.js

describe('The buttonToggle directive', function() {

  var $compile,
    btElement = '<button-toggle></button-toggle>',
    compiledElement,
    btElementPath = 'app/button-toggle/button-toggle.html',
    $scope,
    element;

  beforeEach(module('ocapp.buttonToggle'));
  beforeEach(module('templates'));

  beforeEach(inject(function(_$compile_, $templateCache, $rootScope) {
    $compile = _$compile_;
    $scope = $rootScope;
    var template = $templateCache.get(btElementPath);
    $templateCache.put(btElementPath, template);
    element = angular.element(btElement);
    compiledElement = $compile(element)($scope);
    $scope.$digest();
  }));

  it('should compile', function() {
    expect(compiledElement.html()).toContain('btn');
  });
});

Upvotes: 1

Related Questions