其实微信小程序不过是正常的 webview 而已. 只是产品概念上的不同. 本质还是 h5.
所以用 appium 是可以进行自动化的.
以我们美团外卖为例. 查看结构就可以看到小程序的 dom 结构.
欢迎大家使用美团外卖小程序 (此处应有广告词)
具体的细节可参考我之前写过 微信 webview 的自动化技术
简单写个 demo 给大家. 我本地是测试通过的. 代码是 scala. 大家自行用自己的语言去实现吧.
关键就是那句
val options = new ChromeOptions()
options.setExperimentalOption("androidProcess", "com.tencent.mm:appbrand1")
capability.setCapability(ChromeOptions.CAPABILITY, options)
测试用例代码
test("测试微信小程序") {
val capability = new DesiredCapabilities()
capability.setCapability("app", "")
capability.setCapability("appPackage", "com.tencent.mm")
capability.setCapability("appActivity", ".ui.LauncherUI")
capability.setCapability("deviceName", "emulator-5554")
capability.setCapability("fastReset", "false")
capability.setCapability("fullReset", "false")
capability.setCapability("noReset", "true")
capability.setCapability("automationName", "appium")
capability.setCapability("platformName", "android")
val options = new ChromeOptions()
options.setExperimentalOption("androidProcess", "com.tencent.mm:appbrand1")
capability.setCapability(ChromeOptions.CAPABILITY, options)
val url = "http://127.0.0.1:4723/wd/hub"
val driver = new AndroidDriver[WebElement](new URL(url), capability)
driver.findElementByXPath("//*[@text='发现']").click
driver.findElementByXPath("//*[@text='小程序']").click
driver.findElementByXPath("//*[contains(@text, '美团外卖')]").click
println(driver.getContextHandles)
driver.context("WEBVIEW_com.tencent.mm:tools")
Thread.sleep(5000)
println(driver.getPageSource)
driver.findElementByXPath("//*[contains(@url, '美食')]").click()
driver.findElementByXPath("//*[contains(., '金百万')]").click()
}
这是行业第一篇用 appium 进行微信小程序的自动化测试的例子.
转载请注明出自 testerhome 测试社区和原链 https://testerhome.com/topics/7053
TesterHome 微信小助手
TesterHome 微信公众号
谢谢思寒分享,果断收藏
感谢思寒分享,神速啊
神速呐,👍
刚刚我还留言,说思寒分享过微信的测试,对小程序应该是没有问题的,没想到这么快就出成果了。。
666,刚打算写个~~
谁打赏的 20 啊, 谢谢啦. 告诉我小数点后的数字让我认识下土豪
#7 楼 @Lihuazhang 可以试试
#8 楼 @seveniruby 手工赞一个。 话说我上次打赏了一篇你的文章,是不是没收到提示啊
这个真心要点赞
—— 来自 TesterHome 官方 安卓客户端
@seveniruby 楼主 appbrand1 和 appbrand2 appbrand3 这个是解释一下么 做微信自动化的时候 MAC 端需要启动 chrmedriver 吗 端口不设置要紧吗 ?
@seveniruby
代码如下:driver.find_element_by_xpath("//android.widget.TextView[contains(@text,'美团外卖 +')]").click()
print driver.contexts
driver.context('WEBVIEW_com.tencent.mm:tools')
driver.find_element_by_xpath("//span[text() = '我的']").click()
报错:
[u'NATIVE_APP', u'WEBVIEW_com.tencent.mm:appbrand1', u'WEBVIEW_com.tencent.mm:tools']
Traceback (most recent call last):
File "D:/AutoTestStudy/pythonstudy/H5Test.py", line 90, in
driver.context('WEBVIEW_com.tencent.mm:tools')
TypeError: 'unicode' object is not callable
今天按照@seveniruby 的方式尝试了一下,发现:
options.setExperimentalOption("androidProcess", "com.tencent.mm:appbrand2");//小程序
这里的 appbrand2 好像不是固定的,是不是和微信上添加了几个小程序有关呢?
另外,切换 context 的时候,是不是要使用:
driver.context("WEBVIEW_com.tencent.mm:appbrand2");
而不是:
driver.context("WEBVIEW_com.tencent.mm:tools");
在我的一个酷派手机上,这样操作才能执行成功
切换过去就没反应了,webvies 的东西操作不了,连 System.out.println("2222222"); 也打印不出来.用的是 java
代码:
dr.findElementByXPath("//[@text='小程序']").click();
dr.findElementByXPath("//[contains(@text, 'money 计算器')]").click();
Thread.sleep(5000);
Set contexts = dr.getContextHandles();
for (String contextName : contexts) {
System.out.println(contextName);
}
dr.context("WEBVIEW_com.tencent.mm:appbrand0");
System.out.println("2222222");
#17 楼 @levinzhang1981 appbrand2 确实跟添加小程序的个数有关
#20 楼 @knight80829 广告内容, 删除
@ort886 chromedriver 的什么问题,如何解决的?
@ort886 我 chromedriver 提示 chrome not reachable 是什么情况?
@ort886 我 chrome not reachable 的问题解决了 现在就是跟你一样 切进去了 没任何反应 一会后元素点击报错... 我的 chromedriver2.25 chrome 版本 54 请问你怎么解决了?
@seveniruby 楼主 有个疑问 你 androidProcess 配置 填的是"com.tencent.mm:appbrand1" 为什么 driver.context("WEBVIEW_com.tencent.mm:tools") 而不是 driver.context(“com.tencent.mm:appbrand1”)?
我切换成功
[debug] [JSONWP Proxy] Proxying [GET /status] to [GET http://127.0.0.1:8000/wd/hub/status] with no b
ody
[debug] [JSONWP Proxy] Got response with status 200: "{\"sessionId\":\"\",\"status\":0,\"value\":{\"
build\":{\"version\":\"alpha\"},\"os\":{\"arch\":\"x86_64\",\"name\":\"Windows NT\",\"version\":\"6.
1.7601 SP1\"}}}"
[debug] [JSONWP Proxy] Proxying [POST /session] to [POST http://127.0.0.1:8000/wd/hub/session] with
body: {"desiredCapabilities":{"chromeOptions":{"androidPackage":"com.tencent.mm","androidUseRunningA
pp":true,"args":[],"androidProcess":"com.tencent.mm:appbrand0","extensions":[],"androidDeviceSerial"
:"ZX1G4294SH"}}}
[debug] [JSONWP Proxy] Got response with status 200: {"sessionId":"83a43f95f4d58aaa08c13278d617eb15"
,"status":0,"value":{"acceptSslCerts":true,"applicationCacheEnabled":false,"browserConnectionEnabled
":false,"browserName":"chrome","chrome":{"chromedriverVersion":"2.26.436362 (5476ec6bf7ccbada1734a0c
dec7d570bb042aa30)"},"cssSelectorsEnabled":true,"databaseEnabled":false,"handlesAlerts":true,"hasTou
chScreen":false,"javascriptEnabled":true,"locationContextEnabled":true,"mobileEmulationEnabled":fals
e,"nativeEvents":true,"pageLoadStrategy":"normal","platform":"ANDROID","rotatable":false,"takesHeapS
napshot":true,"takesScreenshot":true,"unexpectedAlertBehaviour":"","version":"37.0.0.0","webStorageE
nabled":true}}
[debug] [Chromedriver] Changed state to 'online'
[debug] [MJSONWP] Responding to client with driver.setContext() result: null
[HTTP] <-- POST /wd/hub/session/9a81663a-b01d-4846-90e0-779e160c4644/context 200 5078 ms - 76、
但是找元素时候提示这个
[debug] [JSONWP Proxy] Got response with status 200: {"sessionId":"83a43f95f4d58aaa08c13278d617eb15"
,"status":7,"value":{"message":"no such element: Unable to locate element: {\"method\":\"xpath\",\"s
elector\":\"//*[text()='机票']\"}\n (Session info: webview=37.0.0.0)\n (Driver info: chromedriver=
2.26.436362 (5476ec6bf7ccbada1734a0cdec7d570bb042aa30),platform=Windows NT 6.1.7601 SP1 x86_64)"}}
原因大概知道了,去哪儿出行页面显示很丰富,但是 getsource 看到 body 是空的
,所以 xpath 什么也找不到
**
@seveniruby
楼主的例子能成功执行?还是只是提供一个思路
美团外卖首页,getsource ,也是
我试了这么多,source 的数据都是
形式的,这样的话不能支持自动化,还是我的方式错了我使用 contextNames = driver.getContextHandles(); 获取的只有 NATIVE_APP 一个,没有 WebView 相关的成员, 这个问题各位是怎么解决的,@seveniruby
请问楼主,这两种写法的区别是什么?
请教下,已经切换到 webview,但是找不到元素,是怎么回事啊,谢谢
package com.demo;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.NoSuchContextException;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.AndroidMobileCapabilityType;
import io.appium.java_client.remote.MobileCapabilityType;
import java.io.File;
import java.net.URL;
import java.util.Set;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.Assert;
import org.testng.annotations.Test;
public class Demo {
@Test
public static void startapp() throws Exception{
AppiumDriver driver;
DesiredCapabilities capabilities=new DesiredCapabilities();
capabilities.setCapability(CapabilityType.BROWSER_NAME, "");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "127.0.0.1:21503");
// capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "192.168.154.101:5555");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "5.1.1");
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
//启动应用的包名
capabilities.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.tencent.mm");
//启动应用的起始 ACTIVITY
capabilities.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY,".ui.LauncherUI");
//支持中文输入
capabilities.setCapability("unicodeKeyboard", "True");
//重置输入法为系统默认
capabilities.setCapability("resetKeyboard", "True");
ChromeOptions options = new ChromeOptions();
// options.setExperimentalOption("androidProcess", "com.tencent.mm:tools");
options.setExperimentalOption("androidProcess", "com.tencent.mm:appbrand0");
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
// DesiredCapabilities option = new DesiredCapabilities();
// option.setCapability("androidProcess", "com.tencent.mm:appbrand0");
// capabilities.setCapability(ChromeOptions.CAPABILITY, option);
driver=new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
Thread.sleep(5000);
System.out.println("启动 app 成功");
Thread.sleep(5000);
driver.findElementByXPath("//[@text='发现']").click();
driver.findElementByXPath("//[@text='小程序']").click();
Thread.sleep(2000);
// driver.findElementByXPath("//*[contains(@text, '京东购物')]").click();
// Thread.sleep(5000);
//
// try{
// Set contexts = driver.getContextHandles();
// for (String context : contexts) {
// //打印出来看看有哪些 context
// System.out.println(context);
// }
// driver.context("WEBVIEW_com.tencent.mm:appbrand0");
// }catch(NoSuchContextException nce){
// Assert.fail("没有这个 context:");
// }
// Thread.sleep(5000);
// driver.findElementByXPath("//span[contains(text(), '领优惠券')]").click();
// ---------------------------------------------------------------------------------------
driver.findElementByXPath("//*[contains(@text, '美团外卖')]").click();
Thread.sleep(5000);
try{
Set contexts = driver.getContextHandles();
for (String context : contexts) {
//打印出来看看有哪些 context
System.out.println(context);
}
driver.context("WEBVIEW_com.tencent.mm:appbrand0");
}catch(NoSuchContextException nce){
Assert.fail("没有这个 context:");
}
Thread.sleep(5000);
driver.findElementByXPath("//[contains(@url, '美食')]").click();
driver.findElementByXPath("//[contains(., '金百万')]").click();
Thread.sleep(2000);
driver.quit();
}
}
App 更换了腾讯的 X5 浏览器内核,获取不到元素,该怎么解决呢
@chenxin 获取不到元素的问题 你解决了么
你好,我也是用 java 写,参考你的代码我无法在真机上进入微信,小白求助~
public void setUp() throws Exception {
File classpathRoot = new File(System.getProperty("user.dir"));
File appDir = new File(classpathRoot, "/Mall/src/main/java/apps/");
File app = new File(appDir, "weixin_1280.apk");
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("app",app.getAbsolutePath());
capabilities.setCapability("platformName", "Android");
capabilities.setCapability("deviceName", "DU2SSE15AH117303");
capabilities.setCapability("platformVersion", "4.4.2");
//将上面获取到的包名和 Activity 名设置为值
capabilities.setCapability("appPackage", "com.tencent.mm");
capabilities.setCapability("appActivity", ".ui.LauncherUI");
//支持中文
capabilities.setCapability("unicodeKeyboard" ,"True");
//capabilities.setCapability("resetKeyboard", "True");
//重签名
capabilities.setCapability("noSign","True");
capabilities.setCapability("sessionOverride", true);
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("androidProcess", "com.tencent.mm:appbrand0");
capabilities.setCapability(ChromeOptions.CAPABILITY, options);
driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub,capabilities"));
}
相同的代码两次执行不同的结果
@seveniruby 思寒,这个问题一直解决不了,能帮我看看吗?
debug 了一下,发现了问题~~~~
如下图,webview 是切换了,没问题,关键是切换后有两个句柄,遇到相同问题的同学可以注意一下。
现在这个方案应该不可行了吧?因为已经无法通过 chromedriver 拿到小程序的 webview
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("app","");
capabilities.setCapability("appPackage","com.tencent.mm");
capabilities.setCapability("appActivity", ".ui.LauncherUI");
capabilities.setCapability("deviceName","S889PBJR99999999");
capabilities.setCapability("fastReset","false");
capabilities.setCapability("fullRest","false");
capabilities.setCapability("noRest","true");
capabilities.setCapability("automationName","Appium");
capabilities.setCapability("platformName","Android");
capabilities.setCapability("platformVersion","5.1");
capabilities.setCapability("recreateChromeDriverSessions", "True");
ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("androidProcess","com.tencent.mm:tools");
capabilities.setCapability(ChromeOptions.CAPABILITY,options);
AndroidDriver driver = new AndroidDriver<WebElement>(new URL("http://127.0.0.1:4723/wd/hub"),capabilities);
//等待元素加载出来
Thread.sleep(5000);
driver.findElement(By.xpath("//*[@text='发现']")).click();
int width = driver.manage().window().getSize().width;
int height = driver.manage().window().getSize().height;
Thread.sleep(2000);
driver.swipe(width /2, height / 4 + 200,width / 2,height / 4,200);
Thread.sleep(2000);
driver.findElement(By.xpath("//*[@text='小程序']")).click();
Thread.sleep(2000);
driver.findElement(By.xpath("//*[@text='京东秒杀']")).click();
System.out.println("所有上下文" + driver.getContext());
System.out.println("所有句柄" + driver.getContextHandles());
driver.context("WEBVIEW_com.tencent.mm:tools");
Thread.sleep(6000);
System.out.println("已经进入webview");
System.out.println(driver.getPageSource());
System.out.println(driver.getContext());
driver.quit();
切换微信小程序的 webview 的时候报错 我真的很疑惑,楼主帮帮我
报错:
已尝试解决方案:
1.关闭代理,不可行
2.换 appium 下的 chrome 版本,使之与手机浏览器内核一致,不可行
3.加代码 ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("androidProcess","WEBVIEW_com.tencent.mm:tools");
capabilities.setCapability("ChromeOptions", options);混合 app 通过,微信自动化仍然报错
4.注释 android-hybrid.js 相关语句,不可行
求大神解决!!!
报错:
已尝试解决方案:
1.关闭代理,不可行
2.换 appium 下的 chrome 版本,使之与手机浏览器内核一致,不可行
3.加代码 ChromeOptions options = new ChromeOptions();
options.setExperimentalOption("androidProcess","WEBVIEW_com.tencent.mm:tools");
capabilities.setCapability("ChromeOptions", options);混合 app 通过,微信自动化仍然报错
4.注释 android-hybrid.js 相关语句,不可行
求大神解决!!!
你好,请问如果是别的 app(不是 wechat),如何设置 androidProcess 呢?我获取的 webview 进程名只是"WEBVIEW_chrome"
启动了 chromedriver 之后就无法启动 adb,有没有人遇到过
你好,Chromedriver 启动了就无法启动 adb,不知道你有没有遇到过
info: [debug] ["WEBVIEW_com.tencent.mm:appbrand0","WEBVIEW_com.tencent.mm:appbrand1","WEBVIEW_com.tencent.mm:support","WEBVIEW_com.tencent.mm:tools"]
info: [debug] Available contexts: NATIVE_APP,WEBVIEW_com.tencent.mm:appbrand0,WEBVIEW_com.tencent.mm:appbrand1,WEBVIEW_com.tencent.mm:support,WEBVIEW_com.tencent.mm:tools
info: [debug] Connecting to chrome-backed webview
info: Set chromedriver binary as: C:\Program Files (x86)\Appium\node_modules\appium\build\chromedriver\windows\chromedriver.exe
info: Killing any old chromedrivers, running: FOR /F "usebackq tokens=5" %a in (netstat -nao ^| findstr /R /C:"9515 "
) do (FOR /F "usebackq" %b in (TASKLIST /FI "PID eq %a" ^| findstr /I chromedriver.exe
) do (IF NOT %b=="" TASKKILL /F /PID %a))
info: No old chromedrivers seemed to exist
info: Spawning chromedriver with: C:\Program Files (x86)\Appium\node_modules\appium\build\chromedriver\windows\chromedriver.exe --url-base=wd/hub --port=9515
info: [CHROMEDRIVER STDOUT] Starting ChromeDriver 2.35.528161 (5b82f2d2aae0ca24b877009200ced9065a772e73) on port 9515
Only local connections are allowed.
info: Proxying [GET /status] to [GET http://127.0.0.1:9515/wd/hub/status] with no body
info: Got response with status 200: {"sessionId":"","status":0,"value":{"build":{"version":"alpha"},"os":{"arch":"x86_64","name":"Windows NT","version":"10.0.16299"}}}
info: Proxying [POST /session] to [POST http://127.0.0.1:9515/wd/hub/session] with body: {"desiredCapabilities":{"chromeOptions":{"androidPackage":"com.tencent.mm","androidUseRunningApp":true,"androidDeviceSerial":"98d0f5b6"}}}
info: Got response with status 200: {"sessionId":"e46dab3cfa7d7d8a585ed7424fb2e70e","status":13,"value":{"message":"unknown error: Failed to run adb command, is the adb server running?\n (Driver info: chromedriver=2.35.528161 (5b82f2d2...
你好,以美团外卖小程序为例,如果在 NATIVE_APP 情况下 (不切换 webview 进入小程序反而可以识别对象),用 driver.find_element_by_xpath("//*[contains(@content-desc,'美食')]").click() 可以发现对象并点击。
但是如果在进入小程序后,切换到 WEBVIEW_com.tencent.mm:appbrand1(我觉得应该是切换成功的 appium log: [debug] [Chromedriver] Changed state to 'online'),用 chrome://inspect/#devices 得到 “美食” 的 xpath,然后
driver.find_element_by_xpath("/html/body/wx-view/wx-view/wx-swiper[1]/div/div[1]/div/wx-swiper-item[1]/wx-view[1]").click() 就会报错找不到对象。
请问:
你好,为什么你的 contexts 这么多,感觉又小程序的,我的只有三个:
Available contexts: ["NATIVE_APP","WEBVIEW_com.tencent.mm:toolsmp","WEBVIEW_com.tencent.mm:tools"]
我切换到 webveiw,是微信打开 H5 的 webview,不是小程序的 webview,怎么弄
想问一下各位大大 现在这种方案还可行吗 我看文章发表的时间是 17 年 1 月,已经一年多过去了
我也是切换成功以后,获取不到页面的元素,切换页面的 current_context,里面都是 CSS 的内容。
求助!
无法找到小程序底部导航栏的元素,导致无法切换,所有 contexts、handles 都循环切换过、试过了,还是找不到。
用 chrome://inspect 工具打开小程序页面 也是不显示这个导航栏,只显示导航栏上面的页面,不知道是小程序本身的问题还是其他原因导致的。
page_source 也只能看到导航栏【首页】里的页面元素。