Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

docs(testing): add docs for writing unit tests with AngularFire/Firebase #18

jeffbcross started this conversation in Ideas
Discussion options

You must be logged in to vote

Replies: 32 comments 4 replies

Comment options

We should abstract the tedious setup parts into a unit testing library, so contributors (and maintainers) don't wince every time they write a test 🎉

You must be logged in to vote
0 replies
Comment options

Is there a way to write unit tests as a user of the library? Any example anywhere even if there are no docs yet?

You must be logged in to vote
0 replies
Comment options

Also having issues with this. We're new to Angular2 testing with jasmine and are having trouble finding the right way to mock this.

You must be logged in to vote
0 replies
Comment options

Ditto, I've tried something along the lines of this: http://a2zhow.xyz/questions/38042941/how-to-mock-angularfire-2-service-in-unit-test

But as yet no luck.

You must be logged in to vote
0 replies
Comment options

Any progress on this? I'm stuck on trying to mock AngularFire2 so I can test my controllers and services. If someone could post an example, that would be awesome.

You must be logged in to vote
0 replies
Comment options

You must be logged in to vote
0 replies
Comment options

1 year after, any update on this?

You must be logged in to vote
0 replies
Comment options

Nothing yet, but i'm going to experiment with it and i'll post my solution here asap.

You must be logged in to vote
0 replies
Comment options

Alright so i managed to make a fake service for my service that uses AngularFire2.

Here is my service that i'm going to mock:
export class TestService {
private angularFire;
constructor(private af: AngularFire) {
this.angularFire = af;

}

getTest() {
return this.angularFire.database.list('/test');} }

For this service i created a fake service that looks like this:
export class FakeTestService {
getTest(){
return Observable.interval(500).map(i => [{$value: 'testvalue1'},{$value: 'testvalue2'},{$value: 'testvalue3'}]);
}
The next thing i did was adding a provider with useClass:
providers: [ { provide: TestService, useClass:FakeTestService } ],

This is my simple setup and i hope it helps you and anyone else who is having difficulties setting up a fake service combined with angularfire2

You must be logged in to vote
0 replies
Comment options

I'm looking for a way to unit test angularfire2, the reference provided by @rjbergerud is good but unfortunately is deprecated because of changes on angularfire2 v4.0.0

You must be logged in to vote
0 replies
Comment options

Also not a solution, but this is probably key to writing good unit tests with async/realtime tools like Firebase. Haven't pondered how rx changes this equation yet; it probably makes mocking the results from AngularFire much, much easier.

https://gist.github.com/katowulf/3e6ec8b109d76e63d7ac4046bf09ef77

You must be logged in to vote
0 replies
Comment options

We're using Jasmine spies to unit test an Ionic app using Angularfire 2. It works well. I will try and write something up and post back.

You must be logged in to vote
0 replies
Comment options

@scottshipp Any updates on this? Even a simple example would be extremely helpful :-)

How do you write your tests when using AngularFireDatabase? I am stuck when i try to provide the necessary dependencies, because it says app.database is not a function. I can fix that by manually mocking it, but i don't want to do that in every single test.

You must be logged in to vote
0 replies
Comment options

You must be logged in to vote
0 replies
Comment options

Thank you so much for sharing this with us @scottshipp :-)

You must be logged in to vote
0 replies
Comment options

no official guide for testing, really? is this an official GOOGLE product?

You must be logged in to vote
0 replies
Comment options

@sandangel this library not a Google product. It's a free and open source project that is maintained by Google, using their money, along with the community.

This library does integrate with the Firebase product from Google. If you would like support for the Firebase product from Google, you can contact them here.

PRs or blog posts that advance the state of testing with AngularFire2 would be greatly appreciated.

You must be logged in to vote
0 replies
Comment options

@Splaktar Thanks for clarifying. I just see

The official library for Firebase and Angular

and I have surprised when could not find any testing guide although this issue was created 2 years ago.

You must be logged in to vote
0 replies
Comment options

@sandangel understood. The blog posts above are the best bet atm. Hopefully after the Firebase Storage stuff gets merged and stabilized, testing will get some more attention and official docs.

You must be logged in to vote
0 replies
Comment options

Hey guys, I was struggling writing tests for AngularFIreAuth and end up with a solution that has been working quite well now. It's only for authentication with email and password, but I'm sharing it here, so it may help someone.

import { TestBed } from '@angular/core/testing';
import { AngularFireAuth } from 'angularfire2/auth';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Subscription } from 'rxjs/Subscription';
import { UserService } from './user.service';
const credentialsMock = {
 email: 'abc@123.com',
 password: 'password'
};
const userMock = {
 uid: 'ABC123',
 email: credentialsMock.email,
};
const fakeAuthState = new BehaviorSubject(null); // <= Pay attention to this guy
const fakeSignInHandler = (email, password): Promise<any> => {
 fakeAuthState.next(userMock);
 return Promise.resolve(userMock);
};
const fakeSignOutHandler = (): Promise<any> => {
 fakeAuthState.next(null);
 return Promise.resolve();
};
const angularFireAuthStub = {
 authState: fakeAuthState,
 auth: {
 createUserWithEmailAndPassword: jasmine
 .createSpy('createUserWithEmailAndPassword')
 .and
 .callFake(fakeSignInHandler),
 signInWithEmailAndPassword: jasmine
 .createSpy('signInWithEmailAndPassword')
 .and
 .callFake(fakeSignInHandler),
 signOut: jasmine
 .createSpy('signOut')
 .and
 .callFake(fakeSignOutHandler),
 },
};
describe('UserService', () => {
 let service: UserService;
 let afAuth: AngularFireAuth;
 let isAuth$: Subscription;
 let isAuthRef: boolean;
 beforeEach(() => {
 TestBed.configureTestingModule({
 providers: [
 UserService,
 { provide: AngularFireAuth, useValue: angularFireAuthStub },
 ],
 });
 service = TestBed.get(UserService);
 afAuth = TestBed.get(AngularFireAuth);
 });
 beforeEach(() => {
 isAuth$ = service.isAuthenticated$
 .subscribe(isAuth => {
 isAuthRef = isAuth;
 });
 });
 afterEach(() => {
 fakeAuthState.next(null);
 isAuth$.unsubscribe();
 });
 it('should be created', () => {
 expect(service).toBeTruthy();
 });
 it('should not be initially authenticated', () => {
 expect(isAuthRef).toBe(false);
 });
 it('should be authenticated after register', () => {
 service.register(credentialsMock);
 expect(afAuth.auth.createUserWithEmailAndPassword)
 .toHaveBeenCalledWith(credentialsMock.email, credentialsMock.password);
 expect(isAuthRef).toBe(true);
 expect(service.user.email).toEqual(credentialsMock.email);
 });
 it('should be authenticated after logging in', () => {
 service.logIn(credentialsMock);
 expect(afAuth.auth.signInWithEmailAndPassword)
 .toHaveBeenCalledWith(credentialsMock.email, credentialsMock.password);
 expect(isAuthRef).toBeTruthy();
 expect(service.user.email).toEqual(credentialsMock.email);
 });
 it('should not be authenticated after logging out', () => {
 fakeAuthState.next(userMock);
 expect(isAuthRef).toBe(true);
 expect(service.user.email).toEqual(credentialsMock.email);
 service.logOut();
 expect(isAuthRef).toBe(false);
 expect(service.user).toBe(null);
 });
});

The service being tested for reference:

import { Injectable } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import { User } from 'firebase/app';
import { Observable } from 'rxjs/Observable';
class Credentials {
 email: string;
 password: string;
}
@Injectable()
export class UserService {
 public user: User;
 public get isAuthenticated$(): Observable<boolean> {
 return this.afAuth.authState.map(user => user !== null);
 }
 constructor(
 private afAuth: AngularFireAuth,
 ) {
 this.afAuth.authState.subscribe(user => {
 this.user = user;
 });
 }
 register(credentials: Credentials): Promise<any> {
 return this.afAuth.auth
 .createUserWithEmailAndPassword(
 credentials.email,
 credentials.password,
 );
 }
 logIn(credentials: Credentials): Promise<any> {
 return this.afAuth.auth
 .signInWithEmailAndPassword(
 credentials.email,
 credentials.password,
 );
 }
 logOut(): Promise<any> {
 return this.afAuth.auth
 .signOut();
 }
}

Cheers!

You must be logged in to vote
1 reply
Comment options

@mattarau would you be able to offer assistance to my stack post for writing unit tests for a angular firebase app?

https://stackoverflow.com/questions/73012544/how-to-mock-auth-createuserwithemailandpassword-signinwithemailandpassword-of

Comment options

I'll take on some of the doc work here, I'd appreciate if people can sound off on strategies that work for them in testing like @mdentinho. It's helpful to gain context in how people are testing so I can capture those patterns in the docs / helpers.

You must be logged in to vote
0 replies
Comment options

FWIW I mocked my AngularFireDatabase list method like this:

export class AngularFireDatabaseMock {
 list(query: string): any {
 return {
 valueChanges() {
 return Observable.of([
 {
 date: 12345,
 name: 'Hello World'
 },
 {
 date: 456779,
 name: 'Hola Mundo'
 }
 ])
 }
 }
 }
}
You must be logged in to vote
0 replies
Comment options

Does someone know how to mock angular fire storage und -storageReference have opened an „issue" on this. Would be awesome if someone has a solution on this.
#1550

You must be logged in to vote
0 replies
Comment options

For the people who use AngularFirebaseStorage and want to build unit tests around this Service thats the way to mock ref() and getDownloadURL():
Create a FakeClass:

export class FirebaseMock {
 public ref(path: string) {
 return {
 getDownloadURL() {
 return Observable.of(path)
 }
 }
 }
}

And inject it into the real into the class' constructor that needs to be tested:

 let mock: any;
 let service: TownhallPictureService;
 beforeEach(() => {
 mock = new FirebaseMock();
 service = new TownhallPictureService(mock);
 });
You must be logged in to vote
0 replies

This comment was marked as off-topic.

Comment options

You need to import map @feryholanda, this location differs depending on the version of rx you're using. In rxjs 5.5:

import { map } from 'rxjs/observable/map';

If you're using rxjs 6, you'll need to pipe.

import { map } from 'rxjs/observables';
...
...snapshotChanges().pipe(map(a => ...))

Please keep comments on topic and post general questions to StackOverflow.

You must be logged in to vote
0 replies
Comment options

@fmontes I like your approach to mock valueChanges() on AngularFireDatabase.list(), but have you tried to mock snapshotChanges()?

You must be logged in to vote
0 replies
Comment options

Hello, is there any news on this ?
An official AngularFireTestingModule ? Or a one build by the community ?

You must be logged in to vote
0 replies
Comment options

`
firebaseRoot = new MockFirebase("Mock://");
firebaseRoot.autoFlush(true); 
statsRef = firebaseRoot.child("stats");
 externalServiceMock.getCapacities.and.callFake(function(){
 return of(helper.getSnapShotChanges(capacitiesRef,true))
 });`

Inside the describe

`beforeEach(()=>{
statsRef.set({*dataObject*})
})
it('subscribes',()=>{
 service.getSnapshotChangesOfData().subscribe(data =>{
 expect(data).toContain({dataObj}); 
 })
})
`

Helper Function

 getSnapShotChanges(data: object, asObserv: boolean){
 const dataKeys = Object.keys(data);
 for(let i = 0; i < dataKeys.length; i++){
 this.actions.push({
 payload: {
 val: function() { return data[dataKeys[i]] },
 key: dataKeys[i]
 },
 prevKey: null,
 type: "value"
 });
 }
 if(asObserv){
 return of(this.actions);
 }else{
 return this.actions;
 }
 };```
This is what we have been doing to allow us to follow on from angularjs testing,its made fairly similar now
You must be logged in to vote
0 replies
Comment options

Any idea on how to write tests with this modular way in v7?

I always get an error:

Error: AngularFireModule has not been provided
You must be logged in to vote
3 replies
Comment options

I have the same issue, I hope someone can give us an example on how to do it the modular way

Comment options

Same issue here, is there a way to provide Firestore, Auth, Storage and whatever else service it's being used only one time instead of on every .spec TestBed.configureTestingModule? I implemented the modular API on a big projectand it would be very cumbersome to have to go to each .spec file and repeat this for every firebase service used in the component

Comment options

So the recommended approach is to actually wrap your Firebase stuff in a root level service e.g. CarFirestoreService, so that Angular can re-use it as much as possible, and have one subscription throughout the lifetime of the app.

It is actually cheaper too, saving you lots of money over time

So, having said that, it gets really easy. Simply mock your custom service

Having tones of Firestores everywhere in the app isn't good. It will mean as the user navigates with the app, it will sub/un-sub, re-fetch data all the time. This will rack up your boss' bill. You will have a lot of explaining to do 6 months down the line

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /