How to do jasmine unit test case for angular 6 bootstrap 4 modal

13,670

This is how I've tested it in the past...

Assuming the component TS file looks like this:

export class MyComponent {

  closeResult: string;

  constructor(private _modalService: NgbModal) {}

  public openModal(content): void {
    this._modalService.open(content, { size: 'lg' }).result.then((result) => {
      this.closeResult = `Closed with: ${result}`;
    }, (reason) => {
       this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
    });
  }

  private getDismissReason(reason: any): string {
    return  `with: ${reason}`;
  }
}

You can use the following test class which will test these scenarios:

  1. this._modalService.open is called with the correct parameters
  2. When the modal is closed, closeResult is updated correctly
  3. When the modal is dimissed, closeResult is updated correctly

The test class looks like this:

import { TestBed, async, ComponentFixture, tick, fakeAsync } from '@angular/core/testing';
import { NgbModal, NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { MyComponent } from './my.component';

// Mock class for NgbModalRef
export class MockNgbModalRef {
  result: Promise<any> = new Promise((resolve, reject) => resolve('x'));
}

describe('MyComponent', () => {

  let fixtureUnderTest: ComponentFixture<MyComponent>;
  let componentUnderTest: MyComponent;
  let modalService: NgbModal;
  let mockModalRef: MockNgbModalRef = new MockNgbModalRef();

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        MyComponent
      ],
      imports: [
        NgbModule.forRoot()
      ]
    }).compileComponents();

    fixtureUnderTest = TestBed.createComponent(MyComponent);
    componentUnderTest = fixtureUnderTest.componentInstance;
    modalService = TestBed.get(NgbModal);
  }));

  it('should open modal', () => {
    spyOn(modalService, 'open').and.returnValue(mockModalRef);
    componentUnderTest.openModal('<xxxx>');
    expect(modalService.open).toHaveBeenCalledWith('<xxxx>', { size: 'lg' });
  });

  // Needs to be async as modal result returned in a promise
  it('should update closeResult when modal closed', fakeAsync(() => {
    spyOn(modalService, 'open').and.returnValue(mockModalRef);

    componentUnderTest.openModal('<xxxx>');
    tick();
    expect(componentUnderTest.closeResult).toBe('Closed with: x');
  }));

  // Needs to be async as modal result returned in a promise
  it('should update closeResult when modal dismissed', fakeAsync(() => {
    spyOn(modalService, 'open').and.returnValue(mockModalRef);
    // Override the result returned from the modal so we can test what happens when the modal is dismissed
    mockModalRef.result = new Promise((resolve, reject) => reject('y'));

    componentUnderTest.openModal('<xxxx>');
    tick();
    expect(componentUnderTest.closeResult).toBe('Dismissed with: y');
  }));

});
Share:
13,670
Reshma
Author by

Reshma

UI dev with a little bit of Angular, Typescript, Javascript, HTML, CSS and Node :)

Updated on June 26, 2022

Comments

  • Reshma
    Reshma about 2 years

    html

    <ng-template #content let-modal>   
    <h1>Modal content inside this ng-template #content </h1>  
    </ng-template>
    

    Button to open model

    <button  (click)="open(content)" > Open modal </button>
    

    In ts file

    import { NgbModal, ModalDismissReasons } from '@ng-bootstrap/ng-bootstrap';
    constructor(  public modalService: NgbModal) { }
    
    open(content) {  
              this.modalService.open(content, { ariaLabelledBy: 'modal-basic-title', size: 'lg' }).result.then((result) => {
                this.closeResult = `Closed with: ${result}`;
              }, (reason) => {
                this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
              });
               }
    

    How to do a jasmine test case for this open function.

  • Reshma
    Reshma over 5 years
    Hi @ian-a i worked for me , the second test case is failing other 2 are working. but some times an error is throwing "Uncaught TypeError: Cannot read property 'code' of undefined thrown" . If any idea about this please help
  • Ian A
    Ian A over 5 years
    Do you have a code variable anywhere in your component TS file?
  • Reshma
    Reshma over 5 years
    :) thanks for the clue. yes there was & i checked for undefined it worked .
  • Bmoe
    Bmoe about 4 years
    @IanA how would I do this same test, except instead of calling openModal method on componentUnderTest, I would actually query the DOM for a button that when clicked opens the modal?
  • Ian A
    Ian A almost 4 years
    @Bmoe assuming you have a button with the ID open-modal-button that calls the a function which opens the modal, you should be able to say fixtureUnderTest.debugElement.query(By.css('#open-modal-butt‌​on')).nativeElement.‌​click(); to trigger opening the modal by clicking the button. The variable fixtureUnderTest would be an instance of ComponentFixture<MyComponent> which can be instantiated in the beforeEach of the test class setup
  • Adam Hughes
    Adam Hughes over 2 years
    I'm not a big fan of these spys. Why can't we do a test where we actually confirm the subsequent modal window opens correctly? IE "user clicks button, wait a bit, modal should exist in DOM". In my tests the modal HTML element never opens