Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to trigger document level events from a jasmine test Angular 2/4

According to the Angular Testing documentation, to trigger the events from the tests, we use the triggerEventHandler() method on the debug element. This method takes the event name and the object. Now, this works if we are adding the events using the HostListener. For ex: @HostListener('mousemove', ['$event']) or to add a document level event, we do it something like this @HostListener('document:mousemove', ['$event']).

In my current directive implementation, as I cannot nest the HostListeners, I add the document level events using the document.addEventListener inside a HostListener.
Code is as follows:

@HostListener('mousedown', ['$event'])
callMouseDown(event){
  if (something) {
   document.addEventListener('mousemove', this.callMouseMove.bind(this));
  }
}

callMouseMove(event){
 // do some computations.
}

Now, I want to trigger the mousemove event which is added at the document level from my tests. The current implementation of triggerEventHandler() doesn't work, i.e., the listener is not fired in the test.

How can I get this to work? Could anyone help me with some guidance.

Edit: Added Test:

it('test spec', inject([MyService], (service: MyService) =>{
   x = [];
  //service calls the method
  service.evtEmit.subscribe(e => {
   x.push(e);
  });
  triggerEventHandler("mousedown", {pageX: 200, pageY: 300});
  triggerEventHandler("document:mousemove", {pageX: 250, pageY: 320});
  // the above statement won't work.
  expect(arr).toEqual({x:50, y: 20});
}));
like image 851
Angela Roux Avatar asked Aug 22 '17 18:08

Angela Roux


People also ask

How do you trigger event in Jasmine?

According to the Angular Testing documentation, to trigger the events from the tests, we use the triggerEventHandler() method on the debug element. This method takes the event name and the object . Now, this works if we are adding the events using the HostListener .

How do you test events in Jasmine?

import triggerEvent from 'trigger-event'; import component from './components/site-menu'; describe('triggering menu button', () => { let menuToggleSpy; beforeEach(() => { menuToggleSpy = jasmine. createSpy('event'); component(); }); it('dispatches menu. toggle event', () => { document.

Which method can be used to trigger data binding in an Angular CLI testing environment?

detectChanges: Angular change detection within a testdetectChanges() . The first test does so immediately, triggering data binding and propagation of the title property to the DOM element.


1 Answers

Seems like the similar problem which you have described is logged as the issue here on angular repo.

You can get the access of the directive with the component instance and can access the method (i.e., in your case it's the callMouseMove). The following way should work:

it('test spec', inject([MyService], (service: MyService) => {
   x = [];
  //service calls the method
  service.evtEmit.subscribe(e => {
   x.push(e);
  });
  triggerEventHandler("mousedown", {pageX: 200, pageY: 300});
  component.directive.callMouseMove({pageX: 250, pageY: 320});
  expect(arr).toEqual({x:50, y: 20});
}));

Hope this helps.

Update

I realized that my way doesn't work if you have private methods inside your directive. It is better to create custom events or in this case a mouse event programmatically and trigger the events either at document level or on the element itself. This method was mentioned by yurzui. Thanks to him.

Here's how you can do it:

function programmaticTrigger(eventType: string, evtObj: any) {
   let evt = new MouseEvent(eventType, evtObj);
   document.dispatchEvent(evt);
}

You can call this function from your spec as:

programmaticTrigger("mousemove", {clientX: 250, clientY: 320});

Note that, I am not passing pageX or pageY here in this case, because they are readonly but they are computed internally based on the clientX and clientY values.

If you want to create a custom event and pass in whatever values you want, you can do as follows:

function programmaticTrigger(eventType: string, evtObj: any) {
       let evt: any;
       evt = Event(eventType, evtObj);
       document.dispatchEvent(evt);
    }

Invoke it as follows:

programmaticTrigger("mousemove", {pageX: 250, pageY: 320});

Hope this helps.

like image 199
ShellZero Avatar answered Sep 23 '22 12:09

ShellZero