Skip to content

Commit ffa827a

Browse files
feat(android): support repro-steps for button
Support extracting the label of the button in repro-steps via TouchedViewExtractor
1 parent d28eb6f commit ffa827a

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.instabug.library.IssueType;
2828
import com.instabug.library.LogLevel;
2929
import com.instabug.library.ReproConfigurations;
30+
import com.instabug.library.core.InstabugCore;
3031
import com.instabug.library.internal.module.InstabugLocale;
3132
import com.instabug.library.invocation.InstabugInvocationEvent;
3233
import com.instabug.library.logging.InstabugLog;
@@ -37,6 +38,7 @@
3738
import com.instabug.reactlibrary.utils.EventEmitterModule;
3839
import com.instabug.reactlibrary.utils.MainThreadHandler;
3940

41+
import com.instabug.reactlibrary.utils.RNTouchedViewExtractor;
4042
import org.json.JSONException;
4143
import org.json.JSONObject;
4244
import org.json.JSONTokener;
@@ -132,6 +134,8 @@ public void init(
132134
MainThreadHandler.runOnMainThread(new Runnable() {
133135
@Override
134136
public void run() {
137+
final RNTouchedViewExtractor rnTouchedViewExtractor = new RNTouchedViewExtractor();
138+
InstabugCore.setTouchedViewExtractorExtension(rnTouchedViewExtractor);
135139
final ArrayList<String> keys = ArrayUtil.parseReadableArrayOfStrings(invocationEventValues);
136140
final ArrayList<InstabugInvocationEvent> parsedInvocationEvents = ArgsRegistry.invocationEvents.getAll(keys);
137141
final InstabugInvocationEvent[] invocationEvents = parsedInvocationEvents.toArray(new InstabugInvocationEvent[0]);
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package com.instabug.reactlibrary.utils;
2+
3+
import android.text.TextUtils;
4+
import android.view.View;
5+
import android.view.ViewGroup;
6+
import android.view.ViewParent;
7+
import android.widget.TextView;
8+
9+
import androidx.annotation.NonNull;
10+
import androidx.annotation.Nullable;
11+
12+
import com.facebook.react.views.view.ReactViewGroup;
13+
import com.instabug.library.core.InstabugCore;
14+
import com.instabug.library.visualusersteps.TouchedView;
15+
import com.instabug.library.visualusersteps.TouchedViewExtractor;
16+
17+
public class RNTouchedViewExtractor implements TouchedViewExtractor {
18+
@Override
19+
public boolean getShouldDependOnNative() {
20+
return true;
21+
}
22+
23+
@Nullable
24+
@Override
25+
public TouchedView extract(@NonNull View view, @NonNull TouchedView touchedView) {
26+
ReactViewGroup reactViewGroup = findReactButtonViewGroup(view);
27+
if (reactViewGroup == null) return null;
28+
return getExtractionStrategy(reactViewGroup).extract(reactViewGroup, touchedView);
29+
}
30+
31+
@Nullable
32+
private ReactViewGroup findReactButtonViewGroup(@NonNull View startView) {
33+
if (isReactButtonViewGroup(startView)) return (ReactViewGroup) startView;
34+
ViewParent currentParent = startView.getParent();
35+
int iteratorIndex = 0;
36+
do {
37+
if (currentParent == null || isReactButtonViewGroup(currentParent))
38+
return (ReactViewGroup) currentParent;
39+
currentParent = currentParent.getParent();
40+
iteratorIndex++;
41+
} while (iteratorIndex < 2);
42+
return null;
43+
}
44+
45+
private boolean isReactButtonViewGroup(@NonNull View view) {
46+
return (view instanceof ReactViewGroup) && view.isFocusable() && view.isClickable();
47+
}
48+
49+
private boolean isReactButtonViewGroup(@NonNull ViewParent viewParent) {
50+
if (!(viewParent instanceof ReactViewGroup)) return false;
51+
ViewGroup group = (ReactViewGroup) viewParent;
52+
return group.isFocusable() && group.isClickable();
53+
}
54+
55+
private ReactButtonExtractionStrategy getExtractionStrategy(ReactViewGroup reactButton){
56+
int labelsCount = 0;
57+
int groupsCount = 0;
58+
for (int index=0; index < reactButton.getChildCount(); index++){
59+
View currentView = reactButton.getChildAt(index);
60+
if (currentView instanceof TextView) {
61+
62+
labelsCount++;
63+
continue;
64+
}
65+
if (currentView instanceof ViewGroup) {
66+
groupsCount++;
67+
}
68+
}
69+
if (labelsCount > 1 || groupsCount > 0) return new MultiLabelsExtractionStrategy();
70+
if (labelsCount == 1) return new SingleLabelExtractionStrategy();
71+
return new NoLabelsExtractionStrategy();
72+
}
73+
74+
interface ReactButtonExtractionStrategy {
75+
@Nullable
76+
TouchedView extract(ViewGroup reactButton, TouchedView touchedView);
77+
}
78+
79+
class MultiLabelsExtractionStrategy implements ReactButtonExtractionStrategy {
80+
private final String MULTI_LABEL_BUTTON_PRE_STRING = "A button that contains \"%s\"";
81+
82+
@Override
83+
@Nullable
84+
public TouchedView extract(ViewGroup reactButton, TouchedView touchedView) {
85+
86+
touchedView.setProminentLabel(
87+
InstabugCore.composeProminentLabelForViewGroup(reactButton, MULTI_LABEL_BUTTON_PRE_STRING)
88+
);
89+
return touchedView;
90+
}
91+
}
92+
93+
class SingleLabelExtractionStrategy implements ReactButtonExtractionStrategy {
94+
95+
@Override
96+
public TouchedView extract(ViewGroup reactButton, TouchedView touchedView) {
97+
TextView targetLabel = null;
98+
for (int index = 0; index < reactButton.getChildCount(); index++) {
99+
View currentView = reactButton.getChildAt(index);
100+
if (!(currentView instanceof TextView)) continue;
101+
targetLabel = (TextView) currentView;
102+
break;
103+
}
104+
if (targetLabel == null) return touchedView;
105+
106+
String labelText = getLabelText(targetLabel);
107+
touchedView.setProminentLabel(InstabugCore.composeProminentLabelFor(labelText, false));
108+
return touchedView;
109+
}
110+
111+
@Nullable
112+
private String getLabelText(TextView textView) {
113+
String labelText = null;
114+
if (!TextUtils.isEmpty(textView.getText())) {
115+
labelText = textView.getText().toString();
116+
} else if (!TextUtils.isEmpty(textView.getContentDescription())) {
117+
labelText = textView.getContentDescription().toString();
118+
}
119+
return labelText;
120+
}
121+
}
122+
123+
class NoLabelsExtractionStrategy implements ReactButtonExtractionStrategy {
124+
125+
@Override
126+
public TouchedView extract(ViewGroup reactButton, TouchedView touchedView) {
127+
touchedView.setProminentLabel(
128+
InstabugCore.composeProminentLabelFor(null, false)
129+
);
130+
return touchedView;
131+
}
132+
}
133+
}

0 commit comments

Comments
 (0)