课前准备
- 阅读appium的log
- 完成之前的作业
- 提前了解 “雪球股票”小程序
- devtools协议 https://chromedevtools.github.io/devtools-protocol/
WebView认知
控件树里有没有对应的class
- android.webkit.WebView
- com.tencent.tbs.core.webkit.WebView
webview的组件的class多数都是android.view.View
webview组件分析
- uiautomatorviewer
- chrome://inspect
坑
- chrome从62版本开始引入了css标签解析的bug,导致无法很好的去inspect web页面
- chrome://inspect需要翻x 需要下载62版本的chrome
自动化注意事项
- 合理的使用显式等待
- accessibility xpath定位
webview的调试
- 模拟器默认开启webview的debug开关。网易mumu模拟器除外
chromedriver相关的配置
- chromedriverUseSystemExecutable=true 默认使用/usr/local/lib/node_modules/appium/node_modules/_appium-chromedriver@4.14.0@appium-chromedriver/chromedriver/mac/chromedriver
- chromedriverExecutableDir指向chromedriver的存放目录,目前不生效
- chromedriverExecutable执行chromedriver的绝对路径
示例代码
def test_webview(self):
self.driver.find_element(MobileBy.XPATH, "//*[@text='交易']").click()
#返回的是不带webview的组件,默认是找不到webview内的元素,除非设置了等待
print(self.driver.page_source)
#原生定位
self.driver.find_element(MobileBy.ID, 'page_type_fund').click()
WebDriverWait(self.driver, 10, 1).until(lambda x: "WEBVIEW_com.xueqiu.android" in self.driver.contexts)
print("=======webview load")
#返回的是带有webview组件树,此时可以使用原生定位去定位webview内的元素
print(self.driver.page_source)
#使用原生定位方式定位webview控件
self.driver.find_element(MobileBy.ACCESSIBILITY_ID, "蛋卷基金安全开户").click()
self.driver.switch_to.context("WEBVIEW_com.xueqiu.android")
print("======webview enter")
#返回的是html,此次可以使用selenium的css定位
print(self.driver.page_source)
self.driver.find_element(By.NAME, "tel").send_keys("15600534760")
self.driver.find_element(By.NAME, "captcha").send_keys("1234")
self.driver.find_element(By.CSS_SELECTOR, ".dj-button").click()
Webview识别原理
- appium会启动chromedriver /Users/seveniruby/projects/chromedriver/2.20/chromedriver --url-base=wd/hub --port=8000 --adb-port=5037 --verbose
- app或者浏览器,底层使用的是android的webview组件,webview组件有一个debug特性,可以在启动的时候,写入一个domain socket记录, webview_devtools_remote_3548
- adb -P 5037 -s emulator-5554 shell cat /proc/net/unix 找到对应的webview调试入口
- adb forward tcp:$port localabstract:webview_devtools_remote_$pid
- curl http://localhost:7770/json/version
- curl http://localhost:7770/json
自动寻找webview并分析
list_webview ()
{
port=$1;
adb shell cat /proc/net/unix | grep -a webview | awk -F_ '{print $NF}' | tr -d '\\r' | while read pid; do
port=$((port+=1));
adb forward tcp:$port localabstract:webview_devtools_remote_$pid;
curl http://localhost:$port/json/version;
curl http://localhost:$port/json;
done
}
list_webview 7770
真机为了提高性能,默认不开启webview的debug属性,需要研发在webview的组件上调用debug开关
https://developers.google.com/web/tools/chrome-devtools/remote-debugging/webviews?hl=zh-cn
adb network功能
networking:
connect HOST[:PORT] connect to a device via TCP/IP [default port=5555]
disconnect [HOST[:PORT]]
disconnect from given TCP/IP device [default port=5555], or all
forward --list list all forward socket connections
forward [--no-rebind] LOCAL REMOTE
forward socket connection using:
tcp:<port> (<local> may be "tcp:0" to pick any open port)
localabstract:<unix domain socket name>
localreserved:<unix domain socket name>
localfilesystem:<unix domain socket name>
dev:<character device name>
jdwp:<process pid> (remote only)
forward --remove LOCAL remove specific forward socket connection
forward --remove-all remove all forward socket connections
为什么uiautomator可以识别webview组件
- 本来是不可识别的
- 从android的高版本6.0之后uiautomator已经可以识别webview了,他会把webview转化为原生控件来表示
小程序
todo:
- 44813内核不支持调试
- appium无法识别小程序内的控件,但是uiautomatorviewer却可以
测试策略
- 使用原生定位方式,通用性比较好
- 把内嵌的网页使用手机浏览器代替测试
- 如果还搞不定,模拟器上进行测试
腾讯FAT
常见错误
An unknown server-side error occurred while processing the command. Original error: No Chromedriver found that can automate Chrome '44.0.2403'. See https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/web/chromedriver.md for more details. You could also try to enable automated chromedrivers download server feature
微信小程序无法切换context
[debug] [WD Proxy] Got response with status 200: {"sessionId":"960cbe136b1e6a12c5a4b574d0bfd9ca","status":13,"value":{"message":"unknown error: unable to discover open pages\\n (Driver info: chromedriver=2.39.562713 (dd642283e958a93ebf6891600db055f1f1b4f3b2),platform=Mac OS X 10.14.5 x86_64)"}}
[debug] [WD Proxy] Determined the downstream protocol as 'MJSONWP' per session creation request
[WD Proxy] The response has an unknown format
[debug] [MJSONWP] Matched JSONWP error code 13 to UnknownError
[Chromedriver] Failed to start Chromedriver session: An unknown server-side error occurred while processing the command. Original error: unknown error: unable to discover open pages
[Chromedriver] (Driver info: chromedriver=2.39.562713 (dd642283e958a93ebf6891600db055f1f1b4f3b2),platform=Mac OS X 10.14.5 x86_64)
[debug] [WD Proxy] Matched '/session' to command name 'createSession'
[debug] [WD Proxy] Proxying [POST /session] to [POST http://127.0.0.1:8000/wd/hub/session] with body: {"desiredCapabilities":{"chromeOptions":{"androidPackage":"com.tencent.mm","androidUseRunningApp":true,"androidDeviceSerial":"SWYDU16524028640"},"loggingPrefs":{"browser":"ALL"}}}
[debug] [Chromedriver] Webview version: 'Chrome/66.0.3359.126'
三端的脚本执行环境以及用于渲染非原生组件的环境是各不相同的:
在 iOS 上,小程序逻辑层的 javascript 代码运行在 JavaScriptCore 中,视图层是由 WKWebView 来渲染的,环境有 iOS8、iOS9、iOS10;
在 Android 上,
旧版本,小程序逻辑层的 javascript 代码运行中 X5 JSCore 中,视图层是由 X5 基于 Mobile Chrome 57 内核来渲染的;
新版本,小程序逻辑层的 javascript 代码运行在 V8 中,视图层是由自研 XWeb 引擎基于 Mobile Chrome 67 内核来渲染的;
在 开发工具上,小程序逻辑层的 javascript 代码是运行在 NW.js 中,视图层是由 Chromium 60 Webview 来渲染的。