angulartypescriptunit-testingjasmine

Angular Unit Testing - Errors on Testing Promise Rejection


I'm trying to make sure the catch block of a function on my service is covered, and I just can't quite get it to work.

I've tried a couple of different ways. In version 1, it seems cleaner but I don't think it's working as well as version 2. In version 2, I can see the console.log() I put in the catch block triggering, so I know the spy etc is working. I'm obviously missing something to connect everything.

AuthService Function

  SignUp(email: any, password: any, firstName: string, lastName: string) {
    return this.afAuth
      .createUserWithEmailAndPassword(email, password)
      .then((userCredential) => {
        this.SendVerificationMail();
        this.SetUserData(userCredential.user, firstName, lastName);
      })
      .catch((error) => {
        console.log('errorLog: ', error)
        window.alert(error.message);
      });
  }

auth.service.spec.ts Version 1

  it('SignUp() - Errors', async () => {

    spyOn(AngularFireAuthMock, 'createUserWithEmailAndPassword').and.callFake(() => { throw new Error('auth/expired-action-code') })
    expect (service.SignUp('test@test.com', '123456', 'Name', 'Two')).toThrowError('auth/expired-action-code');

  });

Version 1 Error

Chrome 126.0.0.0 (Windows 10) AuthService SignUp() - Errors FAILED
        Error: auth/expired-action-code
            at Object.<anonymous> (src/app/shared/services/auth.service.spec.ts:58:93)
            at <Jasmine>
            at AuthService.SignUp (src/app/shared/services/auth.service.ts:41:8)
            at UserContext.<anonymous> (src/app/shared/services/auth.service.spec.ts:59:21)
            at Generator.next (<anonymous>)
            at asyncGeneratorStep (node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:3:1)
Chrome 126.0.0.0 (Windows 10): Executed 5 of 5 (1 FAILED) (0.03 secs / 0.016 secs)  

auth.service.spec.ts Version 2

  it('SignUp() - Errors', async () => {

    spyOn(AngularFireAuthMock, 'createUserWithEmailAndPassword').and.callFake(() => Promise.reject(new Error('auth/expired-action-code')))
    expect (service.SignUp('test@test.com', '123456', 'Name', 'Two')).toThrowError('auth/expired-action-code');

  });

Version 2 Error

Chrome 126.0.0.0 (Windows 10) AuthService SignUp() - Errors FAILED
        Error: <toThrowError> : Actual is not a Function
        Usage: expect(function() {<expectation>}).toThrowError(<ErrorConstructor>, <message>)
            at <Jasmine>
            at UserContext.<anonymous> (src/app/shared/services/auth.service.spec.ts:59:71)
            at Generator.next (<anonymous>)
            at asyncGeneratorStep (node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:3:1)
            at _next (node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:22:1)
            at executor (node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:27:1)
            at new ZoneAwarePromise (node_modules/zone.js/fesm2015/zone.js:2662:25)
            at UserContext.<anonymous> (node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js:19:1)
LOG: 'errorLog: ', Error: auth/expired-action-code                                                                                                  
Error: auth/expired-action-code
    at Object.<anonymous> (http://localhost:9876/_karma_webpack_/webpack:/src/app/shared/services/auth.service.spec.ts:58:100)
    at SpyStrategy.exec (http://localhost:9876/base/node_modules/karma-jasmine/node_modules/jasmine-core/lib/jasmine-core/jasmine.js?86d98e11f43f2c8cfac9fb4806ed6c0aced74cbe:9310:39)

Solution

  • Reject the promise and return an object with message property, but do not throw an error. Then spyOn window alert method and check if it's called:

    it('SignUp() - Errors', fakeAsync(() => {
        spyOn(AngularFireAuthMock, 'createUserWithEmailAndPassword').and.callFake(() => Promise.reject({ message: 'auth/expired-action-code' }));
        spyOn(window, 'alert');
        service.SignUp('test@test.com', '123456', 'Name', 'Two');
        flush();
        expect (window.alert).toHaveBeenCalledWith('auth/expired-action-code');
    }));