question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Detox tests hang with pending items on dispatch queue

See original GitHub issue

Description

I am writing e2e tests on Detox to test a Firebase app. It looks like the call to firebase.auth().signInWithPhoneNumber(number) dispatches some items on the dispatch queue but these items don’t ever seem to be dequeued and therefore the tests cannot proceed. My hunch is that there is a network request being made by the sign in call that never resolves. Here is the log: Here is the log:

12:46:14.209 detox[41991] INFO:  [APP_STATUS] The app is busy with the following tasks:
• There are 2 work items pending on the dispatch queue: "Main Queue (<OS_dispatch_queue_main: com.apple.main-thread>)".
• Run loop "Main Run Loop" is awake.

I have read through this troubleshooting guide and it looks like the operation is on the Main thread (native) and the issue is a waiting too much issue.

Is there a way to inspect the items on the dispatch queue to further understand what they are? I have tried running the /usr/bin/xcrun simctl spawn <device> log stream --level debug --style compact --predicate 'process == "myapp"' but I don’t understand the output. If it is useful I can upload the logs.

I’m hoping I can post some logs of some sort and someone can help me to find the reason for the items on the dispatch queue. I have no experience with native development so device system logs and Objective C/Swift code mean nothing to me. Thanks

Your environment

Detox version: 19.4.2 React Native version: 0.67.4 Node version: v12.22.6 Device model: iPhone 11 Simulator OS: iOS Test-runner (select one): jest-circus

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:10
  • Comments:5

github_iconTop GitHub Comments

1reaction
glesperancecommented, Jul 15, 2022

I am having the exact same issue.

On our side, the interaction happening relates to:

  1. RNFirebase/Auth
  2. Detox
  3. Expo SDK >= 43 (using unimodules expo SDK=42 resolves the issue.)
  • Making the signInWithPhoneNumber call into a promise does not help.
  • ::Taking out the firebaseAuth().signInWithPhoneNumber() call out into another view reproduces the synchronization problem::
  • Pulling the problematic RNFB auth call further up the app chain always leads to the synchronisation problem.

I have inspected the RNFB/Auth implementation and it is rather simple. The blocking call ends up being:

// node_modules/@react-native-firebase/auth/ios/RNFBAuthModule.m:

RCT_EXPORT_METHOD(signInWithPhoneNumber
                  : (FIRApp *)firebaseApp
                  : (NSString *)phoneNumber
                  : (RCTPromiseResolveBlock)resolve
                  : (RCTPromiseRejectBlock)reject) {
  [[FIRPhoneAuthProvider providerWithAuth:[FIRAuth authWithApp:firebaseApp]]
      verifyPhoneNumber:phoneNumber
             UIDelegate:nil
             completion:^(NSString *_Nullable verificationID, NSError *_Nullable error) {
               if (error) {
                 [self promiseRejectAuthException:reject error:error];
               } else {
                 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                 [defaults setObject:verificationID forKey:@"authVerificationID"];
                 resolve(@{@"verificationId" : verificationID});
               }
             }];
}

which eventually makes it here:

// Pods/FirebaseAuth/FIRPhoneAuthProvider.m
- (void)internalVerifyPhoneNumber:(NSString *)phoneNumber
                       UIDelegate:(nullable id<FIRAuthUIDelegate>)UIDelegate
                       completion:(nullable FIRVerificationResultCallback)completion {
  if (!phoneNumber.length) {
    completion(nil, [FIRAuthErrorUtils missingPhoneNumberErrorWithMessage:nil]);
    return;
  }
  [_auth.notificationManager
      checkNotificationForwardingWithCallback:^(BOOL isNotificationBeingForwarded) {
        if (!isNotificationBeingForwarded) {
          completion(nil, [FIRAuthErrorUtils notificationNotForwardedError]);
          return;
        }
        FIRVerificationResultCallback callback =
            ^(NSString *_Nullable verificationID, NSError *_Nullable error) {
              if (completion) {
                completion(verificationID, error);
              }
            };
        [self verifyClientAndSendVerificationCodeToPhoneNumber:phoneNumber
                                   retryOnInvalidAppCredential:YES
                                                    UIDelegate:UIDelegate
                                                      callback:callback];
      }];
}

which calls into the problematic function:

- (void)checkNotificationForwardingWithCallback:(FIRAuthNotificationForwardingCallback)callback {
  if (_pendingCallbacks) {
    [_pendingCallbacks addObject:callback];
    return;
  }
  if (_hasCheckedNotificationForwarding) {
    callback(_isNotificationBeingForwarded);
    return;
  }
  _hasCheckedNotificationForwarding = YES;
  _pendingCallbacks =
      [[NSMutableArray<FIRAuthNotificationForwardingCallback> alloc] initWithObjects:callback, nil];
  dispatch_async(dispatch_get_main_queue(), ^{
    NSDictionary *proberNotification = @{
      kNotificationDataKey : @{
        kNotificationProberKey : @"This fake notification should be forwarded to Firebase Auth."
      }
    };
    if ([self->_application.delegate
            respondsToSelector:@selector(application:
                                   didReceiveRemoteNotification:fetchCompletionHandler:)]) {
      [self->_application.delegate application:self->_application
                  didReceiveRemoteNotification:proberNotification
                        fetchCompletionHandler:^(UIBackgroundFetchResult result){
                        }];
#if !TARGET_OS_TV
    } else if ([self->_application.delegate
                   respondsToSelector:@selector(application:didReceiveRemoteNotification:)]) {
// iOS 10 deprecation
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
      [self->_application.delegate application:self->_application
                  didReceiveRemoteNotification:proberNotification];
#pragma clang diagnostic pop
#endif
    } else {
      FIRLogWarning(kFIRLoggerAuth, @"I-AUT000015",
                    @"The UIApplicationDelegate must handle remote notification for phone number "
                    @"authentication to work.");
    }
  });
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_timeout * NSEC_PER_SEC)),
                 FIRAuthGlobalWorkQueue(), ^{
                   [self callBack];
                 });
}

I haven’t fully dissected the above function but refactoring internalVerifyPhoneNumber such that it doesn’t call checkNotificationForwardingWithCallback allows detox to progress.

@DerrickAfrifa could you tell me what versions of RNFirebase/Expo you are running? @d4vidi would you have any pointers explaining why detox fails to synchronise when checkNotificationForwardingWithCallback is called?

Another mystery here is why is this bug related to updating expo to SDK 45…

0reactions
glesperancecommented, Jul 17, 2022

A PR is in progress (see above ^) for this to be fixed upstream, but in the meantime you can refer to this stack overflow answer for a fix.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Detox tests hang with pending items on dispatch queue
To answer the question: No,there is no easy way to inspect the dispatch queue. You must go through the internals of the app,...
Read more >
Dealing With Synchronization Issues in Tests | Detox
Instead, Detox tries to synchronize the test with the app completely automatically. ... There are 1 work items pending on the dispatch queue:...
Read more >
Detox: Writing Stable Test Suites | Wix Engineering - Medium
Issue: Tests hang and time out​​ Detox manages sync between the app and test code, and waits for the app to go idle....
Read more >
ios - Detox tests hang with pending items on dispatch queue - Stack ...
I am writing e2e tests on Detox to test a Firebase app in React Native. It looks like the call to firebase.auth().signInWithPhoneNumber(number) dispatches ......
Read more >
Dispatch Queue | Apple Developer Documentation
Attempting to synchronously execute a work item on the main queue results in deadlock. Dispatch queues provide minimal support for autoreleased objects by ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found