Skip to content

Commit 328bbb7

Browse files
committed
chore(tests): document and collection tests
1 parent 26ec7de commit 328bbb7

File tree

9 files changed

+367
-215
lines changed

9 files changed

+367
-215
lines changed
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
import { FirebaseApp, FirebaseAppConfig, AngularFireModule } from 'angularfire2';
2+
import { AngularFirestore } from '../firestore';
3+
import { AngularFirestoreModule } from '../firestore.module';
4+
import { AngularFirestoreDocument } from '../document/document';
5+
import { AngularFirestoreCollection } from './collection';
6+
7+
import * as firebase from 'firebase/app';
8+
import * as firestore from 'firestore';
9+
import { Observable } from 'rxjs/Observable';
10+
import { of } from 'rxjs/observable/of';
11+
import { Subscription } from 'rxjs/Subscription';
12+
import 'rxjs/add/operator/skip';
13+
14+
import { TestBed, inject } from '@angular/core/testing';
15+
import { COMMON_CONFIG } from '../test-config';
16+
17+
interface Stock {
18+
name: string;
19+
price: number;
20+
}
21+
22+
const FAKE_STOCK_DATA = { name: 'FAKE', price: 1 };
23+
24+
const randomName = (firestore): string => firestore.collection('a').doc().id;
25+
26+
const createRandomStocks = async (firestore: firestore.Firestore, collectionRef: firestore.CollectionReference, numberOfItems) => {
27+
// Create a batch to update everything at once
28+
const batch = firestore.batch();
29+
// Store the random names to delete them later
30+
let count = 0;
31+
let names: string[] = [];
32+
Array.from(Array(numberOfItems)).forEach((a, i) => {
33+
const name = randomName(firestore);
34+
batch.set(collectionRef.doc(name), FAKE_STOCK_DATA);
35+
names = [...names, name];
36+
});
37+
// Create the batch entries
38+
// Commit!
39+
await batch.commit();
40+
return names;
41+
}
42+
43+
describe('AngularFirestoreCollection', () => {
44+
let app: firebase.app.App;
45+
let afs: AngularFirestore;
46+
let sub: Subscription;
47+
48+
beforeEach(() => {
49+
TestBed.configureTestingModule({
50+
imports: [
51+
AngularFireModule.initializeApp(COMMON_CONFIG),
52+
AngularFirestoreModule
53+
]
54+
});
55+
inject([FirebaseApp, AngularFirestore], (_app: firebase.app.App, _afs: AngularFirestore) => {
56+
app = _app;
57+
afs = _afs;
58+
})();
59+
});
60+
61+
afterEach(async (done) => {
62+
await app.delete();
63+
done();
64+
});
65+
66+
function deleteThemAll(names, ref) {
67+
const promises = names.map(name => ref.doc(name).delete());
68+
return Promise.all(promises);
69+
}
70+
71+
function delayUpdate<T>(collection: AngularFirestoreCollection<T>, path, data, delay = 250) {
72+
setTimeout(() => {
73+
collection.doc(path).update(data);
74+
}, delay);
75+
}
76+
77+
function delayAdd<T>(collection: AngularFirestoreCollection<T>, path, data, delay = 250) {
78+
setTimeout(() => {
79+
collection.doc(path).set(data);
80+
}, delay);
81+
}
82+
83+
function delayDelete<T>(collection: AngularFirestoreCollection<T>, path, delay = 250) {
84+
setTimeout(() => {
85+
collection.doc(path).delete();
86+
}, delay);
87+
}
88+
89+
it('should get unwrapped snapshot', async (done: any) => {
90+
const randomCollectionName = randomName(afs.firestore);
91+
const ref = afs.firestore.collection(`${randomCollectionName}`);
92+
const stocks = new AngularFirestoreCollection<Stock>(ref, ref);
93+
const ITEMS = 4;
94+
95+
const names = await createRandomStocks(afs.firestore, ref, ITEMS)
96+
97+
const sub = stocks.valueChanges().subscribe(data => {
98+
// unsub immediately as we will be deleting data at the bottom
99+
// and that will trigger another subscribe callback and fail
100+
// the test
101+
sub.unsubscribe();
102+
// We added four things. This should be four.
103+
// This could not be four if the batch failed or
104+
// if the collection state is altered during a test run
105+
expect(data.length).toEqual(ITEMS);
106+
data.forEach(stock => {
107+
// We used the same piece of data so they should all equal
108+
expect(stock).toEqual(FAKE_STOCK_DATA);
109+
});
110+
// Delete them all
111+
const promises = names.map(name => ref.doc(name).delete());
112+
Promise.all(promises).then(done).catch(fail);
113+
});
114+
115+
});
116+
117+
it('should get snapshot updates', async (done: any) => {
118+
const randomCollectionName = randomName(afs.firestore);
119+
const ref = afs.firestore.collection(`${randomCollectionName}`);
120+
const stocks = new AngularFirestoreCollection<Stock>(ref, ref);
121+
const ITEMS = 10;
122+
123+
const names = await createRandomStocks(afs.firestore, ref, ITEMS);
124+
125+
const sub = stocks.snapshotChanges().subscribe(data => {
126+
// unsub immediately as we will be deleting data at the bottom
127+
// and that will trigger another subscribe callback and fail
128+
// the test
129+
sub.unsubscribe();
130+
// We added ten things. This should be ten.
131+
// This could not be ten if the batch failed or
132+
// if the collection state is altered during a test run
133+
expect(data.length).toEqual(ITEMS);
134+
data.forEach(action => {
135+
// We used the same piece of data so they should all equal
136+
expect(action.payload.doc.data()).toEqual(FAKE_STOCK_DATA);
137+
});
138+
deleteThemAll(names, ref).then(done).catch(done.fail);
139+
});
140+
141+
});
142+
143+
it('should listen to all changes by default', async (done) => {
144+
const randomCollectionName = randomName(afs.firestore);
145+
const ref = afs.firestore.collection(`${randomCollectionName}`);
146+
const stocks = new AngularFirestoreCollection<Stock>(ref, ref);
147+
const ITEMS = 10;
148+
let count = 0;
149+
const names = await createRandomStocks(afs.firestore, ref, ITEMS);
150+
const sub = stocks.snapshotChanges().subscribe(data => {
151+
count = count + 1;
152+
if(count === 1) {
153+
stocks.doc(names[0]).update({ price: 2});
154+
}
155+
if(count === 2) {
156+
expect(data.length).toEqual(1);
157+
expect(data[0].type).toEqual('modified');
158+
deleteThemAll(names, ref).then(done).catch(done.fail);
159+
}
160+
});
161+
});
162+
163+
it('should be able to filter change types - modified', async (done) => {
164+
const randomCollectionName = randomName(afs.firestore);
165+
const ref = afs.firestore.collection(`${randomCollectionName}`);
166+
const stocks = new AngularFirestoreCollection<Stock>(ref, ref);
167+
const ITEMS = 10;
168+
let count = 0;
169+
const names = await createRandomStocks(afs.firestore, ref, ITEMS);
170+
171+
const sub = stocks.snapshotChanges(['modified']).subscribe(data => {
172+
expect(data.length).toEqual(1);
173+
expect(data[0].payload.doc.data().price).toEqual(2);
174+
expect(data[0].type).toEqual('modified');
175+
deleteThemAll(names, ref).then(done).catch(done.fail);
176+
done();
177+
});
178+
179+
delayUpdate(stocks, names[0], { price: 2 });
180+
});
181+
182+
it('should be able to filter change types - added', async (done) => {
183+
const randomCollectionName = randomName(afs.firestore);
184+
const ref = afs.firestore.collection(`${randomCollectionName}`);
185+
const stocks = new AngularFirestoreCollection<Stock>(ref, ref);
186+
const ITEMS = 10;
187+
let count = 0;
188+
let names = await createRandomStocks(afs.firestore, ref, ITEMS);
189+
190+
const sub = stocks.snapshotChanges(['added']).skip(1).subscribe(data => {
191+
expect(data.length).toEqual(1);
192+
expect(data[0].payload.doc.data().price).toEqual(2);
193+
expect(data[0].type).toEqual('added');
194+
deleteThemAll(names, ref).then(done).catch(done.fail);
195+
done();
196+
});
197+
198+
const nextId = ref.doc('a').id;
199+
names = names.concat([nextId]);
200+
delayAdd(stocks, nextId, { price: 2 });
201+
});
202+
203+
fit('should be able to filter change types - removed', async (done) => {
204+
const randomCollectionName = randomName(afs.firestore);
205+
const ref = afs.firestore.collection(`${randomCollectionName}`);
206+
const stocks = new AngularFirestoreCollection<Stock>(ref, ref);
207+
const ITEMS = 10;
208+
let count = 0;
209+
let names = await createRandomStocks(afs.firestore, ref, ITEMS);
210+
211+
const sub = stocks.snapshotChanges(['removed']).subscribe(data => {
212+
debugger;
213+
expect(data.length).toEqual(1);
214+
expect(data[0].type).toEqual('removed');
215+
deleteThemAll(names, ref).then(done).catch(done.fail);
216+
done();
217+
});
218+
219+
debugger;
220+
delayDelete(stocks, names[0], 400);
221+
});
222+
223+
});

src/firestore/collection/collection.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import { Observable } from 'rxjs/Observable';
55
import { Subscriber } from 'rxjs/Subscriber';
66
import { fromCollectionRef } from '../observable/fromRef';
77
import 'rxjs/add/operator/map';
8+
import 'rxjs/add/operator/filter';
9+
import 'rxjs/add/observable/do';
10+
811

912
import { Injectable } from '@angular/core';
1013
import { FirebaseApp } from 'angularfire2';
@@ -71,7 +74,10 @@ export class AngularFirestoreCollection<T> {
7174
return changes(this.query);
7275
}
7376
return changes(this.query)
74-
.map(actions => actions.filter(change => events.indexOf(change.type) > -1))
77+
.map(actions => {
78+
debugger;
79+
return actions.filter(change => events.indexOf(change.type) > -1);
80+
})
7581
.filter(changes => changes.length > 0);
7682
}
7783

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { FirebaseApp, FirebaseAppConfig, AngularFireModule } from 'angularfire2';
2+
import { AngularFirestore } from '../firestore';
3+
import { AngularFirestoreModule } from '../firestore.module';
4+
import { AngularFirestoreDocument } from '../document/document';
5+
6+
import * as firebase from 'firebase/app';
7+
import * as firestore from 'firestore';
8+
import { Observable } from 'rxjs/Observable';
9+
import { Subscription } from 'rxjs/Subscription';
10+
11+
import { TestBed, inject } from '@angular/core/testing';
12+
import { COMMON_CONFIG } from '../test-config';
13+
14+
interface Stock {
15+
name: string;
16+
price: number;
17+
}
18+
19+
const FAKE_STOCK_DATA = { name: 'FAKE', price: 1 };
20+
21+
const randomName = (firestore): string => firestore.collection('a').doc().id;
22+
23+
const createRandomStocks = async (firestore: firestore.Firestore, collectionRef: firestore.CollectionReference, numberOfItems) => {
24+
// Create a batch to update everything at once
25+
const batch = firestore.batch();
26+
// Store the random names to delete them later
27+
let count = 0;
28+
let names: string[] = [];
29+
Array.from(Array(numberOfItems)).forEach((a, i) => {
30+
const name = randomName(firestore);
31+
batch.set(collectionRef.doc(name), FAKE_STOCK_DATA);
32+
names = [...names, name];
33+
});
34+
// Create the batch entries
35+
// Commit!
36+
await batch.commit();
37+
return names;
38+
}
39+
40+
describe('AngularFirestoreDocument', () => {
41+
let app: firebase.app.App;
42+
let afs: AngularFirestore;
43+
let sub: Subscription;
44+
45+
beforeEach(() => {
46+
TestBed.configureTestingModule({
47+
imports: [
48+
AngularFireModule.initializeApp(COMMON_CONFIG),
49+
AngularFirestoreModule
50+
]
51+
});
52+
inject([FirebaseApp, AngularFirestore], (_app: firebase.app.App, _afs: AngularFirestore) => {
53+
app = _app;
54+
afs = _afs;
55+
})();
56+
});
57+
58+
afterEach(async (done) => {
59+
await app.delete();
60+
done();
61+
});
62+
63+
it('should get action updates', async (done: any) => {
64+
const randomCollectionName = randomName(afs.firestore);
65+
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`);
66+
const stock = new AngularFirestoreDocument<Stock>(ref);
67+
await stock.set(FAKE_STOCK_DATA);
68+
const sub = stock
69+
.snapshotChanges()
70+
.subscribe(async a => {
71+
sub.unsubscribe();
72+
if (a.payload.exists) {
73+
expect(a.payload.data()).toEqual(FAKE_STOCK_DATA);
74+
stock.delete().then(done).catch(done.fail);
75+
}
76+
});
77+
});
78+
79+
it('should get unwrapped snapshot', async (done: any) => {
80+
const randomCollectionName = afs.firestore.collection('a').doc().id;
81+
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`);
82+
const stock = new AngularFirestoreDocument<Stock>(ref);
83+
await stock.set(FAKE_STOCK_DATA);
84+
const obs$ = stock.valueChanges();
85+
const sub = obs$.catch(e => { console.log(e); return e; })
86+
.take(1) // this will unsubscribe after the first
87+
.subscribe(async (data: Stock) => {
88+
sub.unsubscribe();
89+
expect(JSON.stringify(data)).toBe(JSON.stringify(FAKE_STOCK_DATA));
90+
stock.delete().then(done).catch(done.fail);
91+
});
92+
});
93+
94+
});

0 commit comments

Comments
 (0)