1

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.

nurovek
  • 97
  • 5

1 Answers1

1

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();
  })
AliF50
  • 16,947
  • 1
  • 21
  • 37
  • Thanks for your lead, it seems to be a good idea, however my linter wants me to add all missing properties. Should I do so ? https://codepen.io/nurovek-the-sans/pen/zYJmKmG Also, don't worry for groups, it's an array of Group objects {id, category, color, label, count} which is in a const above my test class. I can then call openModalGroups with this array – nurovek Mar 21 '23 at 13:26
  • The Linter says : Argument of type '{ componentInstance: { groups: { id: string; category: string; color: string; label: string; count: number; }[]; }; }' cannot be assigned to 'NgbModalRef' type parameter. And : Type '{ componentInstance: { groups: { id: string; category: string; color: string; label: string; count: number; }[]; }; }' doesn't have this properties of type 'NgbModalRef': _windowCmptRef, _contentRef, _closed, _dismissed & 12 more – nurovek Mar 21 '23 at 13:58
  • Ok, check out my edit of `as any` to make TypeScript happy. – AliF50 Mar 21 '23 at 15:40
  • 1
    Thanks a lot for your help ! Returning the componentInstance in the returnValue (and casted as any) seem to work properly ! I still find it a bit weird to return a componentInstance but nevertheless, it just works. – nurovek Mar 22 '23 at 09:02