angularjasminekarma-jasmineangular-unit-testjasmine-marbles

Unit test for renderer listen method on custom event


I have the below method that listens to a custom event and sets the focus of the element. I want to write a unit test for this method. I am trying to mock the focus element focus and using fakeAsync to provide a little delay and also mocking the renderer listener but the coverage is not getting through this method.

listenToModalCloseEvent() {
    this.modalListenerFn = this.renderer.listen(document, 'popupClosed', () => {
      if (this.focusElement) {
        setTimeout(() => {
          this.focusElement.focus();
        }, 0);
      }
    });
  }

here is what I have trid,

it('should call listenToModalCloseEvent', fakeAsync(() => {
    dummyElement.dispatchEvent(new Event('popupClosed', { bubbles: true }));
    service.focusElement = dummyElement;
    service.listenToModalCloseEvent();
    const spy = spyOnProperty(service, 'focusElement').and.returnValue({ focus: () => {}});
    spyOn((service as any).renderer, 'listen').and.callThrough();
    tick(100);
    expect(service.focusElement).toBeDefined();
    expect(spy).toHaveBeenCalled();
  }))

Don't where I am wrong


Solution

  • The main issue is that you're dispatching popupClosed event before the subscription to that event. Also:

    Here's the final test:

    it('should call listenToModalCloseEvent', fakeAsync(() => {
      const dummyElement = document.createElement('input')!;
      document.body.appendChild(dummyElement); // now it can propagate events to the document
    
      service.focusElement = dummyElement;
      service.listenToModalCloseEvent();
      const spy = spyOn(dummyElement, 'focus');
      dummyElement.dispatchEvent(new Event('popupClosed', { bubbles: true }));
      dummyElement.remove(); // remove input from the page
      tick(0);
      expect(service.focusElement).toBeDefined();
      expect(spy).toHaveBeenCalled();
    }))
    

    btw, expect(service.focusElement).toBeDefined(); looks weird because you explicitly assigned that property to class.