0

I have a test which uses a WebView to login to the application (done in a hacky way by using a text input with a button + injectedJavaScript as WebView instrumentation is not supported).

The problem appears because the login operation inside the WebView happens asynchronously and breaks the Detox synchronization, so I have to manage it myself manually with disableSynchronization and enableSynchronization. After the login I have a stack transition animation to a new screen (from react-navigation) and I need to press a button on that screen to go further. However Detox still fails to synchronize with that screen so I am using tap to press on the button with synchronization disabled.

This is where the problem happens, the tap doesn't always work, and in 50% of the time just fails with a timeout for any action done after the disableSynchronization call. This makes the tests flaky and pretty much useless

Can anyone recommend a workaround or knows what the problem is?

Environment Detox: 12.10.3. React Native: 0.59.8 Node: v11.7.0 Device: iOS Emulator (iPhone 8) OS: iOS

I tried disabling and enabling the synchronisation before and after the tap on the button but it did not help, and in fact made the test fail with a timeout.

The code of my login method:

export const loginAs = async (userID) => {
  await element(by.id('introLoginBtn')).tap();
  await expect(element(by.id('loginScreen'))).toBeVisible();

  const userIdInput = element(by.id('testUserIdInput'));
  await userIdInput.tap();
  await userIdInput.typeText(userID);
  await element(by.id('testLoginBtn')).tap();

  // NOTE: WebView login breaks synchronization see 
  // https://github.com/wix/Detox/blob/master/docs/Troubleshooting.Synchronization.md
  await device.disableSynchronization();

  // Waiting for the element to be visible
  await waitFor(element(by.id('acceptTermsBtn'))).toBeVisible().withTimeout(9000);

  // This does not work consistently
  await element(by.id('acceptTermsBtn')).tap();

  await device.enableSynchronization();
};

When I get in the debug console with --debug-synchronization 200:

detox[33941] INFO:  [actions.js] Sync Timer: Tracking Timer <__NSCFTimer: 0x600003e6de00>
detox[33941] INFO:  [actions.js] Sync Timed: performSelector @selector(removeInactiveFingerTips) on DTXTouchVisualizerWindow
detox[33941] INFO:  [actions.js] Sync Timed: animateWithDuration:delay:options:animations:completion:
detox[33941] INFO:  [actions.js] Sync JavaScript Timers: Javascript Timers
detox[33941] INFO:  [actions.js] Sync App State: undefined
detox[33941] INFO:  [actions.js] Sync Dispatch Queue: com.apple.main-thread
detox[33941] INFO:  [actions.js] Sync Timed: performSelector @selector(removeFromSuperview) on COSTouchSpotView
detox[33941] INFO:  [actions.js] Sync Timed: animateWithDuration:delay:options:animations:completion:
detox[33941] INFO:  [actions.js] Sync Timed: performSelector @selector(removeInactiveFingerTips) on DTXTouchVisualizerWindow
detox[33941] INFO:  [actions.js] Sync Timed: animateWithDuration:delay:options:animations:completion:
detox[33941] INFO:  [actions.js] Sync JavaScript Timers: Javascript Timers
detox[33941] INFO:  [actions.js] Sync App State: undefined
detox[33941] INFO:  [actions.js] Sync Dispatch Queue: com.apple.main-thread
detox[33941] INFO:  [actions.js] Sync Timed: performSelector @selector(removeInactiveFingerTips) on DTXTouchVisualizerWindow
detox[33941] INFO:  [actions.js] Sync Timed: performSelector @selector(removeFromSuperview) on COSTouchSpotView
detox[33941] INFO:  [actions.js] Sync Timed: animateWithDuration:delay:options:animations:completion:
detox[33941] INFO:  [actions.js] Sync JavaScript Timers: Javascript Timers
detox[33941] INFO:  [actions.js] Sync App State: undefined
detox[33941] INFO:  [actions.js] Sync Dispatch Queue: com.apple.main-thread
detox[33941] INFO:  [actions.js] Sync Timed: performSelector @selector(removeInactiveFingerTips) on DTXTouchVisualizerWindow
detox[33941] INFO:  [actions.js] Sync Timed: performSelector @selector(removeFromSuperview) on COSTouchSpotView
detox[33941] INFO:  [actions.js] Sync WXAnimatedDisplayLinkIdlingResource: undefined
detox[33941] INFO:  [actions.js] Sync App State: undefined
detox[33941] INFO:  [actions.js] Sync Dispatch Queue: com.apple.main-thread
detox[33941] INFO:  [actions.js] Sync Timed: performSelector @selector(removeInactiveFingerTips) on DTXTouchVisualizerWindow
detox[33941] INFO:  [actions.js] Sync WXAnimatedDisplayLinkIdlingResource: undefined
detox[33941] INFO:  [actions.js] Sync Dispatch Queue: com.apple.main-thread
detox[33941] INFO:  [actions.js] Sync WXAnimatedDisplayLinkIdlingResource: undefined
detox[33941] INFO:  [actions.js] Sync Dispatch Queue: com.apple.main-thread
detox[33941] INFO:  [actions.js] Sync JavaScript Timers: Javascript Timers
detox[33941] INFO:  [actions.js] Sync Dispatch Queue: com.apple.main-thread
detox[33941] INFO:  [actions.js] Sync JavaScript Timers: Javascript Timers
detox[33941] INFO:  [actions.js] Sync Dispatch Queue: com.apple.main-thread
detox[33941] INFO:  [actions.js] Sync JavaScript Timers: Javascript Timers
detox[33941] INFO:  [actions.js] Sync Dispatch Queue: com.apple.main-thread
detox[33941] INFO:  [actions.js] Sync JavaScript Timers: Javascript Timers

The last 3 lines repeat until the test times out.

and after launching withlaunchArgs: { 'detoxPrintBusyIdleResources': 'YES' } and running xcrun simctl spawn booted log stream --level debug --style compact --predicate "category=='EarlGreyStatistics'":

Error from getpwuid_r: 0 (Undefined error: 0)
Filtering the log data using "category == "EarlGreyStatistics""
Deniss B.
  • 281
  • 4
  • 13
  • What reason do you have to disable synchronization? – Léo Natan Jul 04 '19 at 08:20
  • I have a test that uses script injection to bypass the login step which happens inside a WebView. After that I am triggering a navigation action to a native screen but the matchers can't find any elements on it unless I disable synchronisation. Then they can, but it's flaky and fails 50% of the time by just timing out in a sync-dispatch loop. – Deniss B. Jul 04 '19 at 10:09
  • Injecting code into a web view should not require disabling synchronization. If you see a loop, it means your app is busy. In anyway, what does the error tell you when you try to tap the button? – Léo Natan Jul 04 '19 at 14:44
  • There is not error, the test just times out. If I change my app and navigate to a screen in another stack navigator (from react-navigation) the sync issue goes away. – Deniss B. Jul 05 '19 at 10:48
  • You can enable various synchronization debug features to help you out. This is what I meant by “error”. – Léo Natan Jul 05 '19 at 10:50
  • I updated the question with the debug logs that I get for this problem. They don't really speak to me much.. – Deniss B. Jul 05 '19 at 11:21
  • Right, the log you have posted seems like a classic endless animation. Do you have something like that? I'd recommend mocking that to not be endless if testing. – Léo Natan Jul 05 '19 at 11:31
  • You might be right, it's possible I have a mounted modal with a loading animation under the screen I am showing. Will try to mock it and see of it helps. – Deniss B. Jul 05 '19 at 12:09

1 Answers1

0

The issue I had was indeed caused by an animation that was running in an infinite loop as Leo Nathan mentioned.

I had a screen that was mounted under the current one in a stack navigator from react-navigation. Unmounting the stack (and the endlessly animated screen) with reset solved the problem.

Deniss B.
  • 281
  • 4
  • 13