Skip to content

Commit 22764e6

Browse files
Emily Janzerfacebook-github-bot
Emily Janzer
authored andcommitted
Add an API for Detox to check if there are any timers expiring in a certain range (#27539)
Summary: Pull Request resolved: #27539 Detox currently relies on reflection to inspect the private timers queue in the Timing module to check if React Native is idle or not. This broke when I renamed TimingModule and moved the queue to JavaTimerManager in D17260848 and D17282187. A better solution to this problem is for us to expose a public API for checking the timers queue from TimingModule, so that Detox doesn't need to access private fields. Using similar logic to Detox's TimersIdlingResource: https://github.com/wix/Detox/blob/4f81a77baee4e4542a693922bcbde621d9d8c1a5/detox/android/detox/src/main/java/com/wix/detox/reactnative/idlingresources/TimersIdlingResource.kt#L95 Changelog: [Android] [Added] Added an API for checking if there are busy timers to TimingModule Reviewed By: makovkastar Differential Revision: D19128786 fbshipit-source-id: 835ae214eba58879c8343255bba680a81801ce03
1 parent 80cfa9c commit 22764e6

File tree

4 files changed

+40
-0
lines changed

4 files changed

+40
-0
lines changed

ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaTimerManager.java

+19
Original file line numberDiff line numberDiff line change
@@ -373,4 +373,23 @@ public void run() {
373373
}
374374
});
375375
}
376+
377+
/**
378+
* Returns a bool representing whether there are any active timers that will be fired within a
379+
* certain period of time. Disregards repeating timers (setInterval). Used for testing to
380+
* determine if RN is idle.
381+
*
382+
* @param rangeMs The time range, in ms, to check
383+
* @return True if there are pending timers within the given range; false otherwise
384+
*/
385+
/* package */ boolean hasActiveTimersInRange(long rangeMs) {
386+
synchronized (mTimerGuard) {
387+
for (Timer timer : mTimers) {
388+
if (!timer.mRepeat && timer.mInterval < rangeMs) {
389+
return true;
390+
}
391+
}
392+
}
393+
return false;
394+
}
376395
}

ReactAndroid/src/main/java/com/facebook/react/modules/core/TimingModule.java

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.facebook.react.bridge.LifecycleEventListener;
1212
import com.facebook.react.bridge.ReactApplicationContext;
1313
import com.facebook.react.bridge.WritableArray;
14+
import com.facebook.react.common.annotations.VisibleForTesting;
1415
import com.facebook.react.devsupport.interfaces.DevSupportManager;
1516
import com.facebook.react.jstasks.HeadlessJsTaskContext;
1617
import com.facebook.react.jstasks.HeadlessJsTaskEventListener;
@@ -134,4 +135,9 @@ public void onCatalystInstanceDestroy() {
134135
headlessJsTaskContext.removeTaskEventListener(this);
135136
mJavaTimerManager.onInstanceDestroy();
136137
}
138+
139+
@VisibleForTesting
140+
public boolean hasActiveTimersInRange(long rangeMs) {
141+
return mJavaTimerManager.hasActiveTimersInRange(rangeMs);
142+
}
137143
}

ReactAndroid/src/test/java/com/facebook/react/modules/BUCK

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ rn_robolectric_test(
2828
react_native_target("java/com/facebook/react/common/network:network"),
2929
react_native_target("java/com/facebook/react/devsupport:interfaces"),
3030
react_native_target("java/com/facebook/react/jstasks:jstasks"),
31+
react_native_target("java/com/facebook/react/module/annotations:annotations"),
3132
react_native_target("java/com/facebook/react/modules/blob:blob"),
3233
react_native_target("java/com/facebook/react/modules/camera:camera"),
3334
react_native_target("java/com/facebook/react/modules/clipboard:clipboard"),

ReactAndroid/src/test/java/com/facebook/react/modules/timing/TimingModuleTest.java

+14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
package com.facebook.react.modules.timing;
99

10+
import static org.fest.assertions.api.Assertions.assertThat;
1011
import static org.mockito.Mockito.*;
1112

1213
import com.facebook.react.bridge.Arguments;
@@ -254,6 +255,19 @@ public void testIdleCallback() {
254255
verify(mJSTimersMock).callIdleCallbacks(SystemClock.currentTimeMillis());
255256
}
256257

258+
@Test
259+
public void testActiveTimersInRange() {
260+
mTimingModule.onHostResume();
261+
assertThat(mTimingModule.hasActiveTimersInRange(100)).isFalse();
262+
263+
mTimingModule.createTimer(41, 1, 0, true);
264+
assertThat(mTimingModule.hasActiveTimersInRange(100)).isFalse(); // Repeating
265+
266+
mTimingModule.createTimer(42, 150, 0, false);
267+
assertThat(mTimingModule.hasActiveTimersInRange(100)).isFalse(); // Out of range
268+
assertThat(mTimingModule.hasActiveTimersInRange(200)).isTrue(); // In range
269+
}
270+
257271
private static class PostFrameIdleCallbackHandler implements Answer<Void> {
258272

259273
private ChoreographerCompat.FrameCallback mFrameCallback;

0 commit comments

Comments
 (0)