在Karate Framework中无法实现Page Factory的问题求助
在Karate Framework中实现Page Factory时的元素识别错误问题
问题重现
尝试在Karate Framework中结合Selenium的Page Factory模式编写UI测试,相关代码及报错如下:
LoginPage.java
@AndroidFindBy(xpath = "//android.widget.EditText[@content-desc='email-input']") public WebElement usernametxtbox; @AndroidFindBy(xpath = "//android.widget.EditText[@content-desc='password-input']") public WebElement passwordtxtbox; public LoginPage(WebDriver driver){ this.driver = driver; PageFactory.initElements(driver, this); driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10)); } public void doLogin() throws InterruptedException, IOException { usernametxtbox.sendKeys("username"); passwordtxtbox.sendKeys("password"); }
Login.feature
Background: App Preset * def LoginPage = Java.type('com.mobile.pages.LoginPage') * def LoginPageObj = new LoginPage(driver) Scenario: Android app UI test Given LoginPageObj.doLogin()
执行后触发错误:
01: LoginPageObj.doLogin() <<<< org.graalvm.polyglot.PolyglotException: Unsupported CSS selector '*[name='usernametxtbox']'. Reason: 'Error: 'name' is not a valid attribute. Supported attributes are 'checkable, checked, clickable, enabled, focusable, focused, long-clickable, scrollable, selected, index, instance, description, resource-id, text, class-name, package-name''
问题核心:调用usernametxtbox.sendKeys("username")时,Karate错误将WebElement变量名识别为CSS选择器,而非实际定位到的页面元素。
解决方案
方案1:改用AppiumFieldDecorator初始化Page元素
Karate提供的driver是包装后的对象,直接使用Selenium默认的PageFactory.initElements会引发代理逻辑冲突。改用Appium专属的AppiumFieldDecorator初始化元素,确保定位逻辑由Appium处理:
修改后的LoginPage.java:
import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.pagefactory.AppiumFieldDecorator; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.PageFactory; import org.openqa.selenium.support.ui.Duration; import io.appium.java_client.pagefactory.AndroidFindBy; public class LoginPage { private AndroidDriver driver; @AndroidFindBy(xpath = "//android.widget.EditText[@content-desc='email-input']") public WebElement usernametxtbox; @AndroidFindBy(xpath = "//android.widget.EditText[@content-desc='password-input']") public WebElement passwordtxtbox; public LoginPage(AndroidDriver driver) { this.driver = driver; // 使用AppiumFieldDecorator初始化元素并设置超时 PageFactory.initElements(new AppiumFieldDecorator(driver, Duration.ofSeconds(10)), this); } public void doLogin() { usernametxtbox.sendKeys("username"); passwordtxtbox.sendKeys("password"); } }
方案2:使用Karate原生语法实现Page Object模式
放弃依赖Selenium的Page Factory,直接用Karate的Gherkin语法封装页面操作,完全贴合Karate生态,避免兼容性问题:
创建页面操作封装文件LoginPage.feature:
Feature: Login Page Actions Background: * def usernameLocator = "//android.widget.EditText[@content-desc='email-input']" * def passwordLocator = "//android.widget.EditText[@content-desc='password-input']" Scenario: Perform Login Given input(usernameLocator, 'username') And input(passwordLocator, 'password')
在主测试feature中调用:
Background: App Preset * def LoginPage = call read('classpath:com/mobile/pages/LoginPage.feature') Scenario: Android app UI test Given call LoginPage['Perform Login']
内容的提问来源于stack exchange,提问作者Michael Corleone
相关产品推荐
相关产品推荐

