1
- import { FirebaseApp , FirebaseAppConfig , AngularFireModule } from 'angularfire2' ;
1
+ import { FirebaseApp , FirebaseAppConfig , AngularFireModule } from 'angularfire2' ;
2
2
import { AngularFirestore , AngularFirestoreModule , AngularFirestoreDocument , AngularFirestoreCollection } from 'angularfire2/firestore' ;
3
3
import * as firebase from 'firebase/app' ;
4
4
import * as firestore from 'firestore' ;
@@ -15,12 +15,30 @@ interface Stock {
15
15
16
16
const FAKE_STOCK_DATA = { name : 'FAKE' , price : 1 } ;
17
17
18
- fdescribe ( 'Firestore' , ( ) => {
18
+ const randomName = ( firestore ) : string => firestore . collection ( 'a' ) . doc ( ) . id ;
19
+
20
+ const createRandomStocks = async ( firestore : firestore . Firestore , collectionRef : firestore . CollectionReference , numberOfItems ) => {
21
+ // Create a batch to update everything at once
22
+ const batch = firestore . batch ( ) ;
23
+ // Store the random names to delete them later
24
+ let count = 0 ;
25
+ let names : string [ ] = [ ] ;
26
+ Array . from ( Array ( numberOfItems ) ) . forEach ( ( a , i ) => {
27
+ const name = randomName ( firestore ) ;
28
+ batch . set ( collectionRef . doc ( name ) , FAKE_STOCK_DATA ) ;
29
+ names = [ ...names , name ] ;
30
+ } ) ;
31
+ // Create the batch entries
32
+ // Commit!
33
+ await batch . commit ( ) ;
34
+ return names ;
35
+ }
36
+
37
+ describe ( 'Firestore' , ( ) => {
19
38
let app : firebase . app . App ;
20
39
let afs : AngularFirestore ;
21
- let stock : AngularFirestoreDocument < Stock > ;
22
40
let sub : Subscription ;
23
-
41
+
24
42
beforeEach ( ( ) => {
25
43
TestBed . configureTestingModule ( {
26
44
imports : [
@@ -31,16 +49,11 @@ fdescribe('Firestore', () => {
31
49
inject ( [ FirebaseApp , AngularFirestore ] , ( _app : firebase . app . App , _afs : AngularFirestore ) => {
32
50
app = _app ;
33
51
afs = _afs ;
34
- stock = afs . doc ( 'stocks/FAKE' ) ;
35
52
} ) ( ) ;
36
53
} ) ;
37
54
38
55
afterEach ( async ( done ) => {
39
56
await app . delete ( ) ;
40
- //await stock.delete();
41
- if ( sub ) {
42
- sub . unsubscribe ( ) ;
43
- }
44
57
done ( ) ;
45
58
} ) ;
46
59
@@ -54,42 +67,187 @@ fdescribe('Firestore', () => {
54
67
expect ( afs . app ) . toBeDefined ( ) ;
55
68
} ) ;
56
69
57
- describe ( 'AngularFirestore#document' , ( ) => {
70
+ it ( 'should create an AngularFirestoreDocument' , ( ) => {
71
+ const doc = afs . doc ( 'a/doc' ) ;
72
+ expect ( doc instanceof AngularFirestoreDocument ) . toBe ( true ) ;
73
+ } ) ;
58
74
59
- it ( 'should throw on an invalid path' , ( ) => {
60
- const singleWrapper = ( ) => afs . doc ( 'collection' ) ;
61
- const tripleWrapper = ( ) => afs . doc ( 'collection/doc/subcollection' ) ;
62
- expect ( singleWrapper ) . toThrowError ( ) ;
63
- expect ( tripleWrapper ) . toThrowError ( ) ;
64
- } ) ;
75
+ it ( 'should create an AngularFirestoreCollection' , ( ) => {
76
+ const collection = afs . collection ( 'stuffs' ) ;
77
+ expect ( collection instanceof AngularFirestoreCollection ) . toBe ( true ) ;
78
+ } ) ;
79
+
80
+ it ( 'should throw on an invalid document path' , ( ) => {
81
+ const singleWrapper = ( ) => afs . doc ( 'collection' ) ;
82
+ const tripleWrapper = ( ) => afs . doc ( 'collection/doc/subcollection' ) ;
83
+ expect ( singleWrapper ) . toThrowError ( ) ;
84
+ expect ( tripleWrapper ) . toThrowError ( ) ;
85
+ } ) ;
65
86
66
- it ( 'should get data as an Observable' , async ( done : any ) => {
67
- //await stock.set(FAKE_STOCK_DATA);
68
- const obs$ = Observable . from ( stock ) ;
69
- obs$ . catch ( e => { console . log ( e ) ; return e ; } )
70
- . take ( 1 ) // this will unsubscribe after the first
71
- . subscribe ( async ( data : Stock ) => {
72
- debugger ;
73
- expect ( JSON . stringify ( data ) ) . toBe ( JSON . stringify ( FAKE_STOCK_DATA ) ) ;
87
+ it ( 'should throw on an invalid collection path' , ( ) => {
88
+ const singleWrapper = ( ) => afs . collection ( 'collection/doc' ) ;
89
+ const quadWrapper = ( ) => afs . collection ( 'collection/doc/subcollection/doc' ) ;
90
+ expect ( singleWrapper ) . toThrowError ( ) ;
91
+ expect ( quadWrapper ) . toThrowError ( ) ;
92
+ } ) ;
93
+
94
+ } ) ;
95
+
96
+ describe ( 'AngularFirestoreDocument' , ( ) => {
97
+
98
+ it ( 'should get unwrapped data as an Observable' , async ( done : any ) => {
99
+ const randomCollectionName = afs . firestore . collection ( 'a' ) . doc ( ) . id ;
100
+ const ref = afs . firestore . doc ( `${ randomCollectionName } /FAKE` ) ;
101
+ const stock = new AngularFirestoreDocument < Stock > ( ref ) ;
102
+ await stock . set ( FAKE_STOCK_DATA ) ;
103
+ const obs$ = Observable . from ( stock ) ;
104
+ const sub = obs$ . catch ( e => { console . log ( e ) ; return e ; } )
105
+ . take ( 1 ) // this will unsubscribe after the first
106
+ . subscribe ( async ( data : Stock ) => {
107
+ sub . unsubscribe ( ) ;
108
+ expect ( JSON . stringify ( data ) ) . toBe ( JSON . stringify ( FAKE_STOCK_DATA ) ) ;
109
+ stock . delete ( ) . then ( done ) . catch ( done . fail ) ;
110
+ } ) ;
111
+ } ) ;
112
+
113
+ it ( 'should get snapshot updates' , async ( done : any ) => {
114
+ const randomCollectionName = randomName ( afs . firestore ) ;
115
+ const ref = afs . firestore . doc ( `${ randomCollectionName } /FAKE` ) ;
116
+ const stock = new AngularFirestoreDocument < Stock > ( ref ) ;
117
+ await stock . set ( FAKE_STOCK_DATA ) ;
118
+ const sub = stock
119
+ . snapshotChanges ( )
120
+ . subscribe ( async a => {
121
+ sub . unsubscribe ( ) ;
122
+ if ( a . exists ) {
123
+ expect ( a . data ( ) ) . toEqual ( FAKE_STOCK_DATA ) ;
74
124
stock . delete ( ) . then ( done ) . catch ( done . fail ) ;
75
- } ) ;
125
+ }
126
+ } ) ;
127
+ } ) ;
128
+
129
+ it ( 'should get unwrapped snapshot' , async ( done : any ) => {
130
+ const randomCollectionName = afs . firestore . collection ( 'a' ) . doc ( ) . id ;
131
+ const ref = afs . firestore . doc ( `${ randomCollectionName } /FAKE` ) ;
132
+ const stock = new AngularFirestoreDocument < Stock > ( ref ) ;
133
+ await stock . set ( FAKE_STOCK_DATA ) ;
134
+ const obs$ = stock . valueChanges ( ) ;
135
+ const sub = obs$ . catch ( e => { console . log ( e ) ; return e ; } )
136
+ . take ( 1 ) // this will unsubscribe after the first
137
+ . subscribe ( async ( data : Stock ) => {
138
+ sub . unsubscribe ( ) ;
139
+ expect ( JSON . stringify ( data ) ) . toBe ( JSON . stringify ( FAKE_STOCK_DATA ) ) ;
140
+ stock . delete ( ) . then ( done ) . catch ( done . fail ) ;
141
+ } ) ;
142
+ } ) ;
143
+
144
+
145
+ } ) ;
146
+
147
+ describe ( 'AngularFirestoreCollection' , ( ) => {
148
+
149
+ it ( 'should get unwrapped snapshot' , async ( done : any ) => {
150
+ const randomCollectionName = randomName ( afs . firestore ) ;
151
+ const ref = afs . firestore . collection ( `${ randomCollectionName } ` ) ;
152
+ const stocks = new AngularFirestoreCollection < Stock > ( ref , ref ) ;
153
+ const ITEMS = 4 ;
154
+
155
+ const names = await createRandomStocks ( afs . firestore , ref , ITEMS )
156
+
157
+ const sub = stocks . valueChanges ( ) . subscribe ( data => {
158
+ // unsub immediately as we will be deleting data at the bottom
159
+ // and that will trigger another subscribe callback and fail
160
+ // the test
161
+ sub . unsubscribe ( ) ;
162
+ // We added four things. This should be four.
163
+ // This could not be four if the batch failed or
164
+ // if the collection state is altered during a test run
165
+ expect ( data . length ) . toEqual ( ITEMS ) ;
166
+ data . forEach ( stock => {
167
+ // We used the same piece of data so they should all equal
168
+ expect ( stock ) . toEqual ( FAKE_STOCK_DATA ) ;
169
+ } ) ;
170
+ // Delete them all
171
+ const promises = names . map ( name => ref . doc ( name ) . delete ( ) ) ;
172
+ Promise . all ( promises ) . then ( done ) . catch ( fail ) ;
76
173
} ) ;
77
174
78
- it ( 'should get realtime updates' , async ( done : Function ) => {
79
- // pick a new stock
80
- //await stock.set(FAKE_STOCK_DATA);
81
- sub = stock
82
- . valueChanges ( )
83
- . subscribe ( async a => {
84
- debugger ;
85
- if ( a . exists ) {
86
- expect ( a . data ( ) ) . toEqual ( FAKE_STOCK_DATA ) ;
87
- await stock . delete ( ) ;
88
- done ( ) ;
89
- }
90
- } ) ;
175
+ } ) ;
176
+
177
+ it ( 'should get snapshot updates' , async ( done : any ) => {
178
+ const randomCollectionName = randomName ( afs . firestore ) ;
179
+ const ref = afs . firestore . collection ( `${ randomCollectionName } ` ) ;
180
+ const stocks = new AngularFirestoreCollection < Stock > ( ref , ref ) ;
181
+ const ITEMS = 10 ;
182
+
183
+ const names = await createRandomStocks ( afs . firestore , ref , ITEMS ) ;
184
+
185
+ const sub = stocks . snapshotChanges ( ) . subscribe ( data => {
186
+ // unsub immediately as we will be deleting data at the bottom
187
+ // and that will trigger another subscribe callback and fail
188
+ // the test
189
+ sub . unsubscribe ( ) ;
190
+ // We added ten things. This should be ten.
191
+ // This could not be ten if the batch failed or
192
+ // if the collection state is altered during a test run
193
+ expect ( data . docs . length ) . toEqual ( ITEMS ) ;
194
+ data . docs . forEach ( stock => {
195
+ // We used the same piece of data so they should all equal
196
+ expect ( stock . data ( ) ) . toEqual ( FAKE_STOCK_DATA ) ;
197
+ } ) ;
198
+ // Delete them all
199
+ const promises = names . map ( name => ref . doc ( name ) . delete ( ) ) ;
200
+ Promise . all ( promises ) . then ( done ) . catch ( fail ) ;
201
+ } ) ;
202
+
203
+ } ) ;
204
+
205
+ it ( 'should be able to filter by docChanges' , async ( done : any ) => {
206
+ const randomCollectionName = randomName ( afs . firestore ) ;
207
+ const ref = afs . firestore . collection ( `${ randomCollectionName } ` ) ;
208
+ const stocks = new AngularFirestoreCollection < Stock > ( ref , ref ) ;
209
+
210
+ const added$ = stocks . snapshotChanges ( )
211
+ . map ( snap => snap . docChanges . filter ( change => change . type === 'added' ) )
212
+ . filter ( snap => snap . length > 0 ) ;
213
+
214
+ const modified$ = stocks . snapshotChanges ( )
215
+ . map ( snap => snap . docChanges . filter ( change => change . type === 'modified' ) )
216
+ . filter ( snap => snap . length > 0 ) ;
217
+
218
+ const removed$ = stocks . snapshotChanges ( )
219
+ . map ( snap => snap . docChanges . filter ( change => change . type === 'removed' ) )
220
+ . filter ( snap => snap . length > 0 ) ;
221
+
222
+ added$ . subscribe ( added => {
223
+ // there should only be one addition
224
+ expect ( added . length ) . toEqual ( 1 )
225
+ const change = added [ 0 ] ;
226
+ expect ( change . doc . data ( ) ) . toEqual ( FAKE_STOCK_DATA ) ;
91
227
} ) ;
92
228
229
+ modified$ . subscribe ( added => {
230
+ // there should only be one modification
231
+ expect ( added . length ) . toEqual ( 1 ) ;
232
+ const change = added [ 0 ] ;
233
+ expect ( change . doc . data ( ) ) . toEqual ( { name : 'FAKE' , price : 2 } ) ;
234
+ } ) ;
235
+
236
+ removed$ . subscribe ( added => {
237
+ // there should only be one removal
238
+ expect ( added . length ) . toEqual ( 1 ) ;
239
+ const change = added [ 0 ] ;
240
+ expect ( change . doc . data ( ) ) . toEqual ( { name : 'FAKE' , price : 2 } ) ;
241
+ // delete and done
242
+ change . doc . ref . delete ( ) . then ( done ) . catch ( done . fail ) ;
243
+ } ) ;
244
+
245
+ const randomDocName = randomName ( afs . firestore ) ;
246
+ const addedRef = stocks . doc ( randomDocName ) ;
247
+ addedRef . set ( FAKE_STOCK_DATA ) ;
248
+ addedRef . update ( { price : 2 } ) ;
249
+ addedRef . delete ( ) ;
250
+
93
251
} ) ;
94
252
95
253
} ) ;
0 commit comments