Search code examples
angularunit-testingtypescriptjasmineangular2-services

Jasmine: Expecting Error to be Thrown in a Async Function


I have an async function in my angular2 app for which I want to write a unit test. Imagine my function is like this:

myFunc(a: int): Promise<void> {
    if (a == 1)
        throw new Error('a should not be 1');

    let body = {
        value: a
    };
    return apiService.patch('/url/', JSON.stringify(body)).toPromise();
}

Now, I'm thinking of checking that if condition. I tried the following code; but, this test always fails since my code actually does not wait for any results:

it('should throw error if a = 1', () => {
    expect(() => {
        mySerivce.myFunc(1);
    }).toThrow(new Error('a should not be 1'));
})

I don't know how I should write unit tests for these types of logics...


Solution

  • You can use try catch.

    This is what I came up with and it was also what was suggested on the Github issue tracker for jasmine.

    https://github.com/jasmine/jasmine/issues/1410

    function double(a: number): Promise<number> {
       if (a === 1) {
           throw new Error('a should not be 1')
       }
    
       return new Promise(function (resolve, reject) {
           setTimeout(resolve, 100, a * 2 )
       })
    }
    
    describe('test double', () => {
        it('should double any number but 1', async() => {
            const result = await double(2);
            expect(result).toBe(4)
        });
    
        it('should throw an error', async() => {
            let error;
            try {
                await double(1)
            } catch (e) {
                error = e;
            }
            const expectedError = new Error('a should not be 1');
            expect(error).toEqual(expectedError)
    
        })
    });
    

    I also wrote myself a little helper

    async function unpackErrorForAsyncFunction(functionToTest: Function, ...otherArgs: any[]): Promise<Error> {
        let error;
        try {
            const result = await functionToTest(...otherArgs);
        } catch (e) {
            error = e;
        }
        return error;
    }
    
    function double(a: number): Promise<number> {
        if (a === 1) {
            throw new Error('a should not be 1')
        }
    
        return new Promise(function (resolve, reject) {
            setTimeout(resolve, 100, a * 2 )
        })
    }
    
    function times(a: number, b: number): Promise<number> {
        if (a === 1 && b === 2) {
            throw new Error('a should not be 1 and 2')
        }
    
        return new Promise(function (resolve, reject) {
            setTimeout(resolve, 100, a * b )
        })
    }
    
    describe('test times and double with helper', () => {
        it('double should throw an error with test helper', async() => {
            const result = await unpackErrorForAsyncFunction(double, 1);
            const expectedError = new Error('a should not be 1');
    
            expect(result).toEqual(expectedError)
        });
    
        it('times should throw an error with test helper', async() => {
            const result = await unpackErrorForAsyncFunction(times, 1, 2);
            const expectedError = new Error('a should not be 1 and 2');
    
            expect(result).toEqual(expectedError)
        });
    });