Angular.js + Firestoreという構成では、クライアントライブラリとしてAngularFire2を使うケースが多いと思います。
AngularFire2では、Firestoreからデータ(コレクション)を取得するにはvalueChanges()
とsnapshotChanges()
の2つの方法があります。
このうちvalueChanges()
はドキュメントIDなどのメタデータを含まないデータそのものだけを返しますが、更新系の処理を行うにはsnapshotChanges()
を使ってメタデータを含めてデータを取得する必要があります。
テストの際、メタデータを含まないデータのみを返すvalueChanges()
をスタブするのは簡単です。
しかし、メタデータを含めたデータを返すsnapshotChanges()
をスタブするのは少し面倒です。
そこでこのエントリでは、AngularJSのテストでAngularFire2のsnapshotChangesをスタブする方法を紹介します。
よくあるUserService
クラスの例を下記に挙げます。公式サンプル通りなので特に説明は不要でしょう。
import { Injectable } from '@angular/core';
import { User } from './user';
import { AngularFirestore } from '@angular/fire/firestore';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private afs: AngularFirestore) { }
/**
* 全てのUserを取得する
*/
getUsers(): Observable<User[]> {
return this.afs.collection('users').snapshotChanges().pipe(
map(actions => actions.map(action => {
const doc = action.payload.doc;
const user = doc.data() as User;
return { id: doc.id, ...user };
}))
);
}
}
次にsnapshotChanges()
をスタブします。
結論から言うと、snapshotChanges()
はDocumentChangeAction<T>[]
を型引数に持つObservable
を返します。下記のように定義されています。
snapshotChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction<T>[]>
実際のスタブの例を見てみましょう。
DocumentChangeAction[]
を作成しJasmine.createSpy
でsnapshotChanges()
の返り値に設定しているところに注目してください。
他の注意点としてはDocumentChangeAction
はDocumentChange
を、DocumentChange
はDocumentSnapshot
をインターフェースとして持つところです。
興味のある人はソースを読んでみてくださいね。
import { TestBed } from '@angular/core/testing';
import { AngularFirestore } from '@angular/fire/firestore';
import { DocumentChangeAction } from '@angular/fire/firestore/interfaces';
import { User } from './user';
import { UserService } from './user.service';
import { Observable, of } from 'rxjs';
const fixtureData = [
{
id: 'foo',
email: 'foo@example.com',
name: 'fooName',
},
{
id: 'bar',
email: 'bar@example.com',
name: 'barName',
},
{
id: 'baz',
email: 'baz@example.com',
name: 'bazName',
},
];
const documentChangeActions: DocumentChangeAction<User>[] = fixtureData.map(data => {
const user: User = data;
const documentSnapshot = { id: user.id, data: (() => user) };
const documentChange = { doc: documentSnapshot };
return { payload: documentChange } as DocumentChangeAction<User>;
});
const collectionStub = {
snapshotChanges: jasmine.createSpy('snapshotChanges').and.returnValue(of(documentChangeActions))
};
const angularFirestoreStub = {
collection: jasmine.createSpy('collection').and.returnValue(collectionStub)
};
describe('UserService', () => {
beforeEach(() => TestBed.configureTestingModule({
providers: [
UserService,
{ provide: AngularFirestore, useValue: angularFirestoreStub }
]
}));
describe('getUsers()', () => {
it('returns users as Observable', () => {
const service: UserService = TestBed.get(UserService);
service.getUsers().subscribe(users => expect(users).toEqual(fixtureData as User[]));
});
});
});
以上です。
このエントリでは、AngularJSのテストでAngularFire2のsnapshotChangesをスタブする方法を紹介しました。
コメントを送る
コメントはブログオーナーのみ閲覧できます