Search code examples
unit-testingjasminekarma-jasminekarma-coveragejasmine2.0

How can i test a function that return a promise or reject - Jasmine and Karma


I need to cover 100% of the tests of a function, it returns a return new Promise<boolean>((resolve, reject) this is the full function.

saveData(): Promise < boolean > {
    return new Promise < boolean > ((resolve, reject) => {
        this.legaloneService.saveFinancialData(this.financialModel).subscribe(
            m => {
                if (!m.Success) {
                    const mapFiels: {
                        [id: string]: string
                    } = {};
                    mapFiels['accountName'] = 'Nome da conta';
                    mapFiels['bankId'] = 'Banco';
                    mapFiels['agency'] = 'Agência';
                    mapFiels['accountNumber'] = 'Conta';
                    this.functionsService.displayErrorFromAPII(m, mapFiels);
                }
                resolve(m.Success);
            },
            error => {
                const msg = 'Ocorreu uma falha ao salvar os dados financeiros';
                this.functionsService.cathError(error, msg);
                reject(msg);
            }
        );
    });
}

A few days ago I got help from someone here, and I am trying to solve this issue using his tips, my test is as follows:

it('testing resolve a promise', fakeAsync(() => {

    spyOn(component, 'saveData').and.returnValue(Promise.resolve(true));
    spyOn(funcService, 'displayErrorFromAPII').and.stub();

    component.saveData()
        .then(r => {
            console.log(r);
            expect(funcService.displayErrorFromAPII).toHaveBeenCalled();
            flush(200);
        })
        .catch(e => fail(e));

    expect(component.saveData).toHaveBeenCalled();
}));

and this is my current coverage:

My current coverage


Solution

  • In your test, you mocks the method saveData under test, the real implementation will not be involved and code coverage will not improve. Therefore you should remove the following statement from your test.

    spyOn(component, 'saveData').and.returnValue(Promise.resolve(true));
    

    You should mock the method legaloneService.saveFinancialData instead since this is a unit test. Since saveData is returning a Promise, you can use the done callback function.

    To have full code coverage, you need the following two tests.

    import { of, throwError } from 'rxjs';
    ...
    
    it('#saveData should display error when financial data cannot be saved', (done) => {    
        const saveFinancialDataResult = ?; // replace ? with expected !Success result    
        spyOn(legaloneService, 'saveFinancialData').and.returnValue(of(saveFinancialDataResult));
        spyOn(funcService, 'displayErrorFromAPII').and.stub();
    
        component.saveData()
            .then(r => {
                expect(funcService.displayErrorFromAPII).toHaveBeenCalled();    
                done();        
            })
            .catch(e => fail(e));
    });
    
    it('#saveData should catch error when error occurs', (done) => {    
        spyOn(legaloneService, 'saveFinancialData').and.returnValue(throwError('server error'));
        spyOn(funcService, 'cathError').and.stub();
    
        component.saveData()
            .then(r => fail('should have been rejected'))
            .catch(e => {
                expect(functionsService.cathError).toHaveBeenCalled();
                done();
            });
    });
    

    Please consult https://angular.io/api/core/testing/fakeAsync and https://jasmine.github.io/tutorials/async for detailed information about different testing strategies with Angular and Jasmine.