【问题标题】:Mapping dynamic elements with @FindBy annotations and PageFactory使用 @FindBy 注释和 PageFactory 映射动态元素
【发布时间】:2017-08-19 15:01:28
【问题描述】:

对于下面的页面对象示例类,我有一个 accountsLink 私有成员,它在加载时映射到登录页面上的非动态元素。在构造函数调用 initElements 方法时,使用 FindBy 注解对其进行初始化。

public class Login {
    private WebDriver driver;

    @FindBy(id = "account")
    private WebElement accountsLink;

    //constructor, elements are initialized by the PageFactory
    public MainPage(WebDriver driver) {
        this.driver = driver;
        PageFactory.initElements(driver, this);
    }

    //clicking accounts opens a dynamic ajax menu which has a Sign In Button
    public SignInPage clickAccountsLink() {
        accountsLink.click();   
        WebElement signInButton = driver.findElement(By.id("signin"));
        signInButton.click();
        return new SignInPage(driver);
    }
}

现在解决问题。我有另一个元素(signInButton),它仅在您单击 accountsLink 元素时才动态加载。此操作不会将您带到另一个页面,而只会显示一个 ajax 菜单,其中将显示登录按钮。

我的问题是,由于 signInButton 元素仅在单击 accountsLink 元素时出现,是否可以使用 FindBy 注释将其声明为 Login 类的成员,或者我是否必须坚持当前使用驱动程序的解决方案。 findElement(By.id("signin")) 在 clickAccountsLink 方法中?

我希望我的问题有意义。

【问题讨论】:

  • 这是我完全避免使用PageFactory 的原因之一。您最终会混合使用带注释的元素并根据需要抓取页面。我更喜欢根据需要一直抓取页面以保持一致性和性能。
  • 虽然在纯静态网页中是有意义的,但如今几乎没有任何网站被认为是静态的。所以你是对的。

标签: java selenium automated-tests


【解决方案1】:

PageFactory.initElements 被调用时,它会解析当前的DOM。如果 WebElement 在那个时候不存在,则它不能作为变量的值给出,就像您无法使用 driver.findElement 定位不存在的 WebElement 一样。

您的解决方案是可行的方法,尽管在加载 signInButton 时我会使用 explicit waitExpected Conditions

【讨论】:

  • 我写了这个类来提供一个简单的例子。但在编写实际代码时,我肯定会使用显式等待和预期条件。谢谢。
【解决方案2】:

你可以声明,我认为它不会给你任何错误。 Page Factory 在初始化类时会创建一个虚拟元素。只有当您第一次与元素相交时,它才会创建实际元素。

例如在下面的类中 NoExistingElement 元素不存在并且不会给我任何错误,如果我将调用类的 enterText 方法。测试用例将通过,没有任何错误。

但是,如果我尝试在 NoExistingElement 元素上调用任何函数,那么只有它会因 Webdriver 异常 ElementNotFoundException 而失败

   public class GoogleSearch {

    @FindBy(name="q")
    static WebElement searchBox;

    @FindBy(name = "qqqqq")
    WebElement NoExistingElement;

    public GoogleSearch(WebDriver driver){
        PageFactory.initElements(driver, this);
        driver.get("https://www.google.com");

    }

    public void searchOnGoogle(String text){
        searchBox.sendKeys(text);

    }
}

【讨论】:

  • 我明白了。但是在 NoExistingElement 确实存在的情况下,我可以再次调用 PageFactory.initElements 进行初始化吗?缺点和(性能影响)是它会重新初始化那些在第一次调用 initElements 时已经找到的元素。
  • @jeffsia 正如我所说,它不会用实际值初始化对象,这就像延迟初始化一样,只有在您第一次执行某些操作时才会填充实际值。即在 searchBox.sendKeys(text); 被调用时 searchBox 被填充的情况下。希望现在清楚了。
  • 如果这确实发生了,那为什么还要调用 PageFactory.initElements()?
  • 它是创建类对象并使用代理(虚拟)初始化您的 Web 元素的方法
猜你喜欢
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-09
  • 1970-01-01
相关资源
最近更新 更多