Тестирование директивы angularjs, которая управляет DOM

Я совсем новичок в Карме, так что простите меня за глупый вопрос.

Я тестирую свою директиву, которая отличается двумя способами:

1 - Он условно изменяет шаблон на основе содержимого области и перекомпилирует элемент директивы внутри компоновщика.

var linker = function(scope, element, attrs) {
//...

var getTemplate = function(contentType) {
            var template = '';

            switch(contentType) {
            case 'canvas':
                template = '<div> stuff here </div>';
                break;
            case 'div':
                template = '<div> other stuff here </div>';
                break;
                //...
             }

            return template;
        };

var html = getTemplate(scope.content.uiType);
            var ae = angular.element(html);

            element.replaceWith(ae);
            $compile(ae)(scope);

}

2 — он использует jsplumb в компоновщике, чтобы усилить элемент директивы и установить некоторые конечные точки jsplumb:

// Inside the linker function

var outEndPoint = jsPlumb.addEndpoint (ae, { /* parameters */ }, AudioOutPoint);

Проблема возникает, когда вызывается jsPlumb.addEndpoint. При отладке библиотеки кажется, что в какой-то момент jsPlumb использует jQuery для возврата определенного элемента — того, который он создал — по id, по строкам $("#jsplumb-element");

jQuery, в свою очередь, выполняет эту строку:

elem = document.getElementById( match[2] );

и getElementById возвращает null (может быть, потому что нет настоящего DOM?). В этот момент возникает исключение, и все рушится.

Для ясности: если я установлю точку останова на этот оператор и сделаю document.getElementsByTagName('div'); в консоли, он вернет null.

Я использую Chrome для проверки этой директивы, и простой тестовый код выглядит так:

describe('Directive: hyPluginWindow', function () {

    beforeEach(module('hyacinthHostApp'));

    var element, $compile, scope;

    beforeEach(inject(function(_$compile_, $rootScope) {
        $compile = _$compile_;
        scope = $rootScope.$new();
    }));


  it('should set the right audioDestinations', inject(function () {

      scope.content = {
          name: "testElement",
          id: "testElement000",
          uiType: "canvas",
          audioIn: 0,
          audioOut: 1,
          audioSources: [],
          audioDestinations: []
      };

      var grandparent = angular.element('<div id="pluginArea"></div>');
      var parent =  angular.element('<div class="plugin"></div>');
      var element = angular.element('<div hy-plugin-window content="content"></div>');
      grandparent.append(parent);
      parent.append(element);
      debugger;
      element = $compile(element)(scope);

      expect(scope.audioDestinations.length).toBe(1);

  }));
});

Ожидаемая часть никогда не выполняется, потому что директива исключается, как только она связана. Обратите внимание, что в приложении этот код работает нормально (поэтому проблема заключается в тестовой директиве).

Что мне не хватает?


person janesconference    schedule 24.06.2013    source источник
comment
Прошу прощения за очевидное, но включили ли вы jquery в karma.config.js? Есть некоторая странность, которая может возникнуть в результате того, что jqlite маскирует отсутствие jQuery в тестах кармы.   -  person S McCrohan    schedule 25.06.2013
comment
Да. Если я отлажу всю партию и перейду к вызовам функций, инструменты разработчика введут код jquery. Проблема в том, что в DOM ничего нет. Если я установлю точку останова до того, как она сломается, и сделаю document.getElementsByTagName('div');, она вернет null.   -  person janesconference    schedule 25.06.2013
comment
Хм. В качестве альтернативы использованию getTemplate для условного выбора HTML-шаблона вы можете переместить этот переключатель в сам шаблон с помощью ng-switch. Карма, похоже, прекрасно справляется с этим, поэтому, если он все еще взорвется, вы, по крайней мере, будете знать, что ваша проблема где-то в другом месте.   -  person S McCrohan    schedule 25.06.2013


Ответы (1)


Добавьте элемент в DOM, в своем тесте сделайте что-то вроде:

grandparent.appendTo(document.body);

Кстати. плагин, который вы используете, не должен делать document.getElementsByTagName('div'), а должен делать element.find(...). Тогда вам не нужно добавлять его в DOM, что ускорит выполнение теста.

person Vojta    schedule 26.06.2013
comment
Насколько мне известно, jsPlumb выполняет $("#jsplumb-element");, что, в свою очередь, преобразуется в document.getElementById('jsplumb-element') внутри jQuery. document.getElementsByTagName('div') был примером оператора, который я использовал в консоли, чтобы продемонстрировать свою проблему. Ваша точка зрения остается в силе, я думаю. - person janesconference; 27.06.2013
comment
Да, выполнение $("#x"); - это то же самое - он ищет в документе, а не в корневом элементе. Дело в том, что если бы он искал в корневом элементе (используя .find() или что-то подобное), вам не нужно было бы добавлять его в DOM, чтобы заставить его работать... - person Vojta; 30.07.2013
comment
Если только jqLite, но все еще имеет дело со сторонней библиотекой, ищущей документ по идентификатору: $document.find('body').append(element); - person Michael Allan Jackson; 25.10.2013