什么是toast?
toast是用来提示信息的一种控件。它是一种很方便的消息提示框,会在屏幕中显示一个消息提示框,没任何按钮,也不会获得焦点一段时间过后自动消失!
android中的toast规范
- 出现在屏幕底部。
- 只能放文字不能带图标,文字要精简不宜太长。
- 不是模态的,可以透过Toast对其他控件进行操作。
- 短时间后会自动消失。
- 不能对Toast进行交互,不能手动操作让Toast主动消失。
注意这仅仅只是规范,很多app中的toast都有打破这个规范。
toast定位前提
toast是uiautomator viewer及appium inspector无法识别的。当我们需要确认toast弹框中的文本是否正确时,需要确定一下环境的版本是否正确:
- appium server 1.6.3以上
- 代码中的desired_capabilities必须指定uiautomator2
- UIautomator2只支持安卓版本为5.0+的版本,所以得确保真机或模拟器的安卓版本符合这个条件
- jdk1.8 64位以上。
代码实战
场景分析
首先点击我的柠檬。这里的元素可通过xpath,用text文本属性进行定位。
接着点击“点击头像登录”。这里的元素可通过id进行定位。
接着点击登录按钮,弹出toast。
如何定位
在appium inspector及uiautomator viewer中是无法定位到toast的:
那么toast弹框怎么定位呢?这里有两种方法。
- 盲写xpath表达式。我们可以尝试盲写xpath表达式。它是什么元素我们不知道,但它的文本属性是:手机号码或密码不能为空。所以可以这么写://*[contains(@text, “手机号码或密码不能为空”)]。
这种方法没法在inspector中通过search for element进行校验,所以只能写进代码中执行才知道表达式是否正确。 - 确定的xpath。可以通过:find_element_by_xpath("//android.widget.Toast")进行定位。但要注意的是,这种方式确实是能定位到toast弹框,但无法获取里面的文本。所以要想获取文本的话只能用第一种方法。
显性等待
在获取toast文本的过程中是需要时间的,所以最好设置一个显性等待。
这里要注意的是,显性等待的条件只能是presence_of_element_located,不能用visibility。
代码
import time
from appium import webdriver
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.common.multi_action import MultiAction
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
package_name = "com.lemon.lemonban"
caps = {
"platformName": "Android",
"deviceName": "emulator-5554",
"appPackage": package_name,
"appActivity": ".activity.MainActivity",
"automationName": "UiAutomator2",
}
# 初始化客户端
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4723/wd/hub',
desired_capabilities=caps,
)
# 隐式等待
driver.implicitly_wait(20)
# 点击我的柠檬
me = driver.find_element(MobileBy.ID, 'com.lemon.lemonban:id/navigation_my')
me.click()
# 点击头像登录
login = driver.find_element(MobileBy.ID,
'com.lemon.lemonban:id/fragment_my_lemon_avatar_layout')
login.click()
#点击登录按钮
login_btn = driver.find_element(MobileBy.ID, 'com.lemon.lemonban:id/btn_login')
login_btn.click()
# toast 定位,并获取toast的文本
el = driver.find_element(By.XPATH, '//*[contains(@text, "手机号码或密码不能为空")]')
print(el.text)
time.sleep(3)
driver.quit()