最近给 Sonic 提交了一个小 PR,分享一下我的踩坑记录
作为从 Sonic 开源就开始投入使用的我们来说,Sonic 还是很让我们佩服的,无论是迭代速度和维护力度都是我们从未见过的。
我们的 App 属于混合应用,基于原生 +H5 的形式开发。上一年开始我们开始投入到 UI 自动化里面,刚好 Sonic 提供了自动切换 WebView、切换 Handle 的操作,也能操作 H5 控件,但是更复杂的操作得要用 Sonic 的 自定义脚本 去完成。
例如: 将设备中心的区域往某个方向拖拽多少像素,代码太长就不放出来了
例如: 将 WebView 页面滚动到目标控件到顶部
import org.openqa.selenium.JavascriptExecutor;
def scrollToView(selector,pathValue) {
try{
JavascriptExecutor jsExe = (JavascriptExecutor) androidStepHandler.chromeDriver;
jsExe.executeScript("arguments[0].scrollIntoView();", androidStepHandler.findWebEle(selector,pathValue));
} catch(Exception e){
throw e;
}
}
使用的时候直接使用就可以了
scrollToView("xpath","//div[text()=\"xxx\"]")
落地下来 UI 自动化效果还是不错的。自定义脚本初衷是作者为了开放给用户使用更多自定义的能力(甚至直接调用 Agent 本身许多方法),但是对于我们业务测试的小伙伴来说,还是 Sonic 直接提供 UI 操作更方便呀,这样就可以专注到业务测试中。于是想着,给 Sonic 直接提个 PR 参与建设!
git clone git@github.com:SonicCloudOrg/sonic-agent.git
官网详细的文档 传送门
我们分两步:
其实 Sonic 已经封装得差不多了,我们在 org/cloud/sonic/agent/tests/handlers/AndroidStepHandler.java 下随便找个地方新开一个方法
public void swipeByDefinedDirection(HandleContext handleContext, String slideDirection, int distance) throws Exception {
}
handleContext
:是 Sonic 用来传输测试信息,报错结果等等的实体,每个方法都要带上slideDirection
:滑动方向 distance
:距离像素首先我们要获取设备当前屏幕尺寸,AndroidDeviceBridgeTool
中有现成方法,于是乎:
public void swipeByDefinedDirection(HandleContext handleContext, String slideDirection, int distance) throws Exception {
String size = AndroidDeviceBridgeTool.getScreenSize(iDevice);
String[] winSize = size.split("x");
int width = BytesTool.getInt(winSize[0]);
int height = BytesTool.getInt(winSize[1]);
log.sendStepLog(StepType.INFO, "", "设备分辨率为:" + width + "x" + height);
}
这样宽高我们都拿到了,中心坐标也就能直接拿到
int centerX = (int) Math.ceil(width / 2.0);
int centerY = (int) Math.ceil(height / 2.0);
注意,这里有一个大坑!
我在将逻辑搬运给 iOS 的时候,SibTool
也有一个获取分辨率的方法
SibTool.getSize(String udId)
结果在调试的时候一直滑动没有反应,后来跟作者了解了下,原来是这样
因此在这个需求里面,获取设备长宽应该用的是
WindowSize size = iosDriver.getWindowSize();
int width = size.getWidth();
int height = size.getHeight();
滑动事件 Sonic 已经封装好了,支持 APK 触控和 ADB 触控,我们直接调用AndroidTouchHandler
的swipe
方法就行
try {
AndroidTouchHandler.swipe(iDevice, centerX, centerY, centerX, targetY);
} catch (Exception e) {
handleContext.setE(e);
}
handleContext.setDetail("拖动坐标(" + centerX + "," + centerY + ")到(" + centerX + "," + targetY + ")");
最后我们在最下方的runStep
中加上 case:
case "swipeByDefinedDirection" -> swipeByDefinedDirection(handleContext, step.getString("text"), step.getInteger("content"));
这样前端传入swipeByDefinedDirection
类型和入参就可以了。
这个就更简单了,直接将之前写好的 Groovy 复制过来就行了,查找控件的方法 Sonic 封装好了,我们只需要将 JavascriptExecutor 的处理加入就行
public void webElementScrollToView(HandleContext handleContext, String des, String selector, String pathValue){
handleContext.setStepDes("滚动页面元素" + des + " 至顶部可见");
WebElement we;
try{
we = findWebEle(selector, pathValue);
} catch (Exception e){
handleContext.setE(e);
return;
}
JavascriptExecutor jsExe = chromeDriver;
jsExe.executeScript("arguments[0].scrollIntoView();", we);
handleContext.setDetail("控件元素" + selector + ":"+ pathValue + "滚动至页面顶部");
}
最终代码: https://github.com/SonicCloudOrg/sonic-agent/pull/315/files
前端我个人并不是很擅长,不过作者说最近他会顺便补上,到时候就可以跟我们目前使用的可视化操作一样方便了,直接添加到步骤里就能运行。会跟随 v2.4.0 版本一起发布。
虽然这次 PR 的技术含量并不是很高,但是在跟作者沟通改进的过程中,学习了很多
很开心也有幸成为了 Sonic 贡献者之一,贡献者证书也在快递路上了,让人期待的精美小礼物~