1

I want to test one of methods which helps in closing Modal Window when closed outside of Modal Window container.

Component Method

public hide(): void {
    this.visibleAnimate = false;
    setTimeout(() => { this.visible = false; }, 200);
  }

public onModalClicked(event: MouseEvent): void {
    if ((<HTMLElement>event.target).classList.contains('dialog-container')) {
      this.hide();
    }
  }

Unit Test

it('should call hide method', fakeAsync(() => {
    component.hide();
    fixture.detectChanges();
    fixture.whenStable().then(() => {
      expect(component.visible).toEqual(false);
      tick(200);
      expect(component.visibleAnimate).toEqual(false);
    });
  }));



it('should call onModalClicked()', () => {
    const mockEvent = new Event('click'); --> Error
    component.onModalClicked(mockEvent);
    console.log(component.visible);
  });

My Unit test runs fine on hide() method and please let me know if i am doing it in right way or not.

But i am really stuck how to test onModalClicked() method because that takes MouseEvent as parameter.

In my unit testing method, Event and MouseEvent mismatch error occurs, which is obviouse biut how to cover this method?

Gags
  • 3,759
  • 8
  • 49
  • 96

1 Answers1

6

It doesn't need to actually be a MouseEvent, it just needs to quack like one. So you can just make a dummy object that fits the bill and cast it to MouseEvent so it fits your method parameter type. For example:

function createMouseEvent(hasClass, clazz): MouseEvent {
  const event = { target: { classList: { contains: (arg) => false } } }
  if (hasClass) {
    event.target.classList.contains = (cls) => {
      expect(cls).toBe(clazz)
      return true
    }
  } 
  return <any>event;
}

Then to test it, you don't need to actually test the visibility. That is the job of the hide method (to change the visibility). You just want to test the behavior of the onModalClicked, which is that it either calls hide or doesn't, based on the element containing a class. So you can just spy on the hide function, then check if it was called.

it('onModalClicked() should call hide() when element contains class', () => {
  spyOn(component, 'hide')
  const event = createMouseEvent(true, 'dialog-container');
  component.onModalClicked(event);

  expect(component.hide).toHaveBeenCalled()
})

it('onModalClicked() should NOT call hide() when element DOES NOT contain class', () => {
  spyOn(component, 'hide')
  const event = createMouseEvent(false, null);
  component.onModalClicked(event);

  expect(component.hide).not.toHaveBeenCalled()
})
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • I think it is the best suited solution. And cAn you please confirm if i have written correct test case for hide method – Gags Jul 26 '17 at 15:52
  • You don't need `fixture.whenStable`. You are using `fakeAsync`. It is only needed for `async` – Paul Samsotha Jul 26 '17 at 16:08
  • Does the logic for test looks fine? And instead of calling specific method to test, why fixture.detectChanges() does not test those methods? – Gags Jul 26 '17 at 16:11
  • Not sure what you're asking. Maybe you should do some more research on what fixture.detectChanges actually does. – Paul Samsotha Jul 26 '17 at 16:15
  • `createMouseEvent` function does no work in Typescript. it shows an error `Property 'contains' does not exist on type '{}'` – Gags Jul 27 '17 at 03:53
  • You can just add it. `classList: { contains: () => false }`. If you initialize it like this, then you can actually just leave out the `else` – Paul Samsotha Jul 27 '17 at 03:59
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/150245/discussion-between-gags-and-peeskillet). – Gags Jul 27 '17 at 04:01