Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
jeffbcross opened this issue Jan 26, 2016 · 32 comments
Open
Assignees
Milestone

Comments

@jeffbcross
Copy link
Contributor

@jeffbcross jeffbcross commented Jan 26, 2016

No description provided.

@jeffbcross jeffbcross changed the title Add docs for writing unit tests with AngularFire/Firebase docs(testing): add docs for writing unit tests with AngularFire/Firebase Feb 2, 2016
@davideast

This comment has been minimized.

Copy link
Member

@davideast davideast commented Jun 27, 2016

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 🎉

@kpgarrod

This comment has been minimized.

Copy link

@kpgarrod kpgarrod commented Jul 11, 2016

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

@frankcarey

This comment has been minimized.

Copy link

@frankcarey frankcarey commented Aug 18, 2016

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

@dsummersl

This comment has been minimized.

Copy link

@dsummersl dsummersl commented Aug 24, 2016

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.

@jamesehly

This comment has been minimized.

Copy link

@jamesehly jamesehly commented Nov 5, 2016

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.

@rjbergerud

This comment has been minimized.

Copy link

@rjbergerud rjbergerud commented Nov 29, 2016

@manolof

This comment has been minimized.

Copy link

@manolof manolof commented Jan 26, 2017

1 year after, any update on this?

@OnnoOver9000

This comment has been minimized.

Copy link

@OnnoOver9000 OnnoOver9000 commented Feb 3, 2017

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

@OnnoOver9000

This comment has been minimized.

Copy link

@OnnoOver9000 OnnoOver9000 commented Feb 3, 2017

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

@douglascorrea

This comment has been minimized.

Copy link

@douglascorrea douglascorrea commented May 4, 2017

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

@katowulf

This comment has been minimized.

Copy link
Collaborator

@katowulf katowulf commented May 4, 2017

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

@scottshipp

This comment has been minimized.

Copy link

@scottshipp scottshipp commented May 10, 2017

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.

@pas2al

This comment has been minimized.

Copy link

@pas2al pas2al commented May 18, 2017

@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.

@scottshipp

This comment has been minimized.

Copy link

@scottshipp scottshipp commented May 24, 2017

@pas2al

This comment has been minimized.

Copy link

@pas2al pas2al commented May 24, 2017

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

@scottshipp

This comment has been minimized.

Copy link

@scottshipp scottshipp commented Jun 9, 2017

@yass005

This comment has been minimized.

Copy link

@yass005 yass005 commented Jul 20, 2017

thank you very much i'm writing an ionic app with fire base and angular fire and i'm trying to create an unit test fore my auth services

@sandangel

This comment has been minimized.

Copy link

@sandangel sandangel commented Dec 12, 2017

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

@Splaktar

This comment has been minimized.

Copy link
Member

@Splaktar Splaktar commented Dec 12, 2017

@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.

@sandangel

This comment has been minimized.

Copy link

@sandangel sandangel commented Dec 12, 2017

@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.

@Splaktar

This comment has been minimized.

Copy link
Member

@Splaktar Splaktar commented Dec 13, 2017

@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.

@mattarau

This comment has been minimized.

Copy link

@mattarau mattarau commented Dec 14, 2017

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!

@jamesdaniels jamesdaniels self-assigned this Dec 14, 2017
@jamesdaniels

This comment has been minimized.

Copy link
Member

@jamesdaniels jamesdaniels commented Dec 14, 2017

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.

@troydcthompson

This comment has been minimized.

Copy link

@troydcthompson troydcthompson commented Dec 21, 2017

I couldn't get the logIn function defined from my Firebase Provider, which has my auth service. It kept saying it was undefined... I replaced
service.logIn(credentialsMock);
with
component.service.login(credentialsMock) to get it to run...

@fmontes

This comment has been minimized.

Copy link

@fmontes fmontes commented Mar 19, 2018

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'
                    }
                ])
            }
        }
    }
}
@MarcoLeko

This comment has been minimized.

Copy link

@MarcoLeko MarcoLeko commented Apr 8, 2018

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

@MarcoLeko

This comment has been minimized.

Copy link

@MarcoLeko MarcoLeko commented Apr 10, 2018

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);
  });
@feryholanda

This comment was marked as off-topic.

Copy link

@feryholanda feryholanda commented May 16, 2018

someone, please help me
i have error in my project, can you check my project ?
and tell me, what's wrong with my project ?
error

@jamesdaniels

This comment has been minimized.

Copy link
Member

@jamesdaniels jamesdaniels commented May 16, 2018

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.

@elvisfernandes

This comment has been minimized.

Copy link

@elvisfernandes elvisfernandes commented Jun 7, 2018

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

@GrandSchtroumpf

This comment has been minimized.

Copy link

@GrandSchtroumpf GrandSchtroumpf commented Jun 23, 2019

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

@tedwardsgames

This comment has been minimized.

Copy link

@tedwardsgames tedwardsgames commented Jul 9, 2019

`
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
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 14, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 14, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 14, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 16, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 22, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 23, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 23, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 24, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 24, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 24, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 25, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 26, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 28, 2019
devinshoemaker added a commit to devinshoemaker/promise-to-pay that referenced this issue Jul 28, 2019
@mhmo91 mhmo91 mentioned this issue Sep 18, 2019
4 of 4 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.