From 8b3219e190a385b6077e0464be5881be5be169e1 Mon Sep 17 00:00:00 2001 From: dlowzzxx <210235699+dlowzzxx@users.noreply.github.com> Date: Sat, 26 Sep 2026 21:49:45 +0200 Subject: [PATCH] fix: support Selenium-decorated page elements --- .../pagefactory/ElementInterceptor.java | 7 +- .../SeleniumDecoratorCompatibilityTest.java | 76 +++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/test/java/io/appium/java_client/pagefactory_tests/SeleniumDecoratorCompatibilityTest.java diff --git a/src/main/java/io/appium/java_client/pagefactory/ElementInterceptor.java b/src/main/java/io/appium/java_client/pagefactory/ElementInterceptor.java index 82b61990b..82eb07c83 100644 --- a/src/main/java/io/appium/java_client/pagefactory/ElementInterceptor.java +++ b/src/main/java/io/appium/java_client/pagefactory/ElementInterceptor.java @@ -39,7 +39,12 @@ public ElementInterceptor(ElementLocator locator, WeakReference drive protected Object getObject(WebElement element, Method method, Object[] args) throws Throwable { try { - return method.invoke(element, args); + Method methodToInvoke = method; + if (!method.getDeclaringClass().isInstance(element)) { + // Selenium decorators may expose WebElement without extending RemoteWebElement. + methodToInvoke = WebElement.class.getMethod(method.getName(), method.getParameterTypes()); + } + return methodToInvoke.invoke(element, args); } catch (Throwable t) { throw extractReadableException(t); } diff --git a/src/test/java/io/appium/java_client/pagefactory_tests/SeleniumDecoratorCompatibilityTest.java b/src/test/java/io/appium/java_client/pagefactory_tests/SeleniumDecoratorCompatibilityTest.java new file mode 100644 index 000000000..6c1210e6d --- /dev/null +++ b/src/test/java/io/appium/java_client/pagefactory_tests/SeleniumDecoratorCompatibilityTest.java @@ -0,0 +1,76 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.appium.java_client.pagefactory_tests; + +import io.appium.java_client.events.stubs.EmptyWebDriver; +import io.appium.java_client.events.stubs.StubWebElement; +import io.appium.java_client.pagefactory.AndroidFindBy; +import io.appium.java_client.pagefactory.AppiumFieldDecorator; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.PageFactory; +import org.openqa.selenium.support.events.EventFiringDecorator; +import org.openqa.selenium.support.events.WebDriverListener; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class SeleniumDecoratorCompatibilityTest { + @AndroidFindBy(id = "some_id") + private WebElement element; + + @Test + public void canInvokeElementReturnedBySeleniumDecorator() { + CountingDriver originalDriver = new CountingDriver(); + CountingListener listener = new CountingListener(); + WebDriver decoratedDriver = new EventFiringDecorator<>(listener).decorate(originalDriver); + PageFactory.initElements(new AppiumFieldDecorator(decoratedDriver), this); + + element.click(); + + assertEquals(1, originalDriver.element.clickCount); + assertEquals(1, listener.clickCount); + } + + public static class CountingDriver extends EmptyWebDriver { + private final CountingElement element = new CountingElement(); + + @Override + public StubWebElement findElement(By by) { + return element; + } + } + + public static class CountingElement extends StubWebElement { + private int clickCount; + + @Override + public void click() { + clickCount++; + } + } + + public static class CountingListener implements WebDriverListener { + private int clickCount; + + @Override + public void afterClick(WebElement element) { + clickCount++; + } + } +}