diff --git a/bridge/e2e/firestore/transactions.e2e.js b/bridge/e2e/firestore/transactions.e2e.js index bb6ce321..25aa1c33 100644 --- a/bridge/e2e/firestore/transactions.e2e.js +++ b/bridge/e2e/firestore/transactions.e2e.js @@ -1,77 +1,161 @@ -const should = require('should'); +const { testDocRef } = TestHelpers.firestore; describe('firestore()', () => { describe('runTransaction()', () => { - it('should set, update and delete transactionally and allow a return value', async () => { - let deleteMe = false; + it('should set() values', async () => { const firestore = firebase.firestore(); - - const docRef = firestore - .collection('transactions') - .doc(Date.now().toString()); + const docRef = testDocRef('tSet'); const updateFunction = async transaction => { const doc = await transaction.get(docRef); - if (doc.exists && deleteMe) { - transaction.delete(docRef); - return 'bye'; - } - if (!doc.exists) { - transaction.set(docRef, { value: 1 }); + transaction.set(docRef, { value: 1, somethingElse: 'set' }); return 1; } - const newValue = doc.data().value + 1; - - if (newValue > 2) { - return Promise.reject( - new Error('Value should not be greater than 2!') - ); - } - - transaction.update(docRef, { - value: newValue, - somethingElse: 'update', - }); - - return newValue; + return 0; }; - // set tests - const val1 = await firestore.runTransaction(updateFunction); - should.equal(val1, 1); - const doc1 = await docRef.get(); - doc1.data().value.should.equal(1); - should.equal(doc1.data().somethingElse, undefined); + const result = await firestore.runTransaction(updateFunction); + should.equal(result, 1); + const finalDoc = await docRef.get(); + finalDoc.data().value.should.equal(1); + finalDoc.data().somethingElse.should.equal('set'); + }); - // update - const val2 = await firestore.runTransaction(updateFunction); - should.equal(val2, 2); - const doc2 = await docRef.get(); - doc2.data().value.should.equal(2); - doc2.data().somethingElse.should.equal('update'); + it('should update() values', async () => { + const firestore = firebase.firestore(); + const docRef = testDocRef('tUpdate'); - // rejecting / cancelling transaction + await docRef.set({ value: 1 }); + + const updateFunction = async transaction => { + const doc = await transaction.get(docRef); + if (doc.exists) { + transaction.update(docRef, { + value: doc.data().value + 1, + somethingElse: 'update', + }); + return 1; + } + + return 0; + }; + + const result = await firestore.runTransaction(updateFunction); + should.equal(result, 1); + + const finalDoc = await docRef.get(); + finalDoc.data().value.should.equal(2); + finalDoc.data().somethingElse.should.equal('update'); + }); + + it('should delete() values', async () => { + const firestore = firebase.firestore(); + const docRef = testDocRef('tDelete'); + await docRef.set({ value: 1, somethingElse: 'delete' }); + + const updateFunction = async transaction => { + const doc = await transaction.get(docRef); + if (doc.exists) { + transaction.delete(docRef); + return 1; + } + + return 0; + }; + + const result = await firestore.runTransaction(updateFunction); + should.equal(result, 1); + + const finalDoc = await docRef.get(); + finalDoc.exists.should.equal(false); + }); + + it('error if updateFn does return a promise', async () => { + const firestore = firebase.firestore(); + + // test async functions - they always return a promise in JS let didReject = false; + let updateFunction = async () => 1; try { await firestore.runTransaction(updateFunction); } catch (e) { didReject = true; } + should.equal(didReject, false); + + // should not error as a promise returned + didReject = false; + updateFunction = () => Promise.resolve(); + try { + await firestore.runTransaction(updateFunction); + } catch (e) { + didReject = true; + } + should.equal(didReject, false); + + // should error as no promise returned + didReject = false; + updateFunction = () => '123456'; + try { + await firestore.runTransaction(updateFunction); + } catch (e) { + didReject = true; + e.message.includes('must return a Promise'); + } should.equal(didReject, true); - const doc3 = await docRef.get(); - doc3.data().value.should.equal(2); - doc3.data().somethingElse.should.equal('update'); + }); - // delete - deleteMe = true; - const val4 = await firestore.runTransaction(updateFunction); - should.equal(val4, 'bye'); - const doc4 = await docRef.get(); - should.equal(doc4.exists, false); + it('updateFn promise rejections / js exceptions handled', async () => { + const firestore = firebase.firestore(); - return Promise.resolve('Test Completed'); + // rejections + let didReject = false; + let updateFunction = () => Promise.reject('shoop'); + try { + await firestore.runTransaction(updateFunction); + } catch (e) { + didReject = true; + should.equal(e, 'shoop'); + } + should.equal(didReject, true); + + // exceptions + didReject = false; + updateFunction = () => { + // eslint-disable-next-line no-throw-literal + throw 'doop'; + }; + try { + await firestore.runTransaction(updateFunction); + } catch (e) { + didReject = true; + should.equal(e, 'doop'); + } + should.equal(didReject, true); + }); + + it('handle native exceptions', async () => { + const firestore = firebase.firestore(); + const docRef = testDocRef('tSet'); + const blockedRef = firestore.doc('blocked-collection/foo'); + + const updateFunction = async transaction => { + await transaction.get(docRef); + transaction.set(blockedRef, { value: 1, somethingElse: 'set' }); + return 1; + }; + + // rejections + let didReject = false; + try { + await firestore.runTransaction(updateFunction); + } catch (e) { + e.message.should.containEql('firestore/failed-precondition'); + didReject = true; + } + should.equal(didReject, true); }); }); });