diff --git a/.gitignore b/.gitignore index 3bcdc962..830ad41f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,16 +14,16 @@ xcuserdata/ # Android # Built application files -android/*/build/ +**/android/**/build/ # Crashlytics configuations android/com_crashlytics_export_strings.xml # Local configuration file (sdk path, etc) -android/local.properties +**/android/local.properties # Gradle generated files -android/.gradle/ +**/android/.gradle/ # Signing files android/.signing/ @@ -41,7 +41,7 @@ android/.idea/misc.xml android/.idea/modules.xml android/.idea/scopes/scope_settings.xml android/.idea/vcs.xml -android/*.iml +**/android/**/*.iml ios/RnFirebase.xcodeproj/xcuserdata # OS-specific files @@ -60,3 +60,6 @@ android/gradle/ .idea coverage yarn.lock + +**/ios/Pods/** +**/ios/ReactNativeFirebaseDemo.xcworkspace/ diff --git a/ios/RNFirebase/RNFirebaseDatabase.m b/ios/RNFirebase/RNFirebaseDatabase.m index 4220f8b7..462eb06f 100644 --- a/ios/RNFirebase/RNFirebaseDatabase.m +++ b/ios/RNFirebase/RNFirebaseDatabase.m @@ -5,64 +5,61 @@ @interface RNFirebaseDBReference : NSObject @property RCTEventEmitter *emitter; @property FIRDatabaseQuery *query; +@property NSNumber *refId; @property NSString *path; -@property NSString *modifiersString; @property NSMutableDictionary *listeners; -@property FIRDatabaseHandle childAddedHandler; -@property FIRDatabaseHandle childModifiedHandler; -@property FIRDatabaseHandle childRemovedHandler; -@property FIRDatabaseHandle childMovedHandler; -@property FIRDatabaseHandle childValueHandler; + (NSDictionary *) snapshotToDict:(FIRDataSnapshot *) snapshot; @end @implementation RNFirebaseDBReference + - (id) initWithPathAndModifiers:(RCTEventEmitter *) emitter database:(FIRDatabase *) database + refId:(NSNumber *) refId path:(NSString *) path modifiers:(NSArray *) modifiers - modifiersString:(NSString *) modifiersString { self = [super init]; if (self) { _emitter = emitter; + _refId = refId; _path = path; - _modifiersString = modifiersString; _query = [self buildQueryAtPathWithModifiers:database path:path modifiers:modifiers]; _listeners = [[NSMutableDictionary alloc] init]; } return self; } -- (void) addEventHandler:(NSString *) eventName +- (void) addEventHandler:(NSNumber *) listenerId + eventName:(NSString *) eventName { - if (![self isListeningTo:eventName]) { + if (![_listeners objectForKey:listenerId]) { id withBlock = ^(FIRDataSnapshot * _Nonnull snapshot) { NSDictionary *props = [RNFirebaseDBReference snapshotToDict:snapshot]; [self sendJSEvent:DATABASE_DATA_EVENT title:eventName props: @{ @"eventName": eventName, + @"refId": _refId, + @"listenerId": listenerId, @"path": _path, - @"modifiersString": _modifiersString, @"snapshot": props }]; }; id errorBlock = ^(NSError * _Nonnull error) { NSLog(@"Error onDBEvent: %@", [error debugDescription]); - [self unsetListeningOn:eventName]; + [self removeEventHandler:listenerId eventName:eventName]; [self getAndSendDatabaseError:error - path:_path - modifiersString:_modifiersString]; + listenerId:listenerId]; }; int eventType = [self eventTypeFromName:eventName]; FIRDatabaseHandle handle = [_query observeEventType:eventType withBlock:withBlock withCancelBlock:errorBlock]; - [self setEventHandler:handle forName:eventName]; + [_listeners setObject:@(handle) forKey:listenerId]; } else { - NSLog(@"Warning Trying to add duplicate listener for type: %@ with modifiers: %@ for path: %@", eventName, _modifiersString, _path); + NSLog(@"Warning Trying to add duplicate listener for refId: %@ listenerId: %@", _refId, listenerId); } } @@ -74,7 +71,7 @@ callback(@[[NSNull null], @{ @"eventName": @"value", @"path": _path, - @"modifiersString": _modifiersString, + @"refId": _refId, @"snapshot": props }]); } @@ -83,7 +80,7 @@ callback(@[@{ @"eventName": DATABASE_ERROR_EVENT, @"path": _path, - @"modifiers": _modifiersString, + @"refId": _refId, @"code": @([error code]), @"details": [error debugDescription], @"message": [error localizedDescription], @@ -92,44 +89,14 @@ }]; } -- (void) removeEventHandler:(NSString *) name +- (void) removeEventHandler:(NSNumber *) listenerId + eventName:(NSString *) eventName { - int eventType = [self eventTypeFromName:name]; - switch (eventType) { - case FIRDataEventTypeValue: - if (self.childValueHandler != nil) { - [_query removeObserverWithHandle:self.childValueHandler]; - self.childValueHandler = nil; - } - break; - case FIRDataEventTypeChildAdded: - if (self.childAddedHandler != nil) { - [_query removeObserverWithHandle:self.childAddedHandler]; - self.childAddedHandler = nil; - } - break; - case FIRDataEventTypeChildChanged: - if (self.childModifiedHandler != nil) { - [_query removeObserverWithHandle:self.childModifiedHandler]; - self.childModifiedHandler = nil; - } - break; - case FIRDataEventTypeChildRemoved: - if (self.childRemovedHandler != nil) { - [_query removeObserverWithHandle:self.childRemovedHandler]; - self.childRemovedHandler = nil; - } - break; - case FIRDataEventTypeChildMoved: - if (self.childMovedHandler != nil) { - [_query removeObserverWithHandle:self.childMovedHandler]; - self.childMovedHandler = nil; - } - break; - default: - break; + FIRDatabaseHandle handle = [[_listeners objectForKey:listenerId] integerValue]; + if (handle) { + [_listeners removeObjectForKey:listenerId]; + [_query removeObserverWithHandle:handle]; } - [self unsetListeningOn:name]; } + (NSDictionary *) snapshotToDict:(FIRDataSnapshot *) snapshot @@ -159,21 +126,19 @@ } - (NSDictionary *) getAndSendDatabaseError:(NSError *) error - path:(NSString *) path - modifiersString:(NSString *) modifiersString + listenerId:(NSNumber *) listenerId { NSDictionary *event = @{ @"eventName": DATABASE_ERROR_EVENT, - @"path": path, - @"modifiers": modifiersString, + @"path": _path, + @"refId": _refId, + @"listenerId": listenerId, @"code": @([error code]), @"details": [error debugDescription], @"message": [error localizedDescription], @"description": [error description] }; - - // [self sendJSEvent:DATABASE_ERROR_EVENT title:DATABASE_ERROR_EVENT props: event]; - + @try { [_emitter sendEventWithName:DATABASE_ERROR_EVENT body:event]; } @@ -181,7 +146,7 @@ NSLog(@"An error occurred in getAndSendDatabaseError: %@", [err debugDescription]); NSLog(@"Tried to send: %@ with %@", DATABASE_ERROR_EVENT, event); } - + return event; } @@ -194,70 +159,59 @@ } } - - (FIRDatabaseQuery *) buildQueryAtPathWithModifiers:(FIRDatabase*) database path:(NSString*) path modifiers:(NSArray *) modifiers { FIRDatabaseQuery *query = [[database reference] child:path]; - - for (NSString *str in modifiers) { - if ([str isEqualToString:@"orderByKey"]) { - query = [query queryOrderedByKey]; - } else if ([str isEqualToString:@"orderByPriority"]) { - query = [query queryOrderedByPriority]; - } else if ([str isEqualToString:@"orderByValue"]) { - query = [query queryOrderedByValue]; - } else if ([str containsString:@"orderByChild"]) { - NSArray *args = [str componentsSeparatedByString:@":"]; - NSString *key = args[1]; - query = [query queryOrderedByChild:key]; - } else if ([str containsString:@"limitToLast"]) { - NSArray *args = [str componentsSeparatedByString:@":"]; - NSString *key = args[1]; - NSUInteger limit = key.integerValue; - query = [query queryLimitedToLast:limit]; - } else if ([str containsString:@"limitToFirst"]) { - NSArray *args = [str componentsSeparatedByString:@":"]; - NSString *key = args[1]; - NSUInteger limit = key.integerValue; - query = [query queryLimitedToFirst:limit]; - } else if ([str containsString:@"equalTo"]) { - NSArray *args = [str componentsSeparatedByString:@":"]; - int size = (int)[args count];; - id value = [self getIdValue:args[1] type:args[2]]; - if (size > 3) { - NSString *key = args[3]; - query = [query queryEqualToValue:value - childKey:key]; - } else { - query = [query queryEqualToValue:value]; + + for (NSDictionary *modifier in modifiers) { + NSString *type = [modifier valueForKey:@"type"]; + NSString *name = [modifier valueForKey:@"name"]; + if ([type isEqualToString:@"orderBy"]) { + if ([name isEqualToString:@"orderByKey"]) { + query = [query queryOrderedByKey]; + } else if ([name isEqualToString:@"orderByPriority"]) { + query = [query queryOrderedByPriority]; + } else if ([name isEqualToString:@"orderByValue"]) { + query = [query queryOrderedByValue]; + } else if ([name isEqualToString:@"orderByChild"]) { + NSString *key = [modifier valueForKey:@"key"]; + query = [query queryOrderedByChild:key]; } - } else if ([str containsString:@"endAt"]) { - NSArray *args = [str componentsSeparatedByString:@":"]; - int size = (int)[args count];; - id value = [self getIdValue:args[1] type:args[2]]; - if (size > 3) { - NSString *key = args[3]; - query = [query queryEndingAtValue:value - childKey:key]; - } else { - query = [query queryEndingAtValue:value]; + } else if ([type isEqualToString:@"limit"]) { + int limit = [[modifier valueForKey:@"limit"] integerValue]; + if ([name isEqualToString:@"limitToLast"]) { + query = [query queryLimitedToLast:limit]; + } else if ([name isEqualToString:@"limitToFirst"]) { + query = [query queryLimitedToFirst:limit]; } - } else if ([str containsString:@"startAt"]) { - NSArray *args = [str componentsSeparatedByString:@":"]; - id value = [self getIdValue:args[1] type:args[2]]; - int size = (int)[args count];; - if (size > 3) { - NSString *key = args[3]; - query = [query queryStartingAtValue:value - childKey:key]; - } else { - query = [query queryStartingAtValue:value]; + } else if ([type isEqualToString:@"filter"]) { + NSString* valueType = [modifier valueForKey:@"valueType"]; + NSString* key = [modifier valueForKey:@"key"]; + id value = [self getIdValue:[modifier valueForKey:@"value"] type:valueType]; + if ([name isEqualToString:@"equalTo"]) { + if (key != nil) { + query = [query queryEqualToValue:value childKey:key]; + } else { + query = [query queryEqualToValue:value]; + } + } else if ([name isEqualToString:@"endAt"]) { + if (key != nil) { + query = [query queryEndingAtValue:value childKey:key]; + } else { + query = [query queryEndingAtValue:value]; + } + } else if ([name isEqualToString:@"startAt"]) { + if (key != nil) { + query = [query queryStartingAtValue:value childKey:key]; + } else { + query = [query queryStartingAtValue:value]; + } } } } - + return query; } @@ -273,62 +227,15 @@ } } -- (void) setEventHandler:(FIRDatabaseHandle) handle - forName:(NSString *) name -{ - int eventType = [self eventTypeFromName:name]; - switch (eventType) { - case FIRDataEventTypeValue: - self.childValueHandler = handle; - break; - case FIRDataEventTypeChildAdded: - self.childAddedHandler = handle; - break; - case FIRDataEventTypeChildChanged: - self.childModifiedHandler = handle; - break; - case FIRDataEventTypeChildRemoved: - self.childRemovedHandler = handle; - break; - case FIRDataEventTypeChildMoved: - self.childMovedHandler = handle; - break; - default: - break; - } - [self setListeningOn:name withHandle:handle]; -} - -- (void) setListeningOn:(NSString *) name - withHandle:(FIRDatabaseHandle) handle -{ - [_listeners setValue:@(handle) forKey:name]; -} - -- (void) unsetListeningOn:(NSString *) name -{ - [_listeners removeObjectForKey:name]; -} - -- (BOOL) isListeningTo:(NSString *) name -{ - return [_listeners valueForKey:name] != nil; -} - - (BOOL) hasListeners { return [[_listeners allKeys] count] > 0; } -- (NSArray *) listenerKeys -{ - return [_listeners allKeys]; -} - - (int) eventTypeFromName:(NSString *)name { int eventType = FIRDataEventTypeValue; - + if ([name isEqualToString:DATABASE_VALUE_EVENT]) { eventType = FIRDataEventTypeValue; } else if ([name isEqualToString:DATABASE_CHILD_ADDED_EVENT]) { @@ -343,24 +250,6 @@ return eventType; } -- (void) cleanup { - if (self.childValueHandler > 0) { - [self removeEventHandler:DATABASE_VALUE_EVENT]; - } - if (self.childAddedHandler > 0) { - [self removeEventHandler:DATABASE_CHILD_ADDED_EVENT]; - } - if (self.childModifiedHandler > 0) { - [self removeEventHandler:DATABASE_CHILD_MODIFIED_EVENT]; - } - if (self.childRemovedHandler > 0) { - [self removeEventHandler:DATABASE_CHILD_REMOVED_EVENT]; - } - if (self.childMovedHandler > 0) { - [self removeEventHandler:DATABASE_CHILD_MOVED_EVENT]; - } -} - @end @@ -393,27 +282,27 @@ RCT_EXPORT_METHOD(startTransaction:(NSString *) path identifier:(NSString *) ide dispatch_semaphore_t sema = dispatch_semaphore_create(0); [transactionState setObject:sema forKey:@"semaphore"]; FIRDatabaseReference *ref = [self getPathRef:path]; - + [ref runTransactionBlock:^FIRTransactionResult * _Nonnull(FIRMutableData * _Nonnull currentData) { dispatch_barrier_async(_transactionQueue, ^{ [_transactions setValue:transactionState forKey:identifier]; [self sendTransactionEvent:DATABASE_TRANSACTION_EVENT body:@{ @"id": identifier, @"type": @"update", @"value": currentData.value }]; }); - + // wait for the js event handler to call tryCommitTransaction // this wait occurs on the Firebase Worker Queue // so if the tryCommitTransaction fails to signal the semaphore // no further blocks will be executed by Firebase until the timeout expires dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC); BOOL timedout = dispatch_semaphore_wait(sema, delayTime) != 0; - + BOOL abort = [transactionState valueForKey:@"abort"] || timedout; id value = [transactionState valueForKey:@"value"]; - + dispatch_barrier_async(_transactionQueue, ^{ [_transactions removeObjectForKey:identifier]; }); - + if (abort) { return [FIRTransactionResult abort]; } else { @@ -442,34 +331,34 @@ RCT_EXPORT_METHOD(startTransaction:(NSString *) path identifier:(NSString *) ide RCT_EXPORT_METHOD(tryCommitTransaction:(NSString *) identifier withData:(NSDictionary *) data) { __block NSMutableDictionary *transactionState; - + dispatch_sync(_transactionQueue, ^{ transactionState = [_transactions objectForKey: identifier]; }); - + if (!transactionState) { NSLog(@"tryCommitTransaction for unknown ID %@", identifier); return; } - + dispatch_semaphore_t sema = [transactionState valueForKey:@"semaphore"]; - + BOOL abort = [[data valueForKey:@"abort"] boolValue]; - + if (abort) { [transactionState setValue:@true forKey:@"abort"]; } else { id newValue = [data valueForKey:@"value"]; [transactionState setValue:newValue forKey:@"value"]; } - + dispatch_semaphore_signal(sema); } RCT_EXPORT_METHOD(enablePersistence:(BOOL) enable callback:(RCTResponseSenderBlock) callback) { - + BOOL isEnabled = [FIRDatabase database].persistenceEnabled; if ( isEnabled != enable) { [FIRDatabase database].persistenceEnabled = enable; @@ -526,10 +415,10 @@ RCT_EXPORT_METHOD(push:(NSString *) path { FIRDatabaseReference *ref = [self getPathRef:path]; FIRDatabaseReference *newRef = [ref childByAutoId]; - + NSURL *url = [NSURL URLWithString:newRef.URL]; NSString *newPath = [url path]; - + if ([data count] > 0) { [newRef setValue:[data valueForKey:@"value"] withCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) { if (error != nil) { @@ -540,7 +429,7 @@ RCT_EXPORT_METHOD(push:(NSString *) path @"message": [error localizedDescription], @"description": [error description] }; - + callback(@[evt]); } else { callback(@[[NSNull null], @{ @@ -558,58 +447,50 @@ RCT_EXPORT_METHOD(push:(NSString *) path } - -RCT_EXPORT_METHOD(on:(NSString *) path - modifiersString:(NSString *) modifiersString +RCT_EXPORT_METHOD(on:(nonnull NSNumber *) refId + path:(NSString *) path modifiers:(NSArray *) modifiers + listenerId:(nonnull NSNumber *) listenerId name:(NSString *) eventName callback:(RCTResponseSenderBlock) callback) { - RNFirebaseDBReference *ref = [self getDBHandle:path modifiers:modifiers modifiersString:modifiersString]; - [ref addEventHandler:eventName]; + RNFirebaseDBReference *ref = [self getDBHandle:refId path:path modifiers:modifiers]; + [ref addEventHandler:listenerId eventName:eventName]; callback(@[[NSNull null], @{ @"status": @"success", + @"refId": refId, @"handle": path }]); } -RCT_EXPORT_METHOD(once:(NSString *) path - modifiersString:(NSString *) modifiersString +RCT_EXPORT_METHOD(once:(nonnull NSNumber *) refId + path:(NSString *) path modifiers:(NSArray *) modifiers - name:(NSString *) name - callback:(RCTResponseSenderBlock) callback) -{ - RNFirebaseDBReference *ref = [self getDBHandle:path modifiers:modifiers modifiersString:modifiersString]; - [ref addSingleEventHandler:callback]; -} - -RCT_EXPORT_METHOD(off:(NSString *)path - modifiersString:(NSString *) modifiersString eventName:(NSString *) eventName callback:(RCTResponseSenderBlock) callback) { - NSString *key = [self getDBListenerKey:path withModifiers:modifiersString]; - NSArray *listenerKeys; - RNFirebaseDBReference *ref = [_dbReferences objectForKey:key]; - if (ref == nil) { - listenerKeys = @[]; - } else { - if (eventName == nil || [eventName isEqualToString:@""]) { - [ref cleanup]; - [_dbReferences removeObjectForKey:key]; - } else { - [ref removeEventHandler:eventName]; + RNFirebaseDBReference *ref = [self getDBHandle:refId path:path modifiers:modifiers]; + [ref addSingleEventHandler:callback]; +} + +RCT_EXPORT_METHOD(off:(nonnull NSNumber *) refId + listeners:(NSArray *) listeners + callback:(RCTResponseSenderBlock) callback) +{ + RNFirebaseDBReference *ref = [_dbReferences objectForKey:refId]; + if (ref != nil) { + for (NSDictionary *listener in listeners) { + NSNumber *listenerId = [listener valueForKey:@"listenerId"]; + NSString *eventName = [listener valueForKey:@"eventName"]; + [ref removeEventHandler:listenerId eventName:eventName]; if (![ref hasListeners]) { - [_dbReferences removeObjectForKey:key]; + [_dbReferences removeObjectForKey:refId]; } } - listenerKeys = [ref listenerKeys]; } callback(@[[NSNull null], @{ - @"result": @"success", - @"handle": path, - @"modifiersString": modifiersString, - @"remainingListeners": listenerKeys, + @"status": @"success", + @"refId": refId, }]); } @@ -680,30 +561,23 @@ RCT_EXPORT_METHOD(goOnline) } } -- (RNFirebaseDBReference *) getDBHandle:(NSString *) path - modifiers:modifiers - modifiersString:modifiersString +- (RNFirebaseDBReference *) getDBHandle:(NSNumber *) refId + path:(NSString *) path + modifiers:(NSArray *) modifiers { - NSString *key = [self getDBListenerKey:path withModifiers:modifiersString]; - RNFirebaseDBReference *ref = [_dbReferences objectForKey:key]; - + RNFirebaseDBReference *ref = [_dbReferences objectForKey:refId]; + if (ref == nil) { ref = [[RNFirebaseDBReference alloc] initWithPathAndModifiers:self database:[FIRDatabase database] + refId:refId path:path - modifiers:modifiers - modifiersString:modifiersString]; - [_dbReferences setObject:ref forKey:key]; + modifiers:modifiers]; + [_dbReferences setObject:ref forKey:refId]; } return ref; } -- (NSString *) getDBListenerKey:(NSString *) path - withModifiers:(NSString *) modifiersString -{ - return [NSString stringWithFormat:@"%@ | %@", path, modifiersString, nil]; -} - // Not sure how to get away from this... yet - (NSArray *)supportedEvents { return @[DATABASE_DATA_EVENT, DATABASE_ERROR_EVENT, DATABASE_TRANSACTION_EVENT]; diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index 6e4a1e09..00000000 --- a/tests/.gitignore +++ /dev/null @@ -1,61 +0,0 @@ -# OSX -# -.DS_Store - -# Xcode -# -build/ -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata -*.xccheckout -*.moved-aside -DerivedData -*.hmap -*.ipa -*.xcuserstate -project.xcworkspace - -# Android/IntelliJ -# - -android/gradle -.idea -.gradle -local.properties -*.iml - -# node.js -# -node_modules/ -ios/Pods -npm-debug.log -yarn-error.log -yarn.lock -npm-debug* - -# BUCK -buck-out/ -\.buckd/ -*.keystore - -# fastlane -# -# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the -# screenshots whenever they are needed. -# For more information about the recommended setup visit: -# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md - -fastlane/report.xml -fastlane/Preview.html -fastlane/screenshots -ios/Podfile -ios/Podfile.lock -ios/Pods/ -ios/ReactNativeFirebaseDemo.xcworkspace/ diff --git a/tests/ios/Podfile b/tests/ios/Podfile new file mode 100644 index 00000000..f3805033 --- /dev/null +++ b/tests/ios/Podfile @@ -0,0 +1,40 @@ +install! 'cocoapods', :deterministic_uuids => false +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +target 'ReactNativeFirebaseDemo' do + platform :ios, '8.0' + # Uncomment this line if you're using Swift or would like to use dynamic frameworks + # use_frameworks! + + # Pods for ReactNativeFirebaseDemo + pod 'React', :path => '../node_modules/react-native', :subspecs => [ + 'Core', + 'RCTActionSheet', + 'RCTAnimation', + 'RCTCameraRoll', + 'RCTGeolocation', + 'RCTImage', + 'RCTLinkingIOS', + 'RCTNetwork', + 'RCTPushNotification', + 'RCTSettings', + 'RCTText', + 'RCTVibration', + 'RCTWebSocket' + # Add any other subspecs you want to use in your project + ] + + pod 'Firebase/Auth' + pod 'Firebase/Analytics' + pod 'Firebase/AppIndexing' + pod 'Firebase/Core' + pod 'Firebase/Crash' + pod 'Firebase/Database' + pod 'Firebase/DynamicLinks' + pod 'Firebase/Messaging' + pod 'Firebase/RemoteConfig' + pod 'Firebase/Storage' + + pod 'RNFirebase', :path => '../node_modules/react-native-firebase' +end diff --git a/tests/ios/Podfile.lock b/tests/ios/Podfile.lock new file mode 100644 index 00000000..28cc8d2e --- /dev/null +++ b/tests/ios/Podfile.lock @@ -0,0 +1,177 @@ +PODS: + - Firebase/Analytics (3.15.0): + - Firebase/Core + - Firebase/AppIndexing (3.15.0): + - Firebase/Core + - FirebaseAppIndexing (= 1.2.0) + - Firebase/Auth (3.15.0): + - Firebase/Core + - FirebaseAuth (= 3.1.1) + - Firebase/Core (3.15.0): + - FirebaseAnalytics (= 3.7.0) + - FirebaseCore (= 3.5.2) + - Firebase/Crash (3.15.0): + - Firebase/Core + - FirebaseCrash (= 1.1.6) + - Firebase/Database (3.15.0): + - Firebase/Core + - FirebaseDatabase (= 3.1.2) + - Firebase/DynamicLinks (3.15.0): + - Firebase/Core + - FirebaseDynamicLinks (= 1.3.4) + - Firebase/Messaging (3.15.0): + - Firebase/Core + - FirebaseMessaging (= 1.2.2) + - Firebase/RemoteConfig (3.15.0): + - Firebase/Core + - FirebaseRemoteConfig (= 1.3.4) + - Firebase/Storage (3.15.0): + - Firebase/Core + - FirebaseStorage (= 1.1.0) + - FirebaseAnalytics (3.7.0): + - FirebaseCore (~> 3.5) + - FirebaseInstanceID (~> 1.0) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseAppIndexing (1.2.0) + - FirebaseAuth (3.1.1): + - FirebaseAnalytics (~> 3.7) + - GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1) + - GTMSessionFetcher/Core (~> 1.1) + - FirebaseCore (3.5.2): + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - FirebaseCrash (1.1.6): + - FirebaseAnalytics (~> 3.7) + - FirebaseInstanceID (~> 1.0) + - GoogleToolboxForMac/Logger (~> 2.1) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - Protobuf (~> 3.1) + - FirebaseDatabase (3.1.2): + - FirebaseAnalytics (~> 3.7) + - FirebaseDynamicLinks (1.3.4): + - FirebaseAnalytics (~> 3.7) + - FirebaseInstanceID (1.0.9) + - FirebaseMessaging (1.2.2): + - FirebaseAnalytics (~> 3.7) + - FirebaseInstanceID (~> 1.0) + - GoogleToolboxForMac/Logger (~> 2.1) + - Protobuf (~> 3.1) + - FirebaseRemoteConfig (1.3.4): + - FirebaseAnalytics (~> 3.7) + - FirebaseInstanceID (~> 1.0) + - GoogleToolboxForMac/NSData+zlib (~> 2.1) + - Protobuf (~> 3.1) + - FirebaseStorage (1.1.0): + - FirebaseAnalytics (~> 3.7) + - GTMSessionFetcher/Core (~> 1.1) + - GoogleToolboxForMac/DebugUtils (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/Defines (2.1.1) + - GoogleToolboxForMac/Logger (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSData+zlib (2.1.1): + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSDictionary+URLArguments (2.1.1): + - GoogleToolboxForMac/DebugUtils (= 2.1.1) + - GoogleToolboxForMac/Defines (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (= 2.1.1) + - GoogleToolboxForMac/NSString+URLArguments (2.1.1) + - GTMSessionFetcher/Core (1.1.9) + - Protobuf (3.2.0) + - React (0.40.0): + - React/Core (= 0.40.0) + - React/Core (0.40.0): + - React/cxxreact + - React/yoga + - React/cxxreact (0.40.0): + - React/jschelpers + - React/jschelpers (0.40.0) + - React/RCTActionSheet (0.40.0): + - React/Core + - React/RCTAnimation (0.40.0): + - React/Core + - React/RCTCameraRoll (0.40.0): + - React/Core + - React/RCTImage + - React/RCTGeolocation (0.40.0): + - React/Core + - React/RCTImage (0.40.0): + - React/Core + - React/RCTNetwork + - React/RCTLinkingIOS (0.40.0): + - React/Core + - React/RCTNetwork (0.40.0): + - React/Core + - React/RCTPushNotification (0.40.0): + - React/Core + - React/RCTSettings (0.40.0): + - React/Core + - React/RCTText (0.40.0): + - React/Core + - React/RCTVibration (0.40.0): + - React/Core + - React/RCTWebSocket (0.40.0): + - React/Core + - React/yoga (0.40.0) + - RNFirebase (1.0.0-alpha12): + - Firebase/Auth + - Firebase/Core + - Firebase/Database + - Firebase/Messaging + - Firebase/RemoteConfig + - Firebase/Storage + - React + +DEPENDENCIES: + - Firebase/Analytics + - Firebase/AppIndexing + - Firebase/Auth + - Firebase/Core + - Firebase/Crash + - Firebase/Database + - Firebase/DynamicLinks + - Firebase/Messaging + - Firebase/RemoteConfig + - Firebase/Storage + - React/Core (from `../node_modules/react-native`) + - React/RCTActionSheet (from `../node_modules/react-native`) + - React/RCTAnimation (from `../node_modules/react-native`) + - React/RCTCameraRoll (from `../node_modules/react-native`) + - React/RCTGeolocation (from `../node_modules/react-native`) + - React/RCTImage (from `../node_modules/react-native`) + - React/RCTLinkingIOS (from `../node_modules/react-native`) + - React/RCTNetwork (from `../node_modules/react-native`) + - React/RCTPushNotification (from `../node_modules/react-native`) + - React/RCTSettings (from `../node_modules/react-native`) + - React/RCTText (from `../node_modules/react-native`) + - React/RCTVibration (from `../node_modules/react-native`) + - React/RCTWebSocket (from `../node_modules/react-native`) + - RNFirebase (from `../node_modules/react-native-firebase`) + +EXTERNAL SOURCES: + React: + :path: "../node_modules/react-native" + RNFirebase: + :path: "../node_modules/react-native-firebase" + +SPEC CHECKSUMS: + Firebase: 2b1cdfba1cda8589f32904a697cc753322bff9d8 + FirebaseAnalytics: 0d1b7d81d5021155be37702a94ba1ec16d45365d + FirebaseAppIndexing: d0fa52ce0ad13f4b5b2f09e4b47fb0dc2213f4e9 + FirebaseAuth: cc8a1824170adbd351edb7f994490a3fb5c18be6 + FirebaseCore: a024587e43778508700af8c6b1209f7c4516ba02 + FirebaseCrash: db4c05d9c75baa050744d31b36357c8f1efba481 + FirebaseDatabase: 05c96d7b43a7368dc91c07791adb49683e1738d1 + FirebaseDynamicLinks: 30fb0856dd9ae6d8ba4da00972141a5c293a27b2 + FirebaseInstanceID: 2d0518b1378fe9d685ef40cbdd63d2fdc1125339 + FirebaseMessaging: df8267f378580a24174ce7861233aa11d5c90109 + FirebaseRemoteConfig: af3003f4e8daa2bd1d5cf90d3cccc1fe224f8ed9 + FirebaseStorage: a5c55b23741a49a72af8f30f95b3bb5ddbeda12d + GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0 + GTMSessionFetcher: 5c046c76a1f859bc9c187e918f18e4fc7bb57b5e + Protobuf: 745f59e122e5de98d4d7ef291e264a0eef80f58e + React: 6dfb2f72edb1d74a800127ae157af038646673ce + RNFirebase: 228c16667a3ed1ba3b9ff0702449dca3be1c3618 + +PODFILE CHECKSUM: 23445e2727726988c7338fa2f396980d6fd3906f + +COCOAPODS: 1.2.0 diff --git a/tests/src/tests/database/ref/offTests.js b/tests/src/tests/database/ref/offTests.js index fb31184f..f92d1d2a 100644 --- a/tests/src/tests/database/ref/offTests.js +++ b/tests/src/tests/database/ref/offTests.js @@ -1,3 +1,4 @@ +import { Platform } from 'react-native'; import should from 'should'; import sinon from 'sinon'; @@ -89,9 +90,10 @@ function offTests({ describe, it, xcontext, context, firebase }) { // Check childAddedCallback is really attached await ref.push(DatabaseContents.DEFAULT.number); - // Android Note: There is definitely a single listener, but value is called three times + // TODO: Android: There is definitely a single listener, but value is called three times // rather than the two you'd perhaps expect - valueCallback.should.be.callCount(3); + const expectedCount = Platform.OS === 'ios' ? 2 : 3; + valueCallback.should.be.callCount(expectedCount); childAddedCallback.should.be.callCount(arrayLength + 1); // Returns nothing @@ -104,7 +106,7 @@ function offTests({ describe, it, xcontext, context, firebase }) { await ref.push(DatabaseContents.DEFAULT.number); // Callbacks should have been unbound and not called again - valueCallback.should.be.callCount(3); + valueCallback.should.be.callCount(expectedCount); childAddedCallback.should.be.callCount(arrayLength + 1); }); }); @@ -265,9 +267,10 @@ function offTests({ describe, it, xcontext, context, firebase }) { // Callback should have been called only once because one of the attachments // has been removed - // Android Note: There is definitely a single listener, but value is called twice + // TODO: Android: There is definitely a single listener, but value is called twice // rather than the once you'd perhaps expect - spyA.should.be.callCount(4); + const expectedCount = Platform.OS === 'ios' ? 3 : 4; + spyA.should.be.callCount(expectedCount); // Undo the second attachment const resp2 = await ref.off('value', callbackA); @@ -277,7 +280,7 @@ function offTests({ describe, it, xcontext, context, firebase }) { await ref.set(DatabaseContents.DEFAULT.number); // Callback should not have been called any more times - spyA.should.be.callCount(4); + spyA.should.be.callCount(expectedCount); }); }); });