Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test a service that interacts with Firebase?

It seems like the convention for grabbing data from Firebase is to create a service class that uses AngularFire internally. Then, in your app's components, you can inject and use the service. This allows you to easily mock out the service when unit testing your components.

But, I'm still not clear on how to go about testing the actual service itself.

As an example, say I have a todo list node in Firebase and I have a simple service that grabs all of the todos, like so:

import { Injectable } from '@angular/core';
import { AngularFire } from 'angularfire2';

@Injectable()
export class TodoService {
  constructor(private af: AngularFire) { }

  getAll(): FirebaseListObservable<any[]> {
    return this.af.database.list('todos');
  }
}

How would you go about testing that this service does what you expect?

like image 715
Elliot Larson Avatar asked Feb 05 '23 13:02

Elliot Larson


1 Answers

Reaz recommended MockFirebase in his answer. However, MockFirebase doesn't work with Firebase 3. There is a library called firebase-mock, which appears to be developed by some of the same people as MockFirebase. This augments MF, adding Firebase 3 support, however it doesn't appear to play nicely with WebPack yet.

Here's what I ended up doing:

It occurred to me that FirebaseListObservable inherits from RXJS's Observable. So, you can just mock out the AngularFire call to list and have it return your own Observable.

Some example code showing this in action:

todos.service.spec.ts

let fixtureTodos = [
  { 'text': 'Get milk' },
  { 'text': 'Take out the trash' },
  { 'text': 'Get gas for the car' },
  { 'text': 'Pay parking ticket' },
  { 'text': 'Pick up dry cleaning' },
];
let angularFireDatabaseStub = { list: () => {} };
let mockTodos$ = Observable.of(fixtureTodos);

describe('TodosService', () => {
  beforeEach(() => {
    spyOn(angularFireDatabaseStub, 'list').and.returnValue(mockTodos$);

    TestBed.configureTestingModule({
      providers: [
        TodosService,
        { provide: AngularFireDatabase, useValue: angularFireDatabaseStub },
      ]
    });
  });

  it('#getAll', inject([TodosService], (service: TodosService) => {
    let todos$ = service.getAll();
    todos$.subscribe(todos => {
      expect(todos[0].text).toEqual(fixtureTodos[0].text);
      expect(todos[0]).toEqual(jasmine.any(Todo));
    });
  }));
});

todos.service.ts

@Injectable()
export class TodosService {
  constructor(public db: AngularFireDatabase) { }

  getAll(): Observable<Todo[]> {
    return this.db.list('todos').map(arr => {
      return arr.map(t => new Todo(t.text));
    });
  }
}

todo.model.ts

export class Todo {
  constructor(public text: string) {}
}
like image 84
Elliot Larson Avatar answered Feb 20 '23 00:02

Elliot Larson