angularjasmineng-bootstrapng-bootstrap-modal

Test the callback function in a NgbModal closed Observable with Jasmine


I'm working on an Angular (14) project with nb-bootstrap and testing with Jasmine.

In my code I have this function which opens a modal to add groups (aka labels or tags) in a list. Which you can apply on recipients (in another function) to facilitate sorting.

  openModalGroup(groups: Group[]) {
    const modalRef = this.modalService.open(ModalGroupComponent, {windowClass: 'modal-default-form'});
    modalRef.componentInstance.groups = groups;
    this.subscription.add(modalRef.closed.subscribe(() => {
      this.refreshRecipients();
    }));
  }

I'd like to unit test the call of refreshRecipients in the closed (not dismissed) behavior, which as its name indicates, refreshes the list of recipients (a table). This is one of my last code coverage missing on this component according to Sonar. Sonar says refreshRecipients call isn't covered

I've tried something that looks like this :

  fit('should close modal and refresh recipients', () => {
    const modalgroupRef = modalService.open(ModalGroupComponent, {windowClass: 'modal-default-form'});
    modalgroupRef.componentInstance.groups = groups;

    spyOn(modalgroupRef, 'close');
    spyOn(component, 'refreshRecipients');

    modalgroupRef.close();
    fixture.detectChanges();

    expect(modalgroupRef.close).toHaveBeenCalled();
    expect(component.refreshRecipients).toHaveBeenCalled();
  })

Which in my opinion was the way to go : I trigger the closing of the modal, it should change the value of the closed observable according to the ngbModal doc and the function should have been called.

Except the call of the spy is not detected.Spy refreshRecipients not called

I don't really know what more to do. I've tried several other things, such as subscribing on closed in the unit test too, but the expect was never detected.

Is it possible with the current implementation to check if refreshRecipients is succesfully called ? Or do I have to refactor my code in order to test my function better ?

Thanks.


Solution

  • I would call openModalGroup directly. The way you have it now, the modalRef in your test and component are not the same instance (there is one created in the openModalGroup method and one created in your test).

    I would do the following:

    fit('should close modal and refresh recipients', () => {
        // mock the open method
        spyOn(modalService, 'open').and.returnValue({
           componentInstance: {
             groups: {} // not sure how to mock this
           },
           closed: of(null), // make closed emit null
        // !! Add as any here to make TypeScript happy
        } as any);
        
        spyOn(component, 'refreshRecipients');
        // call the method
        component.openModalGroup();
        
        // Expect refreshRecipients to be called
        expect(component.refreshRecipients).toHaveBeenCalled();
      })