Search code examples
javascriptangularjsphantomjsyeomanyeoman-generator-angular

How to ng-click an A directive in a PhantomJS test


App generated by Yeoman with angular-generator.

Directive:

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

Test:

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

Error:

PhantomJS 1.9.7 (Mac OS X) Directive: scrollTop should have "Back to top" as text TypeError: 'undefined' is not a function (evaluating 'element.click()')

I cannot understand where the problem is. :( Please post functional code.


Solution

  • For some reason PhantomJS does not have a click() function in it. Here is the workaround:

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

    And here is how to use it:

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