Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a unit test for ng-bootstrap modal (NgbModal) [Angular 6]

I am having some trouble writing unit tests for a confirmation modal I have in my app. Here is the piece of code I would like to test:

  confirmModal(prompt = 'Are you sure?', title = 'Confirm'): Observable<boolean> {
    const modal = this.ngbModal.open(
      ConfirmModalComponent, { backdrop: 'static' });

    modal.componentInstance.prompt = prompt;
    modal.componentInstance.title = title;

    return from(modal.result).pipe(
      catchError(error => {
        console.warn(error);
        return of(undefined);
      })
    );
  }

Any suggestions or examples?

like image 651
Amir Avatar asked Dec 30 '19 00:12

Amir


People also ask

How do you test for ngbModal?

compileComponents(); fixtureUnderTest = TestBed. createComponent(MyComponent); componentUnderTest = fixtureUnderTest. componentInstance; ngbModal = TestBed. get(NgbModal); }); it('should open modal', () => { spyOn(ngbModal, 'open').

Can we use bootstrap modal in Angular?

Ng Bootstrap will help to easily use bootstrap ui. In this example we will simply create one model popup, so you can use in your angular 12 application.


1 Answers

I've written the following test class based on your code snippet:

import { TestBed, ComponentFixture } from '@angular/core/testing';
import { NgbModal, NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { ConfirmModalComponent } from './confirm-modal.component';
import { MyComponent } from './test';

// Mock class for NgbModalRef
export class MockNgbModalRef {
    componentInstance = {
        prompt: undefined,
        title: undefined
    };
    result: Promise<any> = new Promise((resolve, reject) => resolve(true));
}

describe('MyComponent tests', () => {

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

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

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

    it('should open modal', () => {
        spyOn(ngbModal, 'open').and.returnValue(mockModalRef);
        componentUnderTest.confirmModal();
        expect(ngbModal.open).toHaveBeenCalledWith(ConfirmModalComponent, { backdrop: 'static' });
    });

    it('should set prompt and title to defaults', () => {
        spyOn(ngbModal, 'open').and.returnValue(mockModalRef);
        componentUnderTest.confirmModal();
        expect(mockModalRef.componentInstance.prompt).toBe('Are you sure?');
        expect(mockModalRef.componentInstance.title).toBe('Confirm');
    });

    it('should return the result of the modal', (done: DoneFn) => {
        spyOn(ngbModal, 'open').and.returnValue(mockModalRef);
        componentUnderTest.confirmModal().subscribe((result: boolean) => {
            expect(result).toBe(true);
            done();
        });
    });

    it('should return undefined if there is an error', (done: DoneFn) => {
        spyOn(ngbModal, '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(false));
        componentUnderTest.confirmModal().subscribe((result: boolean) => {
            expect(result).toBeUndefined();
            done();
        });
    });

});

The tests are as follows:

  1. should open modal: Tests the ngbModal.open method was called with the correct parameters.

  2. should set prompt and title to defaults: Tests that prompt and title attributes are set correctly to their default values after the modal has opened. For this I had to add the following object to the MockNgbModalRef so that the values for prompt and title can be updated by the component itself.

componentInstance = {
    prompt: undefined,
    title: undefined
};
  1. should return the result of the modal: Tests that the value of modal.result is returned from this method. With the method returning an Observable, I needed to subscribe to it and do the assert in within the subscribe. I've inject DoneFn so that done() gets called after the assertion. This means if the assertion never happens (e.g. there is an error in the component), done() never gets called and the test will fail.

  2. should return undefined if there is an error: Similar to #3, however it checks that if the result of the modal was rejected (i.e. there was an error) then undefined is returned.

like image 81
Ian A Avatar answered Sep 28 '22 21:09

Ian A