Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

import static io.appium.java_client.proxy.Helpers.OBJECT_METHOD_NAMES;
import static io.appium.java_client.proxy.Helpers.createProxy;
import static net.bytebuddy.matcher.ElementMatchers.isAbstract;
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
import static net.bytebuddy.matcher.ElementMatchers.not;

Expand Down Expand Up @@ -89,8 +88,6 @@ public static <T> T getEnhancedProxy(
) {
ElementMatcher<MethodDescription> extraMatcher = not(
namedOneOf(NON_PROXYABLE_METHODS.toArray(new String[0]))
).and(
not(isAbstract())
);
return createProxy(
cls,
Expand Down
17 changes: 12 additions & 5 deletions src/main/java/io/appium/java_client/proxy/Interceptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ private Interceptor() {
* @param self The reference to the original instance.
* @param method The reference to the original method.
* @param args The reference to method args.
* @param callable The reference to the non-patched callable to avoid call recursion.
* @param callable The reference to the non-patched callable to avoid call recursion. Abstract methods
* have no superclass implementation, so this may be null; unhandled calls retain
* their {@link AbstractMethodError} behavior.
* @return Either the original method result or the patched one.
*/
@SuppressWarnings("unused")
Expand All @@ -53,11 +55,16 @@ public static Object intercept(
@This Object self,
@Origin Method method,
@AllArguments Object[] args,
@SuperCall Callable<?> callable
@SuperCall(nullIfImpossible = true) Callable<?> callable
) throws Throwable {
Callable<?> original = callable == null
? () -> {
throw new AbstractMethodError(method.toString());
}
: callable;
var listeners = ((HasMethodCallListeners) self).getMethodCallListeners();
if (listeners == null || listeners.length == 0) {
return callable.call();
return original.call();
}

for (var listener : listeners) {
Expand All @@ -75,7 +82,7 @@ public static Object intercept(
Object result = UNSET;
for (var listener : listeners) {
try {
result = listener.call(self, method, args, callable);
result = listener.call(self, method, args, original);
if (result != UNSET) {
break;
}
Expand All @@ -95,7 +102,7 @@ public static Object intercept(
}
if (UNSET == result) {
try {
result = callable.call();
result = original.call();
} catch (Exception e) {
for (var listener : listeners) {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package io.appium.java_client.pagefactory_tests.widget.tests.combined;

import io.appium.java_client.pagefactory.AndroidFindBy;
import io.appium.java_client.pagefactory.AppiumFieldDecorator;
import io.appium.java_client.pagefactory.OverrideWidget;
import io.appium.java_client.pagefactory.Widget;
import io.appium.java_client.pagefactory.iOSXCUITFindBy;
import io.appium.java_client.pagefactory_tests.widget.tests.AbstractStubWebDriver;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

import java.util.List;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.openqa.selenium.support.PageFactory.initElements;

class AbstractWidgetMethodTest {

static Stream<Arguments> drivers() {
return Stream.of(
Arguments.of(new AbstractStubWebDriver.StubAndroidDriver(), "android"),
Arguments.of(new AbstractStubWebDriver.StubIOSXCUITDriver(), "ios"),
Arguments.of(new AbstractStubWebDriver.StubBrowserDriver(), "html"),
Arguments.of(new AbstractStubWebDriver.StubAndroidBrowserOrWebViewDriver(), "html")
);
}

@ParameterizedTest
@MethodSource("drivers")
void delegatesAbstractMethodToPlatformSpecificWidget(WebDriver driver, String expected) {
var page = new Page();
initElements(new AppiumFieldDecorator(driver), page);

assertEquals(expected, page.widget.platformAction());
assertEquals(2, page.widgets.size());
page.widgets.forEach(widget -> assertEquals(expected, widget.platformAction()));
}

static class Page {
@OverrideWidget(html = HtmlWidget.class,
androidUIAutomator = AndroidWidget.class,
iOSXCUITAutomation = IosWidget.class)
@FindBy(id = "widget")
private AbstractActionWidget widget;

@OverrideWidget(html = HtmlWidget.class,
androidUIAutomator = AndroidWidget.class,
iOSXCUITAutomation = IosWidget.class)
@FindBy(id = "widget")
private List<AbstractActionWidget> widgets;
}

public abstract static class AbstractActionWidget extends Widget {
protected AbstractActionWidget(WebElement element) {
super(element);
}

public abstract String platformAction();
}

@AndroidFindBy(uiAutomator = "widget")
public static class AndroidWidget extends AbstractActionWidget {
protected AndroidWidget(WebElement element) {
super(element);
}

@Override
public String platformAction() {
return "android";
}
}

@iOSXCUITFindBy(iOSNsPredicate = "widget")
public static class IosWidget extends AbstractActionWidget {
protected IosWidget(WebElement element) {
super(element);
}

@Override
public String platformAction() {
return "ios";
}
}

public static class HtmlWidget extends AbstractActionWidget {
protected HtmlWidget(WebElement element) {
super(element);
}

@Override
public String platformAction() {
return "html";
}
}
}
11 changes: 11 additions & 0 deletions src/test/java/io/appium/java_client/proxy/ProxyHelpersTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.util.List;
import java.util.concurrent.Callable;

import static io.appium.java_client.pagefactory.utils.ProxyFactory.getEnhancedProxy;
import static io.appium.java_client.proxy.Helpers.createProxy;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
Expand All @@ -43,6 +44,16 @@

class ProxyHelpersTest {

public abstract static class AbstractAction {
public abstract String run();
}

@Test
void unhandledAbstractMethodRetainsAbstractMethodError() {
AbstractAction proxy = getEnhancedProxy(AbstractAction.class, new MethodCallListener() { });
assertThrows(AbstractMethodError.class, proxy::run);
}

public static class FakeIOSDriver extends IOSDriver {
public FakeIOSDriver(URL url, Capabilities caps) {
super(url, caps);
Expand Down
Loading