UI自动化执行,偶发如下报错,自动化连接不上Chromedriver进程。
java.net.ConnectException: Failed to connect to localhost/0:0:0:0:0:0:0:1:31693 Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03' System info: host: 'WIN7-11', ip: '10.2.7.42', os.name: 'Windows 7', os.arch: 'x86', os.version: '6.1', java.version: '1.8.0_121' Driver info: driver.version: RemoteWebDriver
自动化使用的Selenium版本为3.141.59
Chromedriver挂时,都是调用了如下方法点击页面的按钮:
void clickByActions(String selector){
clickByActions(findElement(selector))
}
void clickByActions(WebElement el){
Actions actions = new Actions(driver)
actions.click(el).release().perform()
}
解决办法,可以参考如下代码做实现:
void clickByJsonActions(String selector){
clickByJsonActions(findElement(selector));
}
void clickByJsonActions(WebElement element){
HasInputDevices deviceOwner = (HasInputDevices) driver;
Mouse jsonMouse = deviceOwner.getMouse();
RemoteWebElement remoteWebElement = (RemoteWebElement) element;
Coordinates coordinates = remoteWebElement.getCoordinates();
jsonMouse.mouseMove(coordinates);
jsonMouse.mouseDown(coordinates);
jsonMouse.mouseUp(coordinates);
}
原因:selenium3.x版本在底层维护了多套不同协议选择,JSON Wire Protocol 和 W3C WebDriver Protocol,默认的协议是 JSON Wire Protocol ,在Chromedriver版本较新时,selenium会自动切换为 W3C WebDriver Protocol。
W3C协议在通过Actions点击时,使用的实际上是驱动的actions接口,部分老网页不支持新的事件,最后就会导致Chromedriver崩溃。
可以做个简单的测试,需要启动Chromedriver并唤醒Chrome,拿到返回的session,在被Chromedriver唤醒的Chrome中手动或者通过自动化进入怀疑有问题的页面,通过如下代码模拟点击,如果页面正常,进行下一步。
public class ClickByJsonTest {
// 使用拿到的SessionId替换
static String sessionId = "51811ef491724433eb45d3d6be7344ea";
public static void main(String[] args) throws IOException {
// 由于我的按钮在另外一个窗口,这里切换了窗口,如果不需要切换窗口,请注释掉切换窗口的相关代码
Command command = genCommand(DriverCommand.GET_WINDOW_HANDLES);
JsonHttpCommandCodec commandCodec = new JsonHttpCommandCodec();
HttpRequest encode = commandCodec.encode(command);
OkHttpClient okHttpClient = new OkHttpClient(new okhttp3.OkHttpClient(),new URL("http://localhost:32466/"));
HttpResponse httpResponse = okHttpClient.execute(encode);
W3CHttpResponseCodec responseCodec = new W3CHttpResponseCodec();
Response decode = responseCodec.decode(httpResponse);
List<String> handles = (List<String>) decode.getValue();
Map<String, String> handle = new HashMap<>();
handle.put("handle",handles.get(1));
Command switchWindow = genCommandAndParameters(DriverCommand.SWITCH_TO_WINDOW, handle);
HttpRequest encode1 = commandCodec.encode(switchWindow);
HttpResponse execute = okHttpClient.execute(encode1);
Response decode1 = responseCodec.decode(execute);
System.out.println(decode1.getValue());
Command command1 = genCommand(DriverCommand.GET_CURRENT_WINDOW_HANDLE);
HttpRequest encode2 = commandCodec.encode(command1);
HttpResponse execute1 = okHttpClient.execute(encode2);
Response decode2 = responseCodec.decode(execute1);
System.out.println(decode2.getValue());
handle.clear();
handle.put("using","css selector");
handle.put("value","#send");
Command command2 = genCommandAndParameters(DriverCommand.FIND_ELEMENT, handle);
HttpRequest encode3 = commandCodec.encode(command2);
HttpResponse execute2 = okHttpClient.execute(encode3);
Response decode3 = responseCodec.decode(execute2);
Map<String, String> valueMap = (Map<String, String>) decode3.getValue();
handle.clear();
String value = null;
for (String s : valueMap.keySet()) {
value = valueMap.get(s);
}
handle.put("element", value);
Command command3 = genCommandAndParameters(DriverCommand.MOVE_TO, handle);
HttpRequest encode4 = commandCodec.encode(command3);
HttpResponse execute3 = okHttpClient.execute(encode4);
Command command4 = genCommand(DriverCommand.MOUSE_DOWN);
HttpRequest encode5 = commandCodec.encode(command4);
HttpResponse execute4 = okHttpClient.execute(encode5);
Command command5 = genCommand(DriverCommand.MOUSE_UP);
HttpRequest encode6 = commandCodec.encode(command5);
HttpResponse execute5 = okHttpClient.execute(encode6);
Command command6 = genCommand(DriverCommand.CLICK);
}
static Command genCommand(String com){
return new Command(new SessionId(sessionId), com);
}
static Command genCommandAndParameters(String com, Map<String, String> parameters){
return new Command(new SessionId(sessionId), com,parameters);
}
}
可以通过如下代码模拟Actions的点击行为,执行之后,Chromedriver如预期中的挂掉了,那么问题就在这里。
public class ClickByActionTest {
// 使用拿到的SessionId替换
static String sessionId = "51811ef491724433eb45d3d6be7344ea";
public static void main(String[] args) throws IOException {
// 由于我的按钮在另外一个窗口,这里切换了窗口,如果不需要切换窗口,请注释掉切换窗口的相关代码
Command command = genCommand(DriverCommand.GET_WINDOW_HANDLES);
W3CHttpCommandCodec commandCodec = new W3CHttpCommandCodec();
HttpRequest encode = commandCodec.encode(command);
OkHttpClient okHttpClient = new OkHttpClient(new okhttp3.OkHttpClient(), new URL("http://localhost:32466/"));
HttpResponse httpResponse = okHttpClient.execute(encode);
W3CHttpResponseCodec responseCodec = new W3CHttpResponseCodec();
Response decode = responseCodec.decode(httpResponse);
List<String> handles = (List<String>) decode.getValue();
Map<String, String> handle = new HashMap<>();
handle.put("handle", handles.get(1)); // 获取第一个窗口句柄
Command switchWindow = genCommandAndParameters(DriverCommand.SWITCH_TO_WINDOW, handle);
HttpRequest encode1 = commandCodec.encode(switchWindow);
HttpResponse execute = okHttpClient.execute(encode1);
Response decode1 = responseCodec.decode(execute);
System.out.println(decode1.getValue());
Command command1 = genCommand(DriverCommand.GET_CURRENT_WINDOW_HANDLE);
HttpRequest encode2 = commandCodec.encode(command1);
HttpResponse execute1 = okHttpClient.execute(encode2);
Response decode2 = responseCodec.decode(execute1);
System.out.println(decode2.getValue());
handle.clear();
handle.put("using", "css selector");
handle.put("value", "#send");
Command command2 = genCommandAndParameters(DriverCommand.FIND_ELEMENT, handle);
HttpRequest encode3 = commandCodec.encode(command2);
HttpResponse execute2 = okHttpClient.execute(encode3);
Response decode3 = responseCodec.decode(execute2);
Map<String, String> valueMap = (Map<String, String>) decode3.getValue();
String value = null;
for (String s : valueMap.keySet()) {
value = valueMap.get(s);
}
handle.clear();
handle.put("element", value);
Command command3 = genCommandAndParameters(DriverCommand.MOVE_TO, handle);
HttpRequest encode4 = commandCodec.encode(command3);
HttpResponse execute3 = okHttpClient.execute(encode4);
Response decode4 = responseCodec.decode(execute3);
Command command4 = genCommand(DriverCommand.MOUSE_DOWN);
HttpRequest encode5 = commandCodec.encode(command4);
HttpResponse execute4 = okHttpClient.execute(encode5);
Command command5 = genCommand(DriverCommand.MOUSE_UP);
HttpRequest encode6 = commandCodec.encode(command5);
HttpResponse execute5 = okHttpClient.execute(encode6);
Command command6 = genCommand(DriverCommand.CLICK);
//这里是模拟的Chromedriver转换后的Actions点击行为
// handle.put("actions", "[{\"type\":\"pointerMove\",\"origin\":{\"ELEMENT\":\"" + value + "\"},\"x\":0,\"y\":0},{\"type\":\"pointerDown\",\"button\":0},{\"type\":\"pointerUp\",\"button\":0}]");
// Command command3 = genCommandAndParameters(DriverCommand.ACTIONS, handle);
// HttpRequest encode4 = commandCodec.encode(command3);
// HttpResponse execute3 = okHttpClient.execute(encode4);
// Response decode4 = responseCodec.decode(execute3);
// System.out.println(decode4.getValue());
}
static Command genCommand(String com){
return new Command(new SessionId(sessionId), com);
}
static Command genCommandAndParameters(String com, Map<String, String> parameters){
return new Command(new SessionId(sessionId), com,parameters);
}
}