Pass mock DOM event to directive handler without jQuery

17,388

Solution 1

At the current stable version of Angular, 1.3.14, you can do this without jQuery by passing the event as the first and only parameter of triggerHandler, so instead of what was suggested in the question

element.triggerHandler('dragstart', new Event('dragstart'));

you can write

element.triggerHandler(new Event('dragstart'));

To add a spy on the preventDefault function, as per the original question, you can do the following

var mockEvent; 

beforeEach(function() {
  mockEvent = new Event('dragstart');
  spyOn(mockEvent, 'preventDefault');
});

it('should call preventDefault', function () {
  element.triggerHandler(mockEvent);
  expect(mockEvent.preventDefault).toHaveBeenCalled();
});

You can see this working in this Plunker. You can alternatively just use a plain object with at least a type key, so in this case

mockEvent = {
  type: 'dragstart',
  preventDefault: jasmine.createSpy('preventdefault')
};

which can be seen working in this Plunker

I believe this was added to the 1.3 branch in this commit.

Solution 2

you may include jquery and create a jquery event object. this object can easly be passed:

beforeEach(function() {
  mockEvent = $.Event('dragstart');
  spyOn(mockEvent,'preventDefault');
});

it('should call preventDefault', function () {
  element.triggerHandler(mockEvent);
  expect(mockEvent.preventDefault).toHaveBeenCalled();
});

i have used this jquery version in your plunkr: //ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js

Share:
17,388
Michal Charemza
Author by

Michal Charemza

A full-stack software engineer with experience in AngularJS, in-browser audio and video processing, Python, PHP, C++, and dev-ops. I particularly enjoy bringing designs to life with excellent UX, creating pragmatic and appropriately engineered solutions, profiling code to eliminate bottlenecks, incremental refactoring, functional programming, and slicing up large projects for quick and continual feedback.

Updated on July 24, 2022

Comments

  • Michal Charemza
    Michal Charemza almost 2 years

    I have a very simple directive whose purpose is just to cancel the dragstart event:

    link: function(scope, element) {
      element.on('dragstart', function(e) {
        e.preventDefault();
      })
    }
    

    How can I test this in a Jasmine test? I have the following test that attempts to spy on an Event object, and pass it to the handler:

    var mockEvent; 
    
    beforeEach(function() {
      mockEvent = new Event('dragstart');
      spyOn(mockEvent,'preventDefault');
    });
    
    it('should call preventDefault', function () {
      element.triggerHandler('dragstart', mockEvent);
      expect(mockEvent.preventDefault).toHaveBeenCalled();
    });
    

    But the test fails. You can see this at this Plunker.. How can I test this (/refactor the directive to make it testable)?

    Edit: Ideally without including jQuery. Edit: changed tags

  • Michal Charemza
    Michal Charemza over 10 years
    I've added jQuery and changed the test at plnkr.co/edit/aRvgHQXPTCSvlXougxHX?p=preview , but the test is still failing.
  • michael
    michael over 10 years
    element.triggerHandler(mockEvent); not element.triggerHandler('dragstart' ,mockEvent);
  • Michal Charemza
    Michal Charemza over 10 years
    Ah, that works, including changing $.Event to new Event, as can be seen at plnkr.co/edit/2LrrEBjVjftXH5ueprLI?p=preview. Is there a way to do this without jQuery?
  • Nacho Coloma
    Nacho Coloma about 7 years
    Please edit your title or your answer to specify Angular. Others searching for vanilla JavaScript solutions are landing here.