接上文https://testerhome.com/topics/7658
由于项目特点,无法通过 ID/NAME 等方式查找 element 并进行相关操作,但又不想用 XPATH(使用 XPATH 定位使得脚本可读性变低,加之页面布局经常改动,使得使用 XPATH 的维护量比较大)。因此,写了通用方法(by_accessibility_id)来查找页面 element。另外,还写了 wait_string 的方法来判断页面中是否有特定的字符串。
使用举例:
class MyCarPage(BasePage):
@teststep
def click_add_car(self):
self.click_element_by_accessibility_id('添加车辆')
class InviteFriendsPage(BasePage):
@teststep
def wait_page(self):
if self.wait_string_use_and('福利', '活动规则'):
return True
else:
return False
源码如下:
1、其中的_wait_element 是一个通用的内部方法,大家可以用这个方法构造出其他的定位方式,如 self._wait_element('content-desc', value=value, max_time=max_time) 中,using='content-desc'就是通过'content-desc'查找 element。
2、大家有更好的实现方式可以一同讨论
from xml.etree.ElementTree import ElementTree
class BasePage(object):
@classmethod
def set_driver(cls, dri):
cls.driver = dri
def get_driver(self):
return self.driver
def wait_string(self, string, max_time=10):
"""
wait string between the gaven time
:param string: string
:param max_time: time that wait the gaven strings
:return: True or False
"""
times = max_time
for i in range(times):
time.sleep(1)
source = self.driver.source
if string in source:
return True
if i == times - 1:
return False
def wait_string_use_and(self, *args, max_time=10):
"""
wait all strings between the gaven time
:param args: strings
:param max_time: time that wait the gaven strings
:return: True or False
"""
times = max_time
for i in range(10):
time.sleep(1)
source = self.driver.source
previous = False
for j in range(len(args)):
if args[j] in source:
if j != 0 and not previous:
return False
previous = True
if j == len(args) - 1:
return True
else:
if previous:
return False
if i == times - 1:
return False
def wait_string_use_or(self, *args, max_time=10):
"""
wait anyone string between the gaven time
:param args: strings
:param max_time: time that wait the gaven strings
:return: True or False
"""
times = max_time
for i in range(10):
time.sleep(1)
source = self.driver.source
for string in args:
if string in source:
return True
if i == times - 1:
return False
def _find_element_in_nodes(self, nodes, using, value):
for node in nodes:
result = self._find_element_in_node(node, using, value)
if result is not None:
return result
def _find_element_in_node(self, node, using, value):
if node.get(using) == value:
return node
child_nodes = node.findall('node')
if len(child_nodes):
return self._find_element_in_nodes(child_nodes, using, value)
else:
return None
@staticmethod
def _parse_bounds(bounds_str):
bounds = bounds_str.split(',')
x_left = int(bounds[0].strip('['))
y_up = int(bounds[1].split(']')[0])
x_right = int(bounds[1].split(']')[1].strip('['))
y_down = int(bounds[2].strip(']'))
x_center = (x_left + x_right) / 2
y_center = (y_up + y_down) / 2
return x_center, y_center
@staticmethod
def _delete_file(filename):
if os.path.exists(filename):
os.remove(filename)
def _wait_element(self, using, value, max_time=10):
times = max_time
stability_flag = ''
for i in range(times):
time.sleep(1)
file = 'source.xml'
with open(file, 'wt', encoding='utf-8') as f:
f.write(self.driver.source)
try:
tree = ElementTree()
tree.parse(file)
root = tree.getroot()
nodes = root.findall('node')
result = self._find_element_in_nodes(nodes, using, value)
if result is not None:
bounds_str = result.get('bounds')
if stability_flag != bounds_str:
stability_flag = bounds_str
else:
self._delete_file(file)
return result
if i == times - 1:
self._delete_file(file)
return None
except Exception:
self._delete_file(file)
raise Exception
def wait_element_by_accessibility_id(self, value, max_time=10):
"""
wait element by accessibility id. in android, wait content-desc
:param value: value
:param max_time: time that wait the gaven value of accessibility id
:return: True or False
"""
result = self._wait_element('content-desc', value=value, max_time=max_time)
if result is not None:
return True
else:
return False
def click_element_by_accessibility_id(self, value, max_time=10):
"""
click element by accessibility id. in android, wait content-desc
:param value: value
:param max_time: time that wait the gaven value of accessibility id
:return:
raise:
WebDriverException
"""
result = self._wait_element('content-desc', value=value, max_time=max_time)
if result is not None:
x, y = self._parse_bounds(result.get('bounds'))
self._tap(x, y)
else:
raise WebDriverException('No such accessibility id that value was you gaven.')