ASergey
ASergey

Reputation: 298

Can not get element in directive while testing AngularJs + Jasmine

I've got an angularjs directive with external template. It works well but I can not write jasmine unit tests for it. Here is plunker reproduced code: http://plnkr.co/edit/JPOBm7?p=preview

All my tries failed on the same issue. Link method crashes on getting template's DOM element while running unit-test. It says: TypeError: canvas is null in http://run.plnkr.co/YHHxxmSgCiQxjrjw/app.js (line 8)

I have no idea how to make it work. Help, please.

My simplified directive code:

angular.module('app', [])
  .directive('canvasDirective', canvasDirective);

  function canvasDirective () {
    var link = function () {
      var canvas = document.getElementById('canvas'),
        context = canvas.getContext('2d'),
        testText = 'Test it!';

      canvas.width = 200;
      canvas.height = 200;

      context.fillStyle = '#cccccc';  
      context.fillRect(0, 0, canvas.width, canvas.height);

      context.font = 'bold 32px Arial';
      context.textAlign = 'center';
      context.fillStyle = 'white';

      context.fillText(testText, 100, 100);
      context.strokeText(testText, 100, 100);
    }

    return {
      restrict: 'A',
      link: link,
      templateUrl: 'canvas.html'
    }
  }

Jasmine unit-test code:

describe('Test directive with canvas', function() {
  var $compile, $scope, $templateCache, defaultData, validTemplate,
      html = '<div data-canvas-directive></div>',

      createDirective = function (data, template) {
        var elm;

        $scope.data = data || defaultData;
        elm = $compile(template || validTemplate)($scope);

        $scope.$digest();

        return elm;
      }

  beforeEach(module('app'));

  beforeEach(inject(function(_$compile_, _$rootScope_, _$templateCache_){
    $compile = _$compile_;
    $scope = _$rootScope_.$new();
    $templateCache = _$templateCache_;

    var template = $templateCache.put('canvas.html', html);
  }));

  describe('when created', function () {

    it('should render the expected output', function () {
      var element = createDirective(null, html);

      expect(element.find('canvas').length).toBe(1);
    });

  });
});

Besides, it took a very long time to reproduce issue on Plunker but it still throws TypeError: createElement is not a function on jasmine-html.

Upvotes: 2

Views: 6089

Answers (1)

ASergey
ASergey

Reputation: 298

Well, I've found my answer here Jasmine unit testing an element is not :hidden. I've tried to add directive element to document before, but it didn't work. The only thing I've missed was to inject $document to test scope. document object is not available without it.

describe('Test directive with canvas', function() {
  var $compile, $scope, $templateCache, $document, template,
      html = '<div data-canvas-directive></div>',
      canvasHtml = '<div class="canvas-wrapper"><canvas id="canvas"></canvas></div>';

  beforeEach(module('app'));

  beforeEach(inject(function(_$compile_, _$rootScope_, _$templateCache_, _$document_){
    $document = _$document_;
    $compile = _$compile_;
    $scope = _$rootScope_.$new();
    $templateCache = _$templateCache_;
    template = $templateCache.put('canvas.html', canvasHtml);
  }));

  var createDirective = function () {
    var elm = angular.element(html);

    $compile(elm)($scope);
    document.body.appendChild(elm[0]);
    $scope.$digest();

    return elm;
  };

  describe('when created', function () {

    it('should render the expected output', function () {
      var element = createDirective();

      expect(element.find('canvas').length).toBe(1);
      document.body.removeChild(element[0]);
    });

  });
});

Updated plunker http://plnkr.co/edit/JPOBm7?p=preview

Upvotes: 4

Related Questions