Как ng-щелкнуть директиву A в тесте PhantomJS

Приложение создано Yeoman с генератором angular.

Директива:

angular.module('psApp').directive('scrollTop', function () {
  return {
    restrict: 'A',
    scope: true,
    template: '<a href="#" ng-click="click()" class="scroll-top"><span class="glyphicon glyphicon-arrow-up"></span> Back to top</a>',
    controller: ['$scope', '$element', '$document', function ($scope, $element, $document) {
      $scope.click = function () {
        $document.scrollTop(0, 500);
      };
    }]
  };
});

Контрольная работа:

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

  // load the directive's module
  beforeEach(module('psApp'));

  var scope, element;

  beforeEach(inject(function ($rootScope, $compile) {
    scope = $rootScope.$new();
    element = $compile('<div scroll-top></div>')(scope);
    scope.$apply();
  }));

  it('should have "Back to top" as text', inject(function () {
    expect(element.html()).toBe('<a href="#" ng-click="click()" class="scroll-top"><span class="glyphicon glyphicon-arrow-up"></span> Back to top</a>');
    expect(element.text()).toBe(' Back to top');
    element.click();
  }));
});

Ошибка:

PhantomJS 1.9.7 (Mac OS X) Директива: scrollTop должен иметь текст «Вверх» TypeError: «undefined» не является функцией (оценка «element.click()»)

Я не могу понять, где проблема. :( Пожалуйста, опубликуйте функциональный код.


person Thales P    schedule 28.08.2014    source источник
comment
возможный дубликат PhantomJS; щелкните элемент, так как принятый ответ очень похож на ответ, получивший наибольшее количество голосов.   -  person Artjom B.    schedule 18.09.2014


Ответы (3)


По какой-то причине в PhantomJS нет функции click(). Вот обходной путь:

//Need to create a cross browser click() function no .click() in PhantomJS
function click(el){
    var ev = document.createEvent('MouseEvent');
    ev.initMouseEvent(
        'click',
        true /* bubble */, true /* cancelable */,
        window, null,
        0, 0, 0, 0, /* coordinates */
        false, false, false, false, /* modifier keys */
        0 /*left*/, null
    );
    el.dispatchEvent(ev);
}

И вот как это использовать:

it('Should set the month when the month is changed', function(){
    var obj = element[0].getElementsByClassName('month_opt')[1];
    click(obj);
    expect(scope.dt.getMonth()).toEqual(1);
});
person MBielski    schedule 29.08.2014
comment
хорошо, я делаю это, но как я узнаю, что он был прокручен? Я пробовал использовать $window.scrollY до и после щелчка(); но он равен 0. Что не так? Ваше здоровье! - person Thales P; 31.08.2014
comment
Это совсем другой вопрос, на который у меня нет ответа. Извини. - person MBielski; 01.09.2014
comment
Ответ, вероятно, взят отсюда: stackoverflow.com/questions/15739263/phantomjs -щелчок по элементу - person Artjom B.; 18.09.2014
comment
Это возможно, но я не могу знать, так как получил это решение от коллеги за несколько месяцев до этого поста. - person MBielski; 18.09.2014

Это не недостаток PhantomJS, а известное ограничение пакета jqLite, входящего в состав AngularJS. В его классе элементов нет функции «щелчка»: https://docs.angularjs.org/api/ng/function/angular.element

Есть два альтернативных подхода к тестированию.

  1. Включите jQuery в свои тесты. Если включен jQuery, пакет jqLite автоматически заменяется полным пакетом jQuery, который имеет полную реализацию click(). Я понимаю, что это не идеально, так как ваше приложение предположительно не использует jQuery.
  2. Используйте функцию jqLite 'triggerHandler()' для вызова обработчика кликов. Но этот подход вызовет ваш обработчик с фиктивным событием; см. документацию для triggerHandler. Тестовый код будет выглядеть примерно так:

    element.triggerHandler('click');
    

    Поскольку триггерHandler не передает «настоящий» объект события, вам может потребоваться соответствующим образом скорректировать свои тесты.

person Mike Daly    schedule 17.09.2014
comment
Это очень хороший ответ. Он анализирует проблему и показывает два возможных решения. - person Artjom B.; 18.09.2014
comment
Очень интересно. Я должен попробовать это. - person MBielski; 18.09.2014

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

$scope.$$childHead.click(); // in test $$childHead is scope of your directive in application
...your assertions here

То, что вы хотите протестировать, щелчок по браузеру - это больше интеграционный тест, поскольку вы тестируете щелчок в браузере и ответ в директиве -> это больше работы, например, для Selenium.

person Slaven Tomac    schedule 10.03.2015