I would like to have a AuthWrapper Service that wraps the AngularFireAuth Service. Something like this.
// EDIT: Adding some import statements.
import {TestBed} from '@angular/core/testing';
import { AuthWrapperService } from './auth-wrapper.service';
import {AngularFireModule} from '@angular/fire';
import {AngularFireAuth, AngularFireAuthModule} from '@angular/fire/auth';
import {environment} from '../environments/environment';
@Injectable({
providedIn: 'root'
})
export class AuthWrapper {
constructor(public afAuth: AngularFireAuth) { }
isAuthenticated(): Observable<firebase.User> {
return this.afAuth.user;
}
createUserWithEmailAndPassword(email: string, password: string): Promise<String> {
let authPromise: Promise<firebase.auth.UserCredential> =
this.afAuth.auth.createUserWithEmailAndPassword(email, password);
return authPromise
.then((value) => {
return value.user.email;
})
.catch(function(error) {
return error.message;
});
}
}
I want a wrapper, so that I can test my connection to AngularFireAuth. Other tests mock the AuthWrapper.
( Reason for not mocking AngularFireAuth: Say I mock AngularFireAuth, then I am determining the mock's return values. Then I am saying that I understand what these values would look like. It is not safe to assume this without ever testing these by calling the backend. Say google changes how the results of the real AngularFireAuth's methods, I would then be forced to change the results of each of my AngularFireAuth mocks. Instead it is better to wrap AngularFireAuth in a wrapper, and just change that wrapper's methods to conform to google's changes. )
My tests in Karmine and Jasmine result in an "Async callback was not invoked within 5000ms error." I know the user is signed it because the first expect passes, but how do I get the second expect to work?:
describe('AuthWrapperService', () => {
let fireAuthService: AngularFireAuth;
let password = "dcbA4321!";
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
AngularFireModule.initializeApp(environment.firebase),
AngularFireModule,
AngularFireAuthModule
],
providers: [AngularFireAuth, AuthWrapperService],
declarations: []
})
fireAuthService = TestBed.get(AngularFireAuth);
});
it('should sign in user', async() => {
const email = "[email protected]";
let authWrap = new AuthWrapperService(fireAuthService);
let userEmail = await authWrap.createUserWithEmailAndPassword(email, password);
expect(userEmail).toBe("[email protected]");
let obs = authWrap.isAuthenticated();
let promise = obs.toPromise();
let user = await promise.then((result) => {return result});
expect(user.email).toBe("[email protected]");
});
});
I haven't seen any Angular testing code, where the AngularFireAuth isn't mocked.
These are the tests that worked for me with a time interval of 5000ms. I did test them with "[email protected]" in the expect lines to make sure the expect lines were actually running, and yes, the expect lines are actually passing. I intend to only run the AuthWrapperService tests periodically since they hit the database. I will mock the AuthWrapperService in other tests. Before I run these tests I delete the existing users in the firebase database manually through the firebase console. I do run both of these tests in one go, (inside one describe block).
it('should create new user', async() => {
const annEmail = "[email protected]";
let authWrap = new AuthWrapperService(fireAuthService);
await authWrap.createUserWithEmailAndPassword(annEmail, password).then(
((testEmail) => {
expect(fireAuthService.auth.currentUser.email).toBe(annEmail);
})
)
await fireAuthService.auth.signOut();
});
it('should return error message when user already exists', async() => {
const email = '[email protected]';
const error = 'already in use';
let authWrap = new AuthWrapperService(fireAuthService);
await authWrap.createUserWithEmailAndPassword(email, password)
.then((value: String) => {
expect(fireAuthService.auth.currentUser.email).toBe(email);
});
await fireAuthService.auth.signOut();
expect(fireAuthService.auth.currentUser).toBeNull();
await authWrap.createUserWithEmailAndPassword(email, password)
.then((value: String) => {
expect(value).toContain('already in use');
});
await fireAuthService.auth.signOut();
});
I decided to use fireAuthService.auth.currentUser.email instead of the AuthWrapperService's isAuthenticated() method to directly test that my AuthWrapperService's createUserWithEmailAndPassword() method creates a user in firebase.
I realize that this is not a unit test, but I have decided that it is better to have an integration test than to mock methods that I don't own.
The following test also worked for me within 5000ms and uses the isAuthenticated() method.
it('should create user cat', async() => {
const catEmail = "[email protected]";
let authWrap = new AuthWrapperService(fireAuthService);
let userEmail = await authWrap.createUserWithEmailAndPassword(catEmail, password);
expect(userEmail).toBe(catEmail);
await authWrap.isAuthenticated().subscribe({
next(user) {
expect(user.email).toBe(catEmail);
}
});
console.log("cat, timeinterval: " + jasmine.DEFAULT_TIMEOUT_INTERVAL);
await fireAuthService.auth.signOut();
});
The following "dan test" resulted in time outs. I tried 29000ms once and it ran out of time. Most runs of this test were 10 seconds. Many times, but not always, this test passes correctly if the user is already a user before the test is run (so it's not really creating a user during the test). One time this test passed correctly when the user had not been created before the test, but I ran this many times without the user existing before the test and it failed. I'm not sure why that would be.
it('should create user dan', done => {
const datEmail = "[email protected]";
let authWrap = new AuthWrapperService(fireAuthService);
authWrap.isAuthenticated().subscribe(
{
next(user){
expect(user.email).toBe(datEmail);
done();
}
}
);
authWrap.createUserWithEmailAndPassword(datEmail, password);
console.log("dan, timeinterval: " + jasmine.DEFAULT_TIMEOUT_INTERVAL);
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With