How do I trigger a keyup/keydown event in an angularjs unit test?
Asked Answered
M

6

37

I want to unit test a directive that emulates a placeholder, where the input value is cleared only on keyup/down events.

Mayer answered 1/8, 2013 at 17:52 Comment(0)
M
35

You need to create an event programatically and trigger it. To do so including jQuery for unit tests is quite useful. For example, you could write a simple utility like this:

  var triggerKeyDown = function (element, keyCode) {
    var e = $.Event("keydown");
    e.which = keyCode;
    element.trigger(e);
  };

and then use it in your unit test like so:

triggerKeyDown(element, 13);

You can see this technique in action in the http://angular-ui.github.io/bootstrap/ project here: https://github.com/angular-ui/bootstrap/blob/master/src/typeahead/test/typeahead.spec.js

Disclaimer: let's be precise here: I'm not advocating using jQuery with AngularJS! I'm just saying that it is a useful DOM manipulation utility for writing tests interacting with the DOM.

To make the above code work without jQuery, change:

$.Event('keydown')

to:

angular.element.Event('keydown')
Montevideo answered 1/8, 2013 at 18:5 Comment(2)
The downside is that jQuery would easily replace the jQueryLite coming with angular. As there are actual functional differences, you are essentially testing a (slightly) different system by including it in your unit tests.Lorenzen
Is angular.element.Event still available? I'm getting undefined, and I can't see anything about it in the docs. docs.angularjs.org/api/ng/function/angular.elementTamtam
M
14

I had issues with using accepted answer. I found other soultion.

var e = new window.KeyboardEvent('keydown', {
  bubbles: true,
  cancelable: true,
  shiftKey: true
});

delete e.keyCode;
Object.defineProperty(e, 'keyCode', {'value': 27});

$document[0].dispatchEvent(e);

Working example can be found here

Marchpane answered 26/1, 2015 at 8:16 Comment(2)
I used this approache so +1 but it seems that it's not working within PhantomJS.Cloots
I'm using Chrome in my karma configuration, because PhantomJS doesn't support bindMarchpane
G
9

I got something like this working.

element.triggerHandler({type:"keydown", which:keyCode});
Gina answered 11/3, 2016 at 19:58 Comment(2)
Works for me as wellAsymptotic
triggerHandler is not a function, Agular 8.Borer
G
3

if you are using angular2, you can trigger any event by calling dispatchEvent(new Event('mousedown')) on HTMLElement instance. for example: Tested with angular 2.rc1

it('should ...', async(inject([TestComponentBuilder], (tcb:TestComponentBuilder) => {
return tcb.createAsync(TestComponent).then((fixture: ComponentFixture<any>) => {
  fixture.detectChanges();

  let com = fixture.componentInstance;

  /* query your component to select element*/
  let div:HTMLElement = fixture.nativeElement.querySelector('div');

 /* If you want to test @output you can subscribe to its event*/
  com.resizeTest.subscribe((x:any)=>{
    expect(x).toBe('someValue');
  });
  /* If you want to test some component internal you can register an event listener*/
  div.addEventListener('click',(x)=>{
    expect(x).toBe('someOtherValue');
  });
  /* if you want to trigger an event on selected HTMLElement*/
  div.dispatchEvent(new Event('mousedown'));
  /* For click events you can use this short form*/
  div.click();

  fixture.detectChanges();
});
Gules answered 22/6, 2016 at 0:54 Comment(1)
and how does this answer the question? How can you trigger the keyup/keydown events with dispatchEvent? new Event('keydown.esc') does not workBiak
B
2

I recently wanted to test this HostListener on a component (Angular 2):

  @HostListener('keydown.esc') onEsc() {
    this.componentCloseFn();
  };

And after searching for some time, this is working:

..
nativeElement.dispatchEvent(new KeyboardEvent('keydown', {'key': 'Escape'}));
...
Biak answered 1/12, 2017 at 13:37 Comment(0)
A
0
it('should call listenToModalCloseEvent', fakeAsync(() => {
  spyOn(component, 'closeDropDownMenu').and.callThrough();
  const keyboardEvent = new KeyboardEvent('keydown', {
    'key': 'Escape'
  });
  document.dispatchEvent(keyboardEvent);
  fixture.detectChanges();
  expect(component.closeDropDownMenu).toHaveBeenCalled();
}));
Aldehyde answered 14/4, 2023 at 18:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.