-
Notifications
You must be signed in to change notification settings - Fork 2.2k
docs(testing): add docs for writing unit tests with AngularFire/Firebase #18
-
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 26 -
🎉 2
Replies: 32 comments 4 replies
-
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 🎉
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 24
-
Is there a way to write unit tests as a user of the library? Any example anywhere even if there are no docs yet?
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 2
-
Also having issues with this. We're new to Angular2 testing with jasmine and are having trouble finding the right way to mock this.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 13
-
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.
Beta Was this translation helpful? Give feedback.
All reactions
-
❤️ 1
-
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.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 7
-
Here's a reference that might be useful to some in the meanwhile: https://github.com/r-park/todo-angular2-firebase/blob/d1c523ae71e06e17d48b17a6c25898ccf09b685e/src/auth/services/auth-service.spec.ts
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
1 year after, any update on this?
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 8
-
Nothing yet, but i'm going to experiment with it and i'll post my solution here asap.
Beta Was this translation helpful? Give feedback.
All reactions
-
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
Beta Was this translation helpful? Give feedback.
All reactions
-
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
Beta Was this translation helpful? Give feedback.
All reactions
-
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
Beta Was this translation helpful? Give feedback.
All reactions
-
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.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 6
-
@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.
Beta Was this translation helpful? Give feedback.
All reactions
-
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 7
-
Thank you so much for sharing this with us @scottshipp :-)
Beta Was this translation helpful? Give feedback.
All reactions
-
no official guide for testing, really? is this an official GOOGLE product?
Beta Was this translation helpful? Give feedback.
All reactions
-
👎 5
-
@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.
Beta Was this translation helpful? Give feedback.
All reactions
-
@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.
Beta Was this translation helpful? Give feedback.
All reactions
-
@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.
Beta Was this translation helpful? Give feedback.
All reactions
-
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!
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 24 -
🎉 6 -
❤️ 4
-
@mattarau would you be able to offer assistance to my stack post for writing unit tests for a angular firebase app?
Beta Was this translation helpful? Give feedback.
All reactions
-
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.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 3
-
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' } ]) } } } }
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 6 -
🎉 2
-
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
Beta Was this translation helpful? Give feedback.
All reactions
-
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);
});
Beta Was this translation helpful? Give feedback.
All reactions
This comment was marked as off-topic.
This comment was marked as off-topic.
-
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.
Beta Was this translation helpful? Give feedback.
All reactions
-
@fmontes I like your approach to mock valueChanges()
on AngularFireDatabase.list()
, but have you tried to mock snapshotChanges()
?
Beta Was this translation helpful? Give feedback.
All reactions
-
Hello, is there any news on this ?
An official AngularFireTestingModule ? Or a one build by the community ?
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 7
-
`
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
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
Any idea on how to write tests with this modular way in v7?
I always get an error:
Error: AngularFireModule has not been provided
Beta Was this translation helpful? Give feedback.
All reactions
-
I have the same issue, I hope someone can give us an example on how to do it the modular way
Beta Was this translation helpful? Give feedback.
All reactions
-
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
Beta Was this translation helpful? Give feedback.
All reactions
-
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
Beta Was this translation helpful? Give feedback.