11const { credentials, makeid, sleep } = require ( './util' ) ;
22const fft = require ( 'firebase-functions-test' ) (
3- { projectId : credentials . projectId } ,
3+ {
4+ projectId : credentials . projectId ,
5+ } ,
46 credentials . serviceAccountKeyFile
57) ;
68const test = require ( 'ava' ) ;
79const { integrify } = require ( '../lib' ) ;
10+ const { replaceReferenceWithFields } = require ( '../lib/common' ) ;
811const { getState, setState } = require ( './functions/stateMachine' ) ;
912
1013const admin = require ( 'firebase-admin' ) ;
@@ -48,6 +51,8 @@ testsuites.forEach(testsuite => {
4851 t . true ( sut . replicateMasterToDetail . name === 'cloudFunction' ) ;
4952 t . truthy ( sut . replicateMasterToDetail . run ) ;
5053 } ) ;
54+ test ( `[${ name } ] test basic variable swap` , async t =>
55+ testVariableSwap ( sut , t , name ) ) ;
5156 test ( `[${ name } ] test simple replicate attributes` , async t =>
5257 testReplicateAttributes ( sut , t , name ) ) ;
5358 test ( `[${ name } ] test simple delete references` , async t =>
@@ -60,30 +65,93 @@ testsuites.forEach(testsuite => {
6065 test ( `[${ name } ] test delete with snapshot fields in target reference` , async t =>
6166 testDeleteSnapshotFieldReferences ( sut , t , name ) ) ;
6267 test ( `[${ name } ] test delete with missing snapshot fields in target reference` , async t =>
63- testDeleteMissingSnapshotFieldReferences ( sut , t , name ) ) ;
68+ testDeleteMissingFieldsReferences ( sut , t , name ) ) ;
6469} ) ;
6570
71+ async function testVariableSwap ( sut , t , name ) {
72+ // test no fields
73+ let collectionId = makeid ( ) ;
74+ let targetCollection = 'collection' ;
75+ let doc = {
76+ collectionId,
77+ } ;
78+
79+ let result = replaceReferenceWithFields ( doc , targetCollection ) ;
80+
81+ t . false ( result . hasFields ) ;
82+ t . is ( result . targetCollection , 'collection' ) ;
83+
84+ // Test one field
85+ targetCollection = 'collection/$collectionId/some_detail' ;
86+
87+ result = replaceReferenceWithFields ( doc , targetCollection ) ;
88+
89+ t . true ( result . hasFields ) ;
90+ t . is ( result . targetCollection , `collection/${ collectionId } /some_detail` ) ;
91+
92+ // Test multiple fields
93+ const testId = makeid ( ) ;
94+ const userId = makeid ( ) ;
95+ targetCollection = 'collection/$testId/some_detail/$userId' ;
96+ doc = {
97+ collectionId,
98+ testId,
99+ userId,
100+ } ;
101+
102+ result = replaceReferenceWithFields ( doc , targetCollection ) ;
103+
104+ t . true ( result . hasFields ) ;
105+ t . is ( result . targetCollection , `collection/${ testId } /some_detail/${ userId } ` ) ;
106+
107+ // Test missing field
108+ targetCollection = 'collection/$collectionId/some_detail' ;
109+
110+ const error = t . throws ( ( ) => {
111+ replaceReferenceWithFields ( { } , targetCollection ) ;
112+ } ) ;
113+ t . is ( error . message , 'integrify: Missing dynamic reference: [$collectionId]' ) ;
114+
115+ await t . pass ( ) ;
116+ }
117+
66118async function testReplicateAttributes ( sut , t , name ) {
67119 // Add a couple of detail documents to follow master
68120 const masterId = makeid ( ) ;
69- await db . collection ( 'detail1' ) . add ( { masterId : masterId } ) ;
121+ await db . collection ( 'detail1' ) . add ( {
122+ masterId : masterId ,
123+ } ) ;
70124 const nestedDocRef = db . collection ( 'somecoll' ) . doc ( 'somedoc' ) ;
71- await nestedDocRef . set ( { x : 1 } ) ;
72- await nestedDocRef . collection ( 'detail2' ) . add ( { masterId : masterId } ) ;
125+ await nestedDocRef . set ( {
126+ x : 1 ,
127+ } ) ;
128+ await nestedDocRef . collection ( 'detail2' ) . add ( {
129+ masterId : masterId ,
130+ } ) ;
73131
74132 // Call trigger to replicate attributes from master
75133 const beforeSnap = fft . firestore . makeDocumentSnapshot (
76134 { } ,
77135 `master/${ masterId } `
78136 ) ;
79137 const afterSnap = fft . firestore . makeDocumentSnapshot (
80- { masterField1 : 'after1' , masterField3 : 'after3' } ,
138+ {
139+ masterField1 : 'after1' ,
140+ masterField3 : 'after3' ,
141+ } ,
81142 `master/${ masterId } `
82143 ) ;
83144 const change = fft . makeChange ( beforeSnap , afterSnap ) ;
84145 const wrapped = fft . wrap ( sut . replicateMasterToDetail ) ;
85- setState ( { change : null , context : null } ) ;
86- await wrapped ( change , { params : { masterId : masterId } } ) ;
146+ setState ( {
147+ change : null ,
148+ context : null ,
149+ } ) ;
150+ await wrapped ( change , {
151+ params : {
152+ masterId : masterId ,
153+ } ,
154+ } ) ;
87155
88156 // Assert pre-hook was called (only for rules-in-situ)
89157 if ( name === 'rules-in-situ' ) {
@@ -111,22 +179,34 @@ async function testReplicateAttributes(sut, t, name) {
111179
112180 // Assert irrelevant update is safely ignored
113181 const irrelevantAfterSnap = fft . firestore . makeDocumentSnapshot (
114- { masterFieldIrrelevant : 'whatever' } ,
182+ {
183+ masterFieldIrrelevant : 'whatever' ,
184+ } ,
115185 `master/${ masterId } `
116186 ) ;
117187 const irreleventChange = fft . makeChange ( beforeSnap , irrelevantAfterSnap ) ;
118- await wrapped ( irreleventChange , { params : { masterId : masterId } } ) ;
188+ await wrapped ( irreleventChange , {
189+ params : {
190+ masterId : masterId ,
191+ } ,
192+ } ) ;
119193
120194 await t . pass ( ) ;
121195}
122196
123197async function testDeleteReferences ( sut , t , name ) {
124198 // Create some docs referencing master doc
125199 const masterId = makeid ( ) ;
126- await db . collection ( 'detail1' ) . add ( { masterId : masterId } ) ;
200+ await db . collection ( 'detail1' ) . add ( {
201+ masterId : masterId ,
202+ } ) ;
127203 const nestedDocRef = db . collection ( 'somecoll' ) . doc ( 'somedoc' ) ;
128- await nestedDocRef . set ( { x : 1 } ) ;
129- await nestedDocRef . collection ( 'detail2' ) . add ( { masterId : masterId } ) ;
204+ await nestedDocRef . set ( {
205+ x : 1 ,
206+ } ) ;
207+ await nestedDocRef . collection ( 'detail2' ) . add ( {
208+ masterId : masterId ,
209+ } ) ;
130210 await assertQuerySizeEventually (
131211 db
132212 . collection ( 'somecoll' )
@@ -139,8 +219,15 @@ async function testDeleteReferences(sut, t, name) {
139219 // Trigger function to delete references
140220 const snap = fft . firestore . makeDocumentSnapshot ( { } , `master/${ masterId } ` ) ;
141221 const wrapped = fft . wrap ( sut . deleteReferencesToMaster ) ;
142- setState ( { snap : null , context : null } ) ;
143- await wrapped ( snap , { params : { masterId : masterId } } ) ;
222+ setState ( {
223+ snap : null ,
224+ context : null ,
225+ } ) ;
226+ await wrapped ( snap , {
227+ params : {
228+ masterId : masterId ,
229+ } ,
230+ } ) ;
144231
145232 // Assert pre-hook was called (only for rules-in-situ)
146233 if ( name === 'rules-in-situ' ) {
@@ -265,6 +352,7 @@ async function testDeleteSnapshotFieldReferences(sut, t, name) {
265352 await wrapped ( snap , {
266353 params : {
267354 masterId : masterId ,
355+ testId : testId ,
268356 } ,
269357 } ) ;
270358
@@ -293,7 +381,7 @@ async function testDeleteSnapshotFieldReferences(sut, t, name) {
293381 t . pass ( ) ;
294382}
295383
296- async function testDeleteMissingSnapshotFieldReferences ( sut , t , name ) {
384+ async function testDeleteMissingFieldsReferences ( sut , t , name ) {
297385 // Create some docs referencing master doc
298386 const masterId = makeid ( ) ;
299387 const testId = makeid ( ) ;
@@ -318,17 +406,22 @@ async function testDeleteMissingSnapshotFieldReferences(sut, t, name) {
318406
319407 // Trigger function to delete references
320408 const snap = fft . firestore . makeDocumentSnapshot ( { } , `master/${ masterId } ` ) ;
321- const wrapped = fft . wrap ( sut . deleteReferencesWithSnapshotFields ) ;
409+ const wrapped = fft . wrap ( sut . deleteReferencesWithMissingFields ) ;
322410 setState ( {
323411 snap : null ,
324412 context : null ,
325413 } ) ;
326- await wrapped ( snap , {
327- params : {
328- masterId : masterId ,
329- } ,
414+
415+ const error = await t . throwsAsync ( async ( ) => {
416+ await wrapped ( snap , {
417+ params : {
418+ masterId : masterId ,
419+ } ,
420+ } ) ;
330421 } ) ;
331422
423+ t . is ( error . message , 'Error: integrify: Missing dynamic reference: [$testId]' ) ;
424+
332425 // Assert pre-hook was called (only for rules-in-situ)
333426 if ( name === 'rules-in-situ' ) {
334427 const state = getState ( ) ;
@@ -360,15 +453,19 @@ async function testMaintainCount(sut, t) {
360453 await db
361454 . collection ( 'articles' )
362455 . doc ( articleId )
363- . set ( { favoritesCount : 0 } ) ;
456+ . set ( {
457+ favoritesCount : 0 ,
458+ } ) ;
364459
365460 // Favorite the article a few times
366461 const NUM_TIMES_TO_FAVORITE = 5 ;
367462 const wrappedUpdater = fft . wrap ( sut . maintainFavoritesCount ) ;
368463 const promises = [ ] ;
369464 const emptySnap = fft . firestore . makeDocumentSnapshot ( { } ) ;
370465 const snap = fft . firestore . makeDocumentSnapshot (
371- { articleId : articleId } ,
466+ {
467+ articleId : articleId ,
468+ } ,
372469 `favorites/${ makeid ( ) } `
373470 ) ;
374471 for ( let i = 1 ; i <= NUM_TIMES_TO_FAVORITE ; ++ i ) {
@@ -413,10 +510,18 @@ async function testMaintainCount(sut, t) {
413510}
414511
415512test ( 'test error conditions' , async t => {
416- t . throws ( ( ) => integrify ( { } ) , { message : / I n p u t m u s t b e r u l e o r c o n f i g / i } ) ;
417- t . throws ( ( ) => integrify ( { rule : 'UNKNOWN_RULE_4a4e261a2e37' } ) , {
418- message : / U n k n o w n r u l e / i,
513+ t . throws ( ( ) => integrify ( { } ) , {
514+ message : / I n p u t m u s t b e r u l e o r c o n f i g / i,
419515 } ) ;
516+ t . throws (
517+ ( ) =>
518+ integrify ( {
519+ rule : 'UNKNOWN_RULE_4a4e261a2e37' ,
520+ } ) ,
521+ {
522+ message : / U n k n o w n r u l e / i,
523+ }
524+ ) ;
420525 t . throws ( ( ) => require ( './functions-bad-rules-file' ) , {
421526 message : / U n k n o w n r u l e / i,
422527 } ) ;
0 commit comments