Selendroid Selendroid 的一个坑

恒温 · 2015年06月09日 · 最后由 恒温 回复于 2015年06月10日 · 1461 次阅读

Selendroid 里面有一个坑,比如下面的代码:

@Test
public void shouldGetBodyDOMElementViaJavascript() {
  openWebdriverTestPage(HtmlTestData.XHTML_TEST_PAGE);
  WebElement bodyByJS = (WebElement) driver().executeScript("return document.body;");
  Assert.assertEquals("body", bodyByJS.getTagName());
}

这段代码的意思是,我执行一个 javascript 脚本 return document.body,按照 JavascriptExecutor 的 API 来看,这边就是返回了一个 WebElement 了 。

<li>For an HTML element, this method returns a WebElement</li>
   * <li>For a decimal, a Double is returned</li>
   * <li>For a non-decimal number, a Long is returned</li>
   * <li>For a boolean, a Boolean is returned</li>
   * <li>For all other cases, a String is returned.</li>
   * <li>For an array, return a List&lt;Object&gt; with each object following the rules above. We
   * support nested lists.</li>
   * <li>Unless the value is null or there is no return value, in which null is returned</li>

然后呢,拿到这个 WebElement 后,如果对它进行一些操作,这个时候你就要小心了。比如 getTagName 这个方法,他就会通过 http 请求路由到 SafeRequestHandler 的实现 GetElementTagName 里面,

public class GetElementTagName extends SafeRequestHandler {

  public GetElementTagName(String mappedUri) {
    super(mappedUri);
  }

  @Override
  public Response safeHandle(HttpRequest request) throws JSONException {
    SelendroidLogger.info("get tag name of element command");
    String id = getElementId(request);
    AndroidElement element = getElementFromCache(request, id);
    return new SelendroidResponse(getSessionId(request), element.getTagName());
  }
}

这里面就会去之前缓存的 Element 里面取,结果这坑爹货是 webview 里面的 executeScript 的 Element 并没有缓存,于是你就会得到下面的异常:

org.openqa.selenium.StaleElementReferenceException: The element with id ':wdc:1433853394939' was not found.

这个方法其实是他没用设计好。比如 getPageTitle 就好很多。

public class GetPageTitle extends SafeRequestHandler {

  public GetPageTitle(String mappedUri) {
    super(mappedUri);
  }

  @Override
  public Response safeHandle(HttpRequest request) throws JSONException {
    SelendroidDriver driver = getSelendroidDriver(request);
    return new SelendroidResponse(getSessionId(request), driver.getTitle());
  }
}

直接去 SelendroidDriver 里拿,

@Override
public String getTitle() {
  if (isNativeWindowMode()) {
    return selendroidNativeDriver.getTitle();
  } else {
    return selendroidWebDriver.getTitle();
  }
}
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 5 条回复 时间 点赞

这种巨坑啊。。。不看源码绝对搞不定,看了源码也得改源码才搞的定。。。

#1 楼 @chenhengjie123 改起来成本太高了。 不介意改。 我的做法是:

@Test
  public void shouldGetBodyDOMElementViaJavascript() {
    openWebdriverTestPage(HtmlTestData.XHTML_TEST_PAGE);
    String bodyByJS = (String) driver().executeScript("return document.body.tagName;");
    Assert.assertEquals("body", bodyByJS);
  }

#2 楼 @lihuazhang 这种也行。
不过正常不是应该只有 findElement 方法找的元素才会缓存吗?executeScript 返回的不一定是元素,所以没有缓存也正常。

#3 楼 @chenhengjie123 是的,可以理解。问题在于官方的测试代码就是错误的,会误导人。

#4 楼 @lihuazhang 原来是官方的。。。那要发个 pull request 来 fix 下。。。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册