Skip to content

Commit a79df4b

Browse files
committed
fix: Proxy commands issues via RemoteWebElement
Fixes #2239
1 parent 6cfef35 commit a79df4b

File tree

3 files changed

+128
-5
lines changed

3 files changed

+128
-5
lines changed

src/main/java/io/appium/java_client/proxy/Helpers.java

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,11 @@
2727
import net.bytebuddy.matcher.ElementMatcher;
2828
import net.bytebuddy.matcher.ElementMatchers;
2929
import org.jspecify.annotations.Nullable;
30+
import org.openqa.selenium.remote.RemoteWebDriver;
31+
import org.openqa.selenium.remote.RemoteWebElement;
3032

3133
import java.lang.reflect.Method;
32-
import java.util.Collection;
33-
import java.util.Collections;
34-
import java.util.Map;
35-
import java.util.Set;
36-
import java.util.WeakHashMap;
34+
import java.util.*;
3735
import java.util.stream.Collectors;
3836
import java.util.stream.Stream;
3937

@@ -222,4 +220,28 @@ private static class ProxyClassSignature {
222220
Class<?>[] constructorArgTypes;
223221
ElementMatcher<MethodDescription> extraMethodMatcher;
224222
}
223+
224+
public static RemoteWebElement wrapElement(
225+
RemoteWebElement original,
226+
HasMethodCallListeners parent,
227+
MethodCallListener[] listeners
228+
) {
229+
RemoteWebElement proxy = createProxy(
230+
RemoteWebElement.class,
231+
new Object[]{},
232+
new Class[]{},
233+
List.of(listeners),
234+
ElementMatchers.not(
235+
namedOneOf(
236+
OBJECT_METHOD_NAMES.toArray(new String[0]))
237+
.or(ElementMatchers.named("setId").or(ElementMatchers.named("setParent")))
238+
)
239+
);
240+
241+
proxy.setId(original.getId());
242+
243+
proxy.setParent((RemoteWebDriver) parent);
244+
245+
return proxy;
246+
}
225247
}

src/main/java/io/appium/java_client/proxy/Interceptor.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
2222
import net.bytebuddy.implementation.bind.annotation.SuperCall;
2323
import net.bytebuddy.implementation.bind.annotation.This;
24+
import org.openqa.selenium.remote.RemoteWebElement;
2425
import org.slf4j.Logger;
2526
import org.slf4j.LoggerFactory;
2627

2728
import java.lang.reflect.Method;
29+
import java.util.ArrayList;
30+
import java.util.List;
2831
import java.util.concurrent.Callable;
2932

3033
import static io.appium.java_client.proxy.MethodCallListener.UNSET;
@@ -111,6 +114,25 @@ public static Object intercept(
111114
}
112115
}
113116

117+
if (result instanceof RemoteWebElement) {
118+
result = Helpers.wrapElement((RemoteWebElement) result, (HasMethodCallListeners) self, listeners);
119+
} else if (result instanceof List) {
120+
List<?> originalList = (List<?>) result;
121+
if (!originalList.isEmpty() && originalList.get(0) instanceof RemoteWebElement) {
122+
List<Object> wrappedList = new ArrayList<>(originalList.size());
123+
for (Object item : originalList) {
124+
if (item instanceof RemoteWebElement) {
125+
wrappedList.add(Helpers.wrapElement(
126+
(RemoteWebElement) item,
127+
(HasMethodCallListeners) self, listeners));
128+
} else {
129+
wrappedList.add(item);
130+
}
131+
}
132+
result = wrappedList;
133+
}
134+
}
135+
114136
final Object endResult = result == UNSET ? null : result;
115137
for (var listener : listeners) {
116138
try {

src/test/java/io/appium/java_client/proxy/ProxyHelpersTest.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,20 @@
1919
import io.appium.java_client.ios.IOSDriver;
2020
import io.appium.java_client.ios.options.XCUITestOptions;
2121
import org.junit.jupiter.api.Test;
22+
import org.openqa.selenium.By;
2223
import org.openqa.selenium.Capabilities;
24+
import org.openqa.selenium.NoSuchSessionException;
25+
import org.openqa.selenium.WebElement;
2326
import org.openqa.selenium.remote.RemoteWebDriver;
27+
import org.openqa.selenium.remote.RemoteWebElement;
2428
import org.openqa.selenium.remote.UnreachableBrowserException;
2529

2630
import java.lang.reflect.Method;
2731
import java.net.MalformedURLException;
2832
import java.net.URL;
33+
import java.util.ArrayList;
2934
import java.util.Collections;
35+
import java.util.List;
3036
import java.util.concurrent.Callable;
3137

3238
import static io.appium.java_client.proxy.Helpers.createProxy;
@@ -45,6 +51,31 @@ public FakeIOSDriver(URL url, Capabilities caps) {
4551
@Override
4652
protected void startSession(Capabilities capabilities) {
4753
}
54+
55+
@Override
56+
public WebElement findElement(By locator) {
57+
RemoteWebElement webElement = new RemoteWebElement();
58+
webElement.setId(locator.toString());
59+
webElement.setParent(this);
60+
return webElement;
61+
}
62+
63+
@Override
64+
public List<WebElement> findElements(By locator) {
65+
List<WebElement> webElements = new ArrayList<>();
66+
67+
RemoteWebElement webElement1 = new RemoteWebElement();
68+
webElement1.setId("1234");
69+
webElement1.setParent(this);
70+
webElements.add(webElement1);
71+
72+
RemoteWebElement webElement2 = new RemoteWebElement();
73+
webElement2.setId("5678");
74+
webElement2.setParent(this);
75+
webElements.add(webElement2);
76+
77+
return webElements;
78+
}
4879
}
4980

5081
@Test
@@ -133,4 +164,52 @@ public Object onError(Object obj, Method method, Object[] args, Throwable e) thr
133164
"onError get")
134165
)));
135166
}
167+
168+
169+
@Test
170+
void shouldFireEventsForRemoteWebElement() throws MalformedURLException {
171+
final StringBuilder acc = new StringBuilder();
172+
MethodCallListener listener = new MethodCallListener() {
173+
@Override
174+
public void beforeCall(Object target, Method method, Object[] args) {
175+
acc.append("beforeCall ").append(method.getName()).append("\n");
176+
}
177+
};
178+
179+
FakeIOSDriver driver = createProxy(
180+
FakeIOSDriver.class,
181+
new Object[] {new URL("http://localhost:4723/"), new XCUITestOptions()},
182+
new Class[] {URL.class, Capabilities.class},
183+
listener
184+
);
185+
186+
WebElement element = driver.findElement(By.id("button"));
187+
188+
assertThrows(
189+
NoSuchSessionException.class,
190+
element::click
191+
);
192+
193+
List<WebElement> elements = driver.findElements(By.id("button"));
194+
195+
assertThrows(
196+
NoSuchSessionException.class,
197+
() -> elements.get(1).isSelected()
198+
);
199+
200+
assertThat(acc.toString().trim(), is(equalTo(
201+
String.join("\n",
202+
"beforeCall findElement",
203+
"beforeCall click",
204+
"beforeCall getSessionId",
205+
"beforeCall getCapabilities",
206+
"beforeCall getCapabilities",
207+
"beforeCall findElements",
208+
"beforeCall isSelected",
209+
"beforeCall getSessionId",
210+
"beforeCall getCapabilities",
211+
"beforeCall getCapabilities"
212+
)
213+
)));
214+
}
136215
}

0 commit comments

Comments
 (0)