From ff3b0fd7ea1bfe2719d75f3f26cf568d6ac039c2 Mon Sep 17 00:00:00 2001 From: Salakar Date: Tue, 1 May 2018 22:20:55 +0100 Subject: [PATCH 1/7] [firestore][js] start of blob support --- lib/modules/firestore/Blob.js | 71 +++++++++++++++++++++++++++ lib/modules/firestore/utils/Base64.js | 68 +++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 lib/modules/firestore/Blob.js create mode 100644 lib/modules/firestore/utils/Base64.js diff --git a/lib/modules/firestore/Blob.js b/lib/modules/firestore/Blob.js new file mode 100644 index 00000000..7714ec34 --- /dev/null +++ b/lib/modules/firestore/Blob.js @@ -0,0 +1,71 @@ +import Base64 from './utils/Base64'; + +type BlobFormat = 'string' | 'array'; + +export default class Blob { + constructor(data, type: BlobFormat) { + this._data = data; + this._type = type; + } + + /** + * Creates a new Blob from the given Base64 string + * @url https://firebase.google.com/docs/reference/js/firebase.firestore.Blob#.fromBase64String + * @param base64 string + */ + static fromBase64String(base64: string): Blob { + // TODO convert to Uint8Array? + return new Blob(base64, 'string'); + } + + /** + * Creates a new Blob from the given Uint8Array. + * @url https://firebase.google.com/docs/reference/js/firebase.firestore.Blob#.fromUint8Array + * @param array Array + */ + static fromUint8Array(array: Array): Blob { + return new Blob(array, 'array'); + } + + /** + * Returns 'true' if this Blob is equal to the provided one. + * @url https://firebase.google.com/docs/reference/js/firebase.firestore.Blob#isEqual + * @param {*} blob Blob The Blob to compare against. Value must not be null. + * @returns boolean 'true' if this Blob is equal to the provided one. + */ + isEqual(blob: Blob): boolean { + // TODO comparison checks + console.log(blob); + return true; + } + + /** + * Returns the bytes of a Blob as a Base64-encoded string. + * @url https://firebase.google.com/docs/reference/js/firebase.firestore.Blob#toBase64 + * @returns string The Base64-encoded string created from the Blob object. + */ + toBase64(): string { + if (this._type === 'string') return this._data; + + let binary = ''; + const len = this._data.byteLength; + for (let i = 0; i < len; i++) { + binary += String.fromCharCode(this._data[i]); + } + + return Base64.btoa(binary); + } + + /** + * Returns the bytes of a Blob in a new Uint8Array. + * @url https://firebase.google.com/docs/reference/js/firebase.firestore.Blob#toUint8Array + * @returns non-null Uint8Array The Uint8Array created from the Blob object. + */ + toUint8Array(): Uint8Array { + if (this._type === 'array') return this._data; + // TODO conversion + // TODO conversion + // TODO conversion + return new Uint8Array(); + } +} diff --git a/lib/modules/firestore/utils/Base64.js b/lib/modules/firestore/utils/Base64.js new file mode 100644 index 00000000..1f7ec120 --- /dev/null +++ b/lib/modules/firestore/utils/Base64.js @@ -0,0 +1,68 @@ +// @flow +/* eslint-disable */ + +const CHARS = + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + +export default { + /** + * window.btoa + */ + btoa(input: string = ''): string { + let map; + let i = 0; + let block = 0; + let output = ''; + + // eslint-disable-next-line + for ( + block = 0, i = 0, map = CHARS; + input.charAt(i | 0) || ((map = '='), i % 1); + output += map.charAt(63 & (block >> (8 - (i % 1) * 8))) + ) { + const charCode = input.charCodeAt((i += 3 / 4)); + + if (charCode > 0xff) { + throw new Error( + "'btoa' failed: The string to be encoded contains characters outside of the Latin1 range." + ); + } + + block = (block << 8) | charCode; + } + + return output; + }, + + /** + * window.atob + */ + atob(input: string = ''): string { + let i = 0; + let bc = 0; + let bs = 0; + let buffer; + let output = ''; + + const str = input.replace(/=+$/, ''); + + if (str.length % 4 === 1) { + throw new Error( + "'atob' failed: The string to be decoded is not correctly encoded." + ); + } + + // eslint-disable-next-line + for ( + bc = 0, bs = 0, i = 0; + (buffer = str.charAt(i++)); + ~buffer && ((bs = bc % 4 ? bs * 64 + buffer : buffer), bc++ % 4) + ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6)))) + : 0 + ) { + buffer = CHARS.indexOf(buffer); + } + + return output; + }, +}; From d180b40d196dd4067ba7a65c7bf2c1e05b826f66 Mon Sep 17 00:00:00 2001 From: Salakar Date: Wed, 2 May 2018 10:05:30 +0100 Subject: [PATCH 2/7] [firestore][js] blob uint8 coversion + blob comparator --- lib/modules/firestore/Blob.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/modules/firestore/Blob.js b/lib/modules/firestore/Blob.js index 7714ec34..63f02c6a 100644 --- a/lib/modules/firestore/Blob.js +++ b/lib/modules/firestore/Blob.js @@ -3,6 +3,9 @@ import Base64 from './utils/Base64'; type BlobFormat = 'string' | 'array'; export default class Blob { + _data: Uint8Array | string; + _type: BlobFormat; + constructor(data, type: BlobFormat) { this._data = data; this._type = type; @@ -14,7 +17,6 @@ export default class Blob { * @param base64 string */ static fromBase64String(base64: string): Blob { - // TODO convert to Uint8Array? return new Blob(base64, 'string'); } @@ -23,7 +25,7 @@ export default class Blob { * @url https://firebase.google.com/docs/reference/js/firebase.firestore.Blob#.fromUint8Array * @param array Array */ - static fromUint8Array(array: Array): Blob { + static fromUint8Array(array: Uint8Array): Blob { return new Blob(array, 'array'); } @@ -34,9 +36,15 @@ export default class Blob { * @returns boolean 'true' if this Blob is equal to the provided one. */ isEqual(blob: Blob): boolean { - // TODO comparison checks - console.log(blob); - return true; + let thisBlobBase64 = ''; + if (this._type === 'string') thisBlobBase64 = this._data; + else thisBlobBase64 = this.toBase64(); + + let thatBlobBase64 = ''; + if (blob._type === 'string') thatBlobBase64 = blob._data; + else thatBlobBase64 = blob.toBase64(); + + return thisBlobBase64 === thatBlobBase64; } /** @@ -63,9 +71,10 @@ export default class Blob { */ toUint8Array(): Uint8Array { if (this._type === 'array') return this._data; - // TODO conversion - // TODO conversion - // TODO conversion - return new Uint8Array(); + return new Uint8Array( + Base64.atob(this._data) + .split('') + .map(c => c.charCodeAt(0)) + ); } } From 5906d20ce0ec3f0a21651adbf2c1f054bb88970d Mon Sep 17 00:00:00 2001 From: Salakar Date: Thu, 3 May 2018 20:12:46 +0100 Subject: [PATCH 3/7] [firestore][ios] implement Blob support --- .../firestore/RNFirebaseFirestoreDocumentReference.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m b/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m index 6fe78759..49646047 100644 --- a/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m +++ b/ios/RNFirebase/firestore/RNFirebaseFirestoreDocumentReference.m @@ -208,6 +208,10 @@ static NSMutableDictionary *_listeners; typeMap[@"type"] = @"number"; } typeMap[@"value"] = value; + } else if ([value isKindOfClass:[NSData class]]) { + typeMap[@"type"] = @"blob"; + NSData *blob = (NSData *)value; + typeMap[@"value"] = [blob base64EncodedStringWithOptions:0]; } else { // TODO: Log an error typeMap[@"type"] = @"null"; @@ -248,6 +252,8 @@ static NSMutableDictionary *_listeners; return [RNFirebaseFirestoreDocumentReference parseJSMap:firestore jsMap:value]; } else if ([type isEqualToString:@"reference"]) { return [firestore documentWithPath:value]; + } else if ([type isEqualToString:@"blob"]) { + return [[NSData alloc] initWithBase64EncodedString:(NSString *) value options:0]; } else if ([type isEqualToString:@"geopoint"]) { NSDictionary *geopoint = (NSDictionary*)value; NSNumber *latitude = geopoint[@"latitude"]; From 9c49d9ef57a984ef53e88d13e3d0c8b3bcac565a Mon Sep 17 00:00:00 2001 From: Salakar Date: Thu, 3 May 2018 20:13:51 +0100 Subject: [PATCH 4/7] [firestore][js] implement Blob support --- lib/modules/firestore/Blob.js | 65 +++++++++++++----------- lib/modules/firestore/index.js | 2 + lib/modules/firestore/types.js | 1 + lib/modules/firestore/utils/Base64.js | 4 +- lib/modules/firestore/utils/serialize.js | 8 +++ 5 files changed, 48 insertions(+), 32 deletions(-) diff --git a/lib/modules/firestore/Blob.js b/lib/modules/firestore/Blob.js index 63f02c6a..3d8149e9 100644 --- a/lib/modules/firestore/Blob.js +++ b/lib/modules/firestore/Blob.js @@ -1,32 +1,40 @@ import Base64 from './utils/Base64'; -type BlobFormat = 'string' | 'array'; - export default class Blob { - _data: Uint8Array | string; - _type: BlobFormat; + _binaryString: string; - constructor(data, type: BlobFormat) { - this._data = data; - this._type = type; + constructor(binaryString) { + this._binaryString = binaryString; } /** * Creates a new Blob from the given Base64 string + * * @url https://firebase.google.com/docs/reference/js/firebase.firestore.Blob#.fromBase64String * @param base64 string */ static fromBase64String(base64: string): Blob { - return new Blob(base64, 'string'); + return new Blob(Base64.atob(base64)); } /** * Creates a new Blob from the given Uint8Array. + * * @url https://firebase.google.com/docs/reference/js/firebase.firestore.Blob#.fromUint8Array * @param array Array */ static fromUint8Array(array: Uint8Array): Blob { - return new Blob(array, 'array'); + if (!(array instanceof Uint8Array)) { + throw new Error( + 'firestore.Blob.fromUint8Array expects an instance of Uint8Array' + ); + } + + return new Blob( + Array.prototype.map + .call(array, (char: number) => String.fromCharCode(char)) + .join('') + ); } /** @@ -36,45 +44,42 @@ export default class Blob { * @returns boolean 'true' if this Blob is equal to the provided one. */ isEqual(blob: Blob): boolean { - let thisBlobBase64 = ''; - if (this._type === 'string') thisBlobBase64 = this._data; - else thisBlobBase64 = this.toBase64(); + if (!(blob instanceof Blob)) { + throw new Error('firestore.Blob.isEqual expects an instance of Blob'); + } - let thatBlobBase64 = ''; - if (blob._type === 'string') thatBlobBase64 = blob._data; - else thatBlobBase64 = blob.toBase64(); - - return thisBlobBase64 === thatBlobBase64; + return this._binaryString === blob._binaryString; } /** * Returns the bytes of a Blob as a Base64-encoded string. + * * @url https://firebase.google.com/docs/reference/js/firebase.firestore.Blob#toBase64 * @returns string The Base64-encoded string created from the Blob object. */ toBase64(): string { - if (this._type === 'string') return this._data; - - let binary = ''; - const len = this._data.byteLength; - for (let i = 0; i < len; i++) { - binary += String.fromCharCode(this._data[i]); - } - - return Base64.btoa(binary); + return Base64.btoa(this._binaryString); } /** * Returns the bytes of a Blob in a new Uint8Array. + * * @url https://firebase.google.com/docs/reference/js/firebase.firestore.Blob#toUint8Array * @returns non-null Uint8Array The Uint8Array created from the Blob object. */ toUint8Array(): Uint8Array { - if (this._type === 'array') return this._data; return new Uint8Array( - Base64.atob(this._data) - .split('') - .map(c => c.charCodeAt(0)) + this._binaryString.split('').map(c => c.charCodeAt(0)) ); } + + /** + * Returns a string representation of this blob instance + * + * @returns {string} + * @memberof Blob + */ + toString(): string { + return `firestore.Blob(base64: ${this.toBase64()})`; + } } diff --git a/lib/modules/firestore/index.js b/lib/modules/firestore/index.js index d0e6d60e..80fe4678 100644 --- a/lib/modules/firestore/index.js +++ b/lib/modules/firestore/index.js @@ -11,6 +11,7 @@ import DocumentReference from './DocumentReference'; import FieldPath from './FieldPath'; import FieldValue from './FieldValue'; import GeoPoint from './GeoPoint'; +import Blob from './Blob'; import Path from './Path'; import WriteBatch from './WriteBatch'; import TransactionHandler from './TransactionHandler'; @@ -258,6 +259,7 @@ export const statics = { FieldPath, FieldValue, GeoPoint, + Blob, enableLogging(enabled: boolean): void { // DEPRECATED: Remove method in v4.1.0 console.warn( diff --git a/lib/modules/firestore/types.js b/lib/modules/firestore/types.js index 6ed935dc..3dd1f4a6 100644 --- a/lib/modules/firestore/types.js +++ b/lib/modules/firestore/types.js @@ -42,6 +42,7 @@ export type NativeTypeMap = { | 'array' | 'boolean' | 'date' + | 'blob' | 'documentid' | 'fieldvalue' | 'geopoint' diff --git a/lib/modules/firestore/utils/Base64.js b/lib/modules/firestore/utils/Base64.js index 1f7ec120..a9ef56a2 100644 --- a/lib/modules/firestore/utils/Base64.js +++ b/lib/modules/firestore/utils/Base64.js @@ -24,7 +24,7 @@ export default { if (charCode > 0xff) { throw new Error( - "'btoa' failed: The string to be encoded contains characters outside of the Latin1 range." + "'firestore.utils.btoa' failed: The string to be encoded contains characters outside of the Latin1 range." ); } @@ -48,7 +48,7 @@ export default { if (str.length % 4 === 1) { throw new Error( - "'atob' failed: The string to be decoded is not correctly encoded." + "'firestore.utils.atob' failed: The string to be decoded is not correctly encoded." ); } diff --git a/lib/modules/firestore/utils/serialize.js b/lib/modules/firestore/utils/serialize.js index 8ea8a5d7..79b0ad0c 100644 --- a/lib/modules/firestore/utils/serialize.js +++ b/lib/modules/firestore/utils/serialize.js @@ -3,6 +3,7 @@ */ import DocumentReference from '../DocumentReference'; +import Blob from '../Blob'; import { DOCUMENT_ID } from '../FieldPath'; import { DELETE_FIELD_VALUE, @@ -98,6 +99,11 @@ export const buildTypeMap = (value: any): NativeTypeMap | null => { type: 'date', value: value.getTime(), }; + } else if (value instanceof Blob) { + return { + type: 'blob', + value: value.toBase64(), + }; } return { type: 'object', @@ -156,6 +162,8 @@ const parseTypeMap = (firestore: Firestore, typeMap: NativeTypeMap): any => { return new GeoPoint(value.latitude, value.longitude); } else if (type === 'date') { return new Date(value); + } else if (type === 'blob') { + return Blob.fromBase64String(value); } console.warn(`Unknown data type received ${type}`); return value; From a8cefc4425792b1042f54539ca89e89c1edacbc1 Mon Sep 17 00:00:00 2001 From: Salakar Date: Thu, 3 May 2018 20:14:23 +0100 Subject: [PATCH 5/7] [tests][firestore] implement Blob support --- bridge/e2e/firestore/blob.e2e.js | 114 +++++++++++++++++++++++++++++++ bridge/helpers/index.js | 44 +++++++++++- 2 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 bridge/e2e/firestore/blob.e2e.js diff --git a/bridge/e2e/firestore/blob.e2e.js b/bridge/e2e/firestore/blob.e2e.js new file mode 100644 index 00000000..6c228f66 --- /dev/null +++ b/bridge/e2e/firestore/blob.e2e.js @@ -0,0 +1,114 @@ +const testObject = { hello: 'world', testRunId }; +const testString = JSON.stringify(testObject); +const testBuffer = Buffer.from(testString); +const testBase64 = testBuffer.toString('base64'); + +const testObjectLarge = new Array(5000).fill(testObject); +const testStringLarge = JSON.stringify(testObjectLarge); +const testBufferLarge = Buffer.from(testStringLarge); +const testBase64Large = testBufferLarge.toString('base64'); + +// function sizeInKiloBytes(base64String) { +// return 4 * Math.ceil(base64String.length / 3) / 1000; +// } + +// console.log(sizeInKiloBytes(testBase64)); +// console.log(sizeInKiloBytes(testBase64Large)); + +/** ---------------- + * CLASS TESTS + * -----------------*/ +describe('firestore', () => { + it('should export Blob class on statics', async () => { + const { Blob } = firebase.firestore; + should.exist(Blob); + }); + + describe('Blob', () => { + it('.constructor() -> returns new instance of Blob', async () => { + const { Blob } = firebase.firestore; + const myBlob = new Blob(testStringLarge); + myBlob.should.be.instanceOf(Blob); + myBlob._binaryString.should.equal(testStringLarge); + myBlob.toBase64().should.equal(testBase64Large); + }); + + it('.fromBase64String() -> returns new instance of Blob', async () => { + const { Blob } = firebase.firestore; + const myBlob = Blob.fromBase64String(testBase64); + myBlob.should.be.instanceOf(Blob); + myBlob._binaryString.should.equal(testString); + should.deepEqual( + JSON.parse(myBlob._binaryString), + testObject, + 'Expected Blob _binaryString internals to serialize to json and match test object' + ); + }); + + it('.fromUint8Array() -> returns new instance of Blob', async () => { + const testUInt8Array = new Uint8Array(testBuffer); + const { Blob } = firebase.firestore; + const myBlob = Blob.fromUint8Array(testUInt8Array); + myBlob.should.be.instanceOf(Blob); + const json = JSON.parse(myBlob._binaryString); + json.hello.should.equal('world'); + }); + }); + + describe('Blob instance', () => { + it('.toString() -> returns string representation of blob instance', async () => { + const { Blob } = firebase.firestore; + const myBlob = Blob.fromBase64String(testBase64); + myBlob.should.be.instanceOf(Blob); + should.equal( + myBlob.toString().includes(testBase64), + true, + 'toString() should return a string that includes the base64' + ); + }); + + it('.toBase64() -> returns base64 string', async () => { + const { Blob } = firebase.firestore; + const myBlob = Blob.fromBase64String(testBase64); + myBlob.should.be.instanceOf(Blob); + myBlob.toBase64().should.equal(testBase64); + }); + + it('.toUint8Array() -> returns Uint8Array', async () => { + const { Blob } = firebase.firestore; + const myBlob = Blob.fromBase64String(testBase64); + const testUInt8Array = new Uint8Array(testBuffer); + const testUInt8Array2 = new Uint8Array(); + + myBlob.should.be.instanceOf(Blob); + should.deepEqual(myBlob.toUint8Array(), testUInt8Array); + should.notDeepEqual(myBlob.toUint8Array(), testUInt8Array2); + }); + }); +}); + +/** ---------------- + * USAGE TESTS + * -----------------*/ + +describe.only('firestore', () => { + describe('Blob', () => { + it('reads and writes blobs', async () => { + const { Blob } = firebase.firestore; + + await firebase + .firestore() + .doc('blob-tests/small') + .set({ blobby: Blob.fromBase64String(testBase64) }); + + const snapshot = await firebase + .firestore() + .doc('blob-tests/small') + .get(); + + const blob = snapshot.data().blobby; + blob._binaryString.should.equal(testString); + blob.toBase64().should.equal(testBase64); + }); + }); +}); diff --git a/bridge/helpers/index.js b/bridge/helpers/index.js index fc08ea22..bc8dfabc 100644 --- a/bridge/helpers/index.js +++ b/bridge/helpers/index.js @@ -9,6 +9,38 @@ Object.defineProperty(global, 'firebase', { }, }); +// TODO move as part of bridge +const { Uint8Array } = global; +Object.defineProperty(global, 'Uint8Array', { + get() { + const { stack } = new Error(); + if ( + (stack.includes('Context.it') || stack.includes('Context.beforeEach')) && + global.bridge && + global.bridge.context + ) { + return bridge.context.window.Uint8Array; + } + return Uint8Array; + }, +}); + +// TODO move as part of bridge +const { Array } = global; +Object.defineProperty(global, 'Array', { + get() { + const { stack } = new Error(); + if ( + (stack.includes('Context.it') || stack.includes('Context.beforeEach')) && + global.bridge && + global.bridge.context + ) { + return bridge.context.window.Array; + } + return Array; + }, +}); + global.isObject = function isObject(item) { return item ? typeof item === 'object' && !Array.isArray(item) && item !== null @@ -30,11 +62,17 @@ global.randomString = (length, chars) => { } return result; }; - -global.firebaseAdmin = require('firebase-admin'); - global.testRunId = randomString(4, 'aA#'); +/** ------------------ + * Init WEB SDK + ---------------------*/ + +/** ------------------ + * Init ADMIN SDK + ---------------------*/ +global.firebaseAdmin = require('firebase-admin'); + firebaseAdmin.initializeApp({ credential: firebaseAdmin.credential.cert(require('./service-account')), databaseURL: 'https://rnfirebase-b9ad4.firebaseio.com', From 912335062acfbb1f98d1b5a0f344620867edb8ec Mon Sep 17 00:00:00 2001 From: Salakar Date: Thu, 3 May 2018 20:56:55 +0100 Subject: [PATCH 6/7] [firestore][android] implement Blob support --- .../firebase/firestore/FirestoreSerialize.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java b/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java index d35e44d5..90291179 100644 --- a/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java +++ b/android/src/main/java/io/invertase/firebase/firestore/FirestoreSerialize.java @@ -1,14 +1,15 @@ package io.invertase.firebase.firestore; +import android.util.Base64; import android.util.Log; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMapKeySetIterator; -import com.facebook.react.bridge.ReadableType; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; +import com.google.firebase.firestore.Blob; import com.google.firebase.firestore.DocumentChange; import com.google.firebase.firestore.DocumentReference; import com.google.firebase.firestore.DocumentSnapshot; @@ -18,15 +19,11 @@ import com.google.firebase.firestore.FirebaseFirestore; import com.google.firebase.firestore.GeoPoint; import com.google.firebase.firestore.QuerySnapshot; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.TimeZone; import io.invertase.firebase.Utils; @@ -214,6 +211,9 @@ public class FirestoreSerialize { } else if (value instanceof Date) { typeMap.putString("type", "date"); typeMap.putDouble("value", ((Date) value).getTime()); + } else if (value instanceof Blob) { + typeMap.putString("type", "blob"); + typeMap.putString("value", Base64.encodeToString(((Blob) value).toBytes(), Base64.NO_WRAP)); } else { Log.e(TAG, "buildTypeMap: Cannot convert object of type " + value.getClass()); typeMap.putString("type", "null"); @@ -266,6 +266,9 @@ public class FirestoreSerialize { } else if ("geopoint".equals(type)) { ReadableMap geoPoint = typeMap.getMap("value"); return new GeoPoint(geoPoint.getDouble("latitude"), geoPoint.getDouble("longitude")); + } else if ("blob".equals(type)) { + String base64String = typeMap.getString("value"); + return Blob.fromBytes(Base64.decode(base64String, Base64.NO_WRAP)); } else if ("date".equals(type)) { Double time = typeMap.getDouble("value"); return new Date(time.longValue()); From 93dc585ac3d8619945fb5755f48d7c6be1b98f20 Mon Sep 17 00:00:00 2001 From: Salakar Date: Thu, 3 May 2018 21:02:07 +0100 Subject: [PATCH 7/7] [tests][firestore] added large and small sized blob read/write tests --- bridge/e2e/firestore/blob.e2e.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/bridge/e2e/firestore/blob.e2e.js b/bridge/e2e/firestore/blob.e2e.js index 6c228f66..380cdd64 100644 --- a/bridge/e2e/firestore/blob.e2e.js +++ b/bridge/e2e/firestore/blob.e2e.js @@ -91,9 +91,9 @@ describe('firestore', () => { * USAGE TESTS * -----------------*/ -describe.only('firestore', () => { +describe('firestore', () => { describe('Blob', () => { - it('reads and writes blobs', async () => { + it('reads and writes small blobs', async () => { const { Blob } = firebase.firestore; await firebase @@ -110,5 +110,23 @@ describe.only('firestore', () => { blob._binaryString.should.equal(testString); blob.toBase64().should.equal(testBase64); }); + + it('reads and writes large blobs', async () => { + const { Blob } = firebase.firestore; + + await firebase + .firestore() + .doc('blob-tests/large') + .set({ blobby: Blob.fromBase64String(testBase64Large) }); + + const snapshot = await firebase + .firestore() + .doc('blob-tests/large') + .get(); + + const blob = snapshot.data().blobby; + blob._binaryString.should.equal(testStringLarge); + blob.toBase64().should.equal(testBase64Large); + }); }); });