如何返回一个延迟实例化的动态web元素



我已经使用@FindBy有一段时间了,我喜欢这样一个事实,即元素直到必要时才被定位(不是实例化时)。

然而,网页可能有某个元素的2-10个元素,并且元素上的id是有编号的(因此第一个元素的id为"element1",依此类推)

我想写一个函数,在这里我可以传递一个整数,它将返回一个具有适当ID的WebElement,and被延迟实例化。这意味着拥有以下功能将不起作用:

public WebElement getElement(int numOnPage){
    return driver.findElement(By.id("element"+numOnPage));
}

因为我调用该函数的那一刻,WebElement就被定位了。(不能实例化它的原因是,我有一个函数,它通过反复调用isDisplayed()来等待元素存在,从而捕获NoSuchElementExceptions)。

我还意识到,我可以创建一个List<WebElement>,通过CSS选择ID以"element"开头的每个元素,但我也遇到过其他情况,我想返回一个动态生成的元素,并且必须在那里使用一个变通方法。

谢谢!

首先,我真的不明白为什么在元素真正进入页面之前绝对需要获得WebElement引用。在正常情况下,您可以检查页面是否已完全加载,然后查找WebElement。第一个通常是用一个循环和一个捕获NoSuchElementException来完成的,正如您所提到的。

但是,如果在页面中找不到WebElement之前需要它的引用,我只需创建一个延迟加载(仅在第一次需要时)真实WebElement实例的代理。类似这样的东西:

public WebElement getElement(final int numOnPage) {
        return (WebElement) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class<?>[] { WebElement.class }, new InvocationHandler() {
            // Lazy initialized instance of WebElement
            private WebElement webElement;
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                if (webElement == null) {
                    webElement = driver.findElement(By.id("element" + numOnPage));
                }
                return method.invoke(webElement, args);
            }
        });
    }

通过调用getElement,可以检索类型为WebElement的对象。一旦调用它的一个方法,就会使用WebDriver.findElement检索它。请注意,如果在代理实例上调用一个方法,则元素必须在页面中,否则当然会得到NoSuchElementException

如果我正确理解了这个问题,那么使用@FindBy注释就无法做到这一点。问题是Java中的注释是在编译时处理的,因此您无法实时修改它们:

http://docs.oracle.com/javase/tutorial/java/annotations/

然而,听起来你的问题可以很容易地通过使用显式等待来解决:

public WebElement getElement(int numOnPage){
    WebDriverWait waiting= new WebDriverWait(driver, 15, 100);
    return waiting.until(ExpectedConditions.visibilityOfElementLocated(By.id("element"+numOnPage)));
}

这将扫描页面,等待元素存在并可见,并在元素存在时向您返回WebElement。

最新更新