Skip to content

Commit

Permalink
Fix crash in long-tap spy method in demo app running on RN<60
Browse files Browse the repository at this point in the history
  • Loading branch information
d4vidi committed Dec 18, 2019
1 parent 003fef9 commit 4c4bb4e
Showing 1 changed file with 12 additions and 15 deletions.
27 changes: 12 additions & 15 deletions detox/test/android/app/src/main/java/com/example/NativeModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@
import com.facebook.react.uimanager.util.ReactFindViewUtil;
import com.facebook.react.uimanager.util.ReactFindViewUtil.OnMultipleViewsFoundListener;

import java.util.HashSet;
import java.util.Set;

import androidx.collection.ArraySet;

public class NativeModule extends ReactContextBaseJavaModule {

public static final String NAME = "NativeModule";
Expand Down Expand Up @@ -111,42 +110,40 @@ public void getLaunchArguments(Promise promise) {

@ReactMethod
public void spyLongTaps(final String testID) {
new LongTapsSpy(testID).spyOnce();
new LongTapCrasher(testID).attach();
}

/**
* Implementation note: For this purpose, a simpler RN API exists in the same class -
* {@link ReactFindViewUtil#addViewListener(ReactFindViewUtil.OnViewFoundListener)}.
* However, it is found to be a but buggy since it removes all listeners immediately
* However, it is found to be a bit buggy since it removes all listeners immediately
* after being called (i.e. while iterating) with no thread-sync mechanisms to protect it.
* If real life (CI), we've genuinely seen on occasions that it throws ConcurrentModificationException
* exceptions (and why wouldn't it? - we have a screen with multiple views subscribing and
* called concurrently in the ActionsScreen of this demo app; could it be that it is not always called
* from the main thread?).
* If real life (CI), we've genuinely seen that it throws ConcurrentModificationException exceptions,
* on occasions (and why wouldn't it? - our demo app's ActionsScreen has multiple views subscribing and
* called concurrently; could it be that not always everything is run in the main thread?).
* Therefore, we use here {@link ReactFindViewUtil#addViewsListener(OnMultipleViewsFoundListener, Set)},
* which is too generic but nevertheless allows us to better control when we are to be removed.
*/
private static class LongTapsSpy implements OnMultipleViewsFoundListener {
private static class LongTapCrasher implements OnMultipleViewsFoundListener {

private final String testID;

private LongTapsSpy(String testID) {
private LongTapCrasher(String testID) {
this.testID = testID;
}

public void spyOnce() {
final Set<String> nativeIdsSet = new ArraySet<>(1);
nativeIdsSet.add(testID);
public void attach() {
final Set<String> nativeIds = new HashSet<>();
nativeIds.add(testID);

ReactFindViewUtil.addViewsListener(this, nativeIdsSet);
ReactFindViewUtil.addViewsListener(this, nativeIds);
}

@Override
public void onViewFound(View view, String nativeId) {
view.setOnLongClickListener(v -> {
throw new IllegalStateException("Validation failed: component \"" + testID + "\" was long-tapped!!!");
});

view.post(() -> ReactFindViewUtil.removeViewsListener(this));
}
}
Expand Down

0 comments on commit 4c4bb4e

Please sign in to comment.