0
votes

Ive got a method register() in my service which I want to test. My assert is that an another method from a injected service is called. Lets have a deeper look into my code:

Service

export class OAuthRegistrationService {

  constructor(private afAuth: AngularFireAuth,
              private afs: AngularFirestore) {
  }

  public register(register: RegisterDataModel): Promise<void | string> {
    return this.afAuth.auth.createUserWithEmailAndPassword(register.email, register.password)
      .then(() => {
      const user = this.afAuth.auth.currentUser;
      this.setUser(user, register).then(() =>
        user.sendEmailVerification().then(() => 'Please verify your email').catch((err) => err));
    }).catch((err: FirebaseErrorModel) => err.message);
  }
}

Now on my unit tests I want to assert that sendEmailVerification has been called. Now I need to properly mock the pomises called above, to check if this method has been called.

Spec File /Unit tests

describe('OAuthRegistrationService', () => {
  let service: OAuthRegistrationService;
  // stubs
  const afAuthStub = {
    auth: {
      sendEmailVerification(): Promise<void> {
        return new Promise<void>(resolve => resolve());
      },
      createUserWithEmailAndPassword(): Promise<void> {
        return new Promise<void>(resolve => resolve());
      },
      currentUser: {
        uid: 'blub'
      }
    }
  };

  const afsStub = {
    doc(path: string) {
      return {
        set() {
          return path;
        }
      };
    }
  }

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        {provide: AngularFireAuth, useValue: afAuthStub},
        {provide: AngularFirestore, useValue: afsStub},
        OAuthRegistrationService
      ]
    });
    service = TestBed.get(OAuthRegistrationService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('should send email verification', () => {
    const register: RegisterDataModel = new RegisterDataModel('username', '[email protected]', 'password', null, null);

    const mock = TestBed.get(AngularFireAuth);
    const spy = spyOn(afAuthStub.auth, 'sendEmailVerification').and.callThrough();
    spyOn(afAuthStub.auth, 'createUserWithEmailAndPassword').and.callThrough();
    mock.auth = afAuthStub.auth;

      service.register(register).then(() => {
        expect(spy).toHaveBeenCalled();
    });
  });
});

Jasmines and.callTrough allows me to call a Promise .then() method and to go to the next step of my tested method. But somehow my console says: That my Spy has never been called. Does someone know, what am I doing wrong here?

1

1 Answers

2
votes

Your stub is slightly incorrect, the sendEmailVerification() method belongs on the currentUser property.

const afAuthStub = {
  auth: {
    createUserWithEmailAndPassword(): Promise<void> {
      return new Promise<void>(resolve => resolve());
    },
    currentUser: {
      uid: 'blub',
      sendEmailVerification(): Promise<void> {
        return new Promise<void>(resolve => resolve());
      },
    }
  }
};

...

const spy = spyOn(afAuthStub.auth.currentUser, 'sendEmailVerification')

Here is a StackBlitz with the test passing.