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<Object> 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();
}
}