0

I am coding with Angular and am attempting to write a test for the below function. We are not using the built in test and are using Jest with the angular-testing-library. When I run the test, I am not covering the

modalRef.componentInstance.emitService.subscribe((deleteConfirm: boolean) => {
      if(deleteConfirm) {
        this.deleteIndividualCertById(id);
      }
});

portion of the below function. My question is: How do I write the test to cover the subscription and missing branch that is in the if statement?

Screenshot of test coverage

The function requiring the test:

openDeleteModal(id: number) {
    const modalRef = this.modalService.open(DeleteConfirmComponent, {
      size: 'lg',
      backdrop: 'static',
      centered: true,
    });
    modalRef.componentInstance.confirmMessage = "Are you sure you wish to delete this Certification?";
    modalRef.componentInstance.emitService.subscribe((deleteConfirm: boolean) => {
      if(deleteConfirm) {
        this.deleteIndividualCertById(id);
      }
    });
}

The modal is held in another component (DeleteConfirmComponent) to make it reusable. The confirmDelete() function is called by the confirm button on the modal. The code for the modal is:

import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-delete-confirm',
  templateUrl: './delete-confirm.component.html',
  styleUrls: ['./delete-confirm.component.css']
})

export class DeleteConfirmComponent implements OnInit {

  constructor(public activeModal: NgbActiveModal) {}

  @Input() confirmMessage: any;
  @Output() emitService = new EventEmitter();


  ngOnInit(): void {
    console.log();
  }

  confirmDelete(){
    this.emitService?.next(true);
    this.activeModal?.close('Close click');
  }

}

The fault is with me not really understanding how to capture the eventEmitter that sets the deleteConfirm boolean and then verify it moves on to the deleteIndividualCertById(id) function in the if statement.

I have tried a bunch of different things after spending a few days searching the internet and sites like Stack Overflow.

it('#openDeleteModal should call #deleteIndividualCertById when confirm is selected', async () => {
    const mockId = 123;
    const mockModalRef = {
      componentInstance: {
        confirmMessage: '',
        emitService: {
          subscribe: jest.fn(),
          next: jest.fn(),
          close: jest.fn()
        }
      },
      result: Promise.resolve(true)
    };
    const mockModalService = {
      open: jest.fn().mockReturnValue(mockModalRef),
      close: jest.fn()
    };

    const component = await render(CertificationsComponent, {
      imports: [HttpClientTestingModule, NgbPaginationModule, NgbModalModule],
      componentProviders: [
        { provide: NgbModal, useValue: mockModalService },
        { provide: NgbModalRef, useValue: mockModalRef },
        {provide: NgbActiveModal, useValue: NgbActiveModal}
      ]
    });
    const componentInstance = component.fixture.componentInstance;
    jest.spyOn(componentInstance, 'deleteIndividualCertById');

    componentInstance.openDeleteModal(mockId);
    expect(mockModalService.open).toHaveBeenCalledWith(DeleteConfirmComponent, {
      size: 'lg',
      backdrop: 'static',
      centered: true,
    });
    
    mockModalService.close();
    expect(mockModalService.close).toHaveBeenCalled();
    const deleteConfirm = true;
    console.log('LOG MSG: ', deleteConfirm);
    if(deleteConfirm) {
      componentInstance.deleteIndividualCertById(mockId);
      expect(componentInstance.deleteIndividualCertById).toHaveBeenCalledWith(mockId);
    }
    
  });

Here I have a simpler version of the modal mock that I haven't yet worked on targeting the missing branch.

test('Should #openDeleteModal with #id of selected certification', async () => {
    const component = await render(CertificationsComponent, {
      declarations: [CertificationsComponent],
      imports: [HttpClientTestingModule, NgbPaginationModule],
      providers: [
        {
          provide: CertificationApiService,
          useValue: MockIndividualsApiService,
        },
      ],
    });
    expect(component);
    const componentInstance = component.fixture.componentInstance;
    let mockId = 1;
    componentInstance.openDeleteModal(mockId);
    const modal = mockModalService.open();
    expect(modal).toEqual({ ...mockReturn });
    });

I would appreciate some guidance here and as a side note, if you have any good references for Angular testing with Jest and the testing-library that I may have missed in my searching, please list them!

balaso
  • 11
  • 1

1 Answers1

0

You can try something like this:

import { openDeleteModal } from './src/yourmodule';
import { DeleteConfirmComponent } from '../components/delete-confirm.component';

describe('openDeleteModal', () => {
    // Mock the ModalService
    const mockModalService = {
        open: jest.fn()
    };

    let modalRef;
    beforeEach(() => {
        modalRef = {
            componentInstance: {
                emitService: jest.fn()
            }
        }
        mockModalService.open.mockReturnValue(modalRef);
    });

    it('should set the correct message and size when calling open', () => {
        openDeleteModal(1, mockModalService);
        expect(mockModalService.open).toHaveBeenCalledWith(DeleteConfirmComponent, {
            size: 'lg',
            backdrop: 'static',
            centered: true
        });
        expect(modalRef.componentInstance.confirmMessage).toBe('Are you sure you wish to delete this Certification?');
    });

    it('should call deleteIndividualCertById when emitService is called with true', () => {
        const spy = jest.spyOn(openDeleteModal, 'deleteIndividualCertById');
        openDeleteModal(1, mockModalService);
        expect(spy).not.toHaveBeenCalled();
        modalRef.componentInstance.emitService.mock.calls[0][0](true);
        expect(spy).toHaveBeenCalledWith(1);
    });
});
José Matos
  • 569
  • 4
  • 13