Angular2 + Jasmine Event Object
Asked Answered
R

2

1

I have this simple method which needs to be tested:

  public onLayerContainerClick(event: Event): void {
    event.stopPropagation();
    event.preventDefault();
    if (event.srcElement.classList.contains('dpm-info__layerContainer')) {
     this.closeInfoLayer(event);
    }
  }

My objective is actually to increase code coverage for the component. If I test is like this:

  it( 'should close on info container click', () => {
    spyOn( component, 'onLayerContainerClick' );
    const el: DebugElement = fixture.debugElement.query( By.css( '.dpm-info__layerContainer' ) );
    el.triggerEventHandler( 'click', null );
    expect( component.onLayerContainerClick ).toHaveBeenCalled();
  } );

the test is OK, but instanbul says "function not covered". So I guess, I need to call the function explicitly? To do that, I need to have a full event object, including (at least) srcTarget property. How do I define such an event within the unit test?

Ratiocinate answered 8/12, 2017 at 10:17 Comment(0)
D
3

You have to call the function with a mocked event in the test. component.onLayerContainerClick({ srcElement: { value: 'mock_value' } });

And then write what you expect

expect( component.closeInfoLayer ).toHaveBeenCalled();

Maybe this https://angular.io/guide/testing#triggereventhandler might help as well

Damask answered 8/12, 2017 at 10:25 Comment(5)
The challenge is the Typescript, which expects the argument passed in to onLayerContainerClick to be of type Event. Just passing an object with srcTarget property doesn't cut it - I get a type error.Ratiocinate
ok, can you post also the beforeEach at the beginning of each test ? btw, if you try component.onLayerContainerClick(<any>{ srcElement: { value: 'mock_value' } }); or <Event> do u get errors ?Damask
@Ratiocinate Not a challenge. The types are there to help you, not to create obstacles. You can pass any argument you need with <any>arg or <Event><any>arg.Locke
yes, for mocking input data it shouldn't be a problemDamask
Well, I am over the first hurdle, and am able to construct an object of type Event, just as you guys say. However (here we go), this line in the component event.srcElement.classList.contains expects classList to be of type DOMTokenList which has its own methods and properties (see here #29173015).Ratiocinate
R
1

Thanks to estus and DrNio I've come up with this test, which makes istanbul code coverage happy and doesn't have any type problems:

  it( 'should close on info container click', () => {
    spyOn( component, 'closeInfoLayer' );
    const el: HTMLElement = fixture.debugElement.query(By.css('.dpm-info__layerContainer')).nativeElement;
    const mockEvent: Event = <Event><any>{
      srcElement: {
        classList: el.classList
      },
      stopPropagation: <any>( ( e: any ) => { /**/ }),
      preventDefault: <any>( ( e: any ) => { /**/ }),
    };

    component.onLayerContainerClick( mockEvent );
    expect( component.closeInfoLayer ).toHaveBeenCalled();
  } );
Ratiocinate answered 8/12, 2017 at 11:5 Comment(5)
i think you don't need the spyOn( component, 'closeInfoLayer' );. I think this is used mostly when you want to check function calls of external services, ex: spyOn(myService, 'aMethodThere');Damask
well, I need something to test again. no variable is set in that method and the only outcome is the function call. so this is what I test - it being called. how else?Ratiocinate
if u delete spyOn( component, 'closeInfoLayer' ); it should work, cause it will pass the if statement since u mock the event. give it a try and let us knowDamask
what should I expect then? just deleting spyOn and leaving expect will throw error.Ratiocinate
can you post the error here ? i think if it throws error it means that it didn't pass the if statement and the closeInfoLayer was not calledDamask

© 2022 - 2024 — McMap. All rights reserved.