测试 AngularJs + Jasmine 时无法获取指令中的元素

Can not get element in directive while testing AngularJs + Jasmine

我有一个带有外部模板的 angularjs 指令。它运行良好,但我不能为它编写 jasmine 单元测试。 这是 plunker 复制的代码:http://plnkr.co/edit/JPOBm7?p=preview

我在同一个问题上的所有尝试都失败了。 Link 方法在 运行 单元测试时获取模板的 DOM 元素时崩溃。它说:TypeError: canvas is null in http://run.plnkr.co/YHHxxmSgCiQxjrjw/app.js (line 8)

我不知道如何让它发挥作用。请帮忙。

我的简化指令代码:

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 单元测试代码:

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);
    });

  });
});

此外,在 Plunker 上重现问题花了很长时间,但它仍然在 jasmine-html 上抛出 TypeError: createElement is not a function

好吧,我在这里找到了答案 Jasmine unit testing an element is not :hidden。我之前尝试过将指令元素添加到文档中,但没有成功。我唯一错过的是注入 $document 到测试范围。 document 没有它,对象不可用。

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]);
    });

  });
});

更新了 plunker http://plnkr.co/edit/JPOBm7?p=preview