当Selenium2 findElement失败时故障转移到JavascriptExecutor?

时间:2013-10-10 02:34:25

标签: java selenium selenium-webdriver browser-automation

如果Selenium2在轮询一段有限的时间后无法检索WebElement对象,我有这个想法可以故障转移到JavascriptExecutor。如您所见,该方法的局限性在于调用getElementByLocator时需要预先定义“故障转移”Javascript片段。我想不出动态做到这一点的任何方法。如果有人可以帮助我改进这一点,我会给出最佳建议的答案,无论它多么小。

// failover example1: "document.getElementById('gbqfb')"
// failover example2: "document.querySelector("div#gbqfb")"
public static WebElement getElementByLocator(final By locator, String failover) {
  Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
    .withTimeout(30, TimeUnit.SECONDS)
    .pollingEvery(5, TimeUnit.SECONDS);
    .ignoring(NoSuchElementException.class,StaleElementReferenceException.class);
  WebElement we = wait.until( ExpectedConditions
      .presenceOfElementLocated( locator ) );
  if ( we.isNull() ) {
    JavascriptExecutor js = (JavascriptExecutor) driver;
    if ( !failover.isEmpty() ) {
      we = (WebElement)js.executeScript( failover );
      if ( we.isNull() ) LOG.info("Still couldn't get element.");
    } else {
      LOG.info("No failover String available.  Cannot try with " +
        "a JavascriptExecutor.");
    }    
  }
  return we;
}

1 个答案:

答案 0 :(得分:0)

实际上回答了类似的问题here

我不建议将任何内容委托给javascript。使用Selenium给你的东西......这已经足够了。

我在我构建的每个框架中都放置了一些东西,这非常有效。这是从here找到的框架的一个例外。

在对对象执行任何操作之前,我实现了一种伪等待类型方法。亲自尝试一下。这非常有效。

这些是来自AutomationTest

的方法
/**
 * Checks if the element is present or not.<br>
 * @param by
 * @return <i>this method is not meant to be used fluently.</i><br><br.
 * Returns <code>true</code> if the element is present. and <code>false</code> if it's not.
 */
public boolean isPresent(By by) {
    if (driver.findElements(by).size() > 0) return true;
    return false;
}

/**
 * Private method that acts as an arbiter of implicit timeouts of sorts.. sort of like a Wait For Ajax method.
 */
private WebElement waitForElement(By by) {
    int attempts = 0;
    int size = driver.findElements(by).size();

    while (size == 0) {
        size = driver.findElements(by).size();
        if (attempts == MAX_ATTEMPTS) fail(String.format("Could not find %s after %d seconds",
                                                         by.toString(),
                                                         MAX_ATTEMPTS));
        attempts++;
        try {
            Thread.sleep(1000); // sleep for 1 second.
        } catch (Exception x) {
            fail("Failed due to an exception during Thread.sleep!");
            x.printStackTrace();
        }
    }

    if (size > 0) System.err.println("WARN: There are more than 1 " + by.toString() + " 's!");

    return driver.findElement(by);
}

我所做的,无论何时我执行某些事情,例如

getText(By.cssSelector("input#someId"))

如果第一次没有找到它,它会等待1秒钟。如果它发现它,继续。这样做了5次,所以总共等了5秒......这是完全可以的,因为如果你找不到你需要的元素,那么你的测试应该会在那时失败。

此外,根据经验,我可以告诉您,使用driver.findElements()WebDriverWait更有效。

这并不意味着我不使用它们......只是不是为了那个。不幸的是,我没有将这个功能添加到selenium框架的入门中,所以我只会告诉你何时使用Webdriverwait。

所以我的测试看起来像 -

@Config(url="http://systemunder.test", browser=CHROME)
public class MyClass extends AutomationTest {

    @Test
    public void testSomething() {
        setText(By.id("blah")) // if <* id="blah" /> doesn't exist, waits 1+ seconds for it to appear before interacting.
        .click(By.id("Blah2")) // ^ same thing here.
        .waitForPresent(By.cssSelector("ajaxy")); // this method right here would circumvent the hard waits, with webdriverwait's.
    }
}

我不记得为什么之前它对我不起作用,但在这样的东西中使用webdriverwaits是完美的。