How to use child_by_description method in uiautomator

Best Python code snippet using uiautomator

FTTAutomator.py

Source:FTTAutomator.py Github

copy

Full Screen

1# -*- coding: UTF-8 -*-2'''3Created on 20170315 by leochechen4@Summary: ftt-automator 基于uiautomator的二次封装5'''6import os7import re8import time9import itertools10import threading11from functools import wraps12from time import sleep13from libs import yaml14from UiAutomator import point, rect, param_to_property, DEVICE_PORT, next_local_port15from UiAutomator import Adb, AutomatorServer, AutomatorDevice16try:17 import urllib218except ImportError:19 import urllib.request as urllib220try:21 from httplib import HTTPException22except:23 from http.client import HTTPException24try:25 if os.name == 'nt':26 from libs import urllib327except: # to fix python setup error on Windows.28 pass29class FTTJob(threading.Thread):30 def __init__(self, group=None, target=None, name=None,31 args=(), kwargs={}, verbose=None, interval=1, times=-1):32 super(FTTJob, self).__init__(name=name)33 self.__name = name34 self.__target = target35 self.__args = args36 self.__kwargs = kwargs37 self.__interval = interval38 self.__times = times39 # 用于暂停线程的标识40 self.__flag = threading.Event()41 # 设置为True42 self.__flag.set()43 # 用于停止线程的标识44 self.__running = threading.Event()45 # 将running设置为True46 self.__running.set()47 def _control(self):48 if self.__target and self.__times > 0:49 self.__target(*self.__args, **self.__kwargs)50 self.__times -= 151 if self.__times == 0:52 self.stop()53 elif self.__target and self.__times == -1:54 # print "invoke {}".format(self.name)55 self.__target(*self.__args, **self.__kwargs)56 else:57 raise EnvironmentError("target and times doesn't meet the conditions")58 time.sleep(self.__interval)59 def run(self):60 while self.__running.isSet():61 self.__flag.wait()62 self._control()63 def pause(self):64 self.__flag.clear()65 def resume(self):66 self.__flag.set()67 def stop(self):68 self.__flag.set()69 self.__running.clear()70 def __str__(self):71 return "<FTTJob-{} interval={} times={}>".format(self.__name, self.__interval, self.__times)72 def __repr__(self):73 return self.__str__()74class FTTTestCase(object):75 '''76 @FttTestCase77 class TestCase(object):78 def __init__(self):79 pass80 def setup(self):81 pass82 def tearDown(self):83 pass84 '''85 @property86 def cls_name(self):87 return self.cls.__name__88 @staticmethod89 def super(ftttestcase_cls, instance):90 '''91 返回父类对象92 :param ftttestcase_cls: 被FTTTestCase修饰的类93 :param instance: self94 :return:95 '''96 if hasattr(ftttestcase_cls, 'cls'):97 return super(ftttestcase_cls.cls, instance)98 else:99 raise TypeError("{} hasn't cls property".format(ftttestcase_cls))100 @staticmethod101 def inherit(ftttestcase_cls):102 '''103 从ftttestcase实例中提取类实例104 :param ftttestcase_cls: 被FTTTestCase修饰的类105 :return: 原始类106 '''107 if type(ftttestcase_cls) is not FTTTestCase:108 raise EnvironmentError("只接受@FTTTestCase修饰过的类")109 return ftttestcase_cls.cls110 def __init__(self, cls):111 self.cls = cls112 def __call__(self, custom_module=None):113 ins = self.cls()114 if hasattr(ins, 'setup'):115 ins.setup()116 else:117 raise EnvironmentError("ftt testcase class hasn't setup method...")118 if hasattr(ins, 'cleanup'):119 ins.cleanup()120 else:121 raise EnvironmentError("ftt testcase class hasn't cleanup method...")122 def __getattr__(self, item):123 return getattr(self.cls, item)124 def __str__(self):125 return "<{0} instance-{1}>".format(self.__class__.__name__, self.cls.__name__)126 def __repr__(self):127 return self.__str__()128class FTTUISelector(object):129 # 将yaml格式语法数据提取出来,形成AutomatorDeviceObject130 __fields = (131 'text',132 'textContains',133 'textMatches',134 'textStartsWith',135 'className',136 'classNameMatches',137 'description',138 'descriptionContains',139 'descriptionMatches',140 'descriptionStartsWith',141 'checkable',142 'checked',143 'clickable',144 'longClickable',145 'scrollable',146 'enabled',147 'focusable',148 'focused',149 'selected',150 'packageName',151 'packageNameMatches',152 'resourceId',153 'resourceIdMatches',154 'index',155 'instance'156 )157 def __init__(self, device):158 self.ftt_device = device159 self._steams = {}160 self._path = None161 self._steam = None162 @property163 def path(self):164 return self._path.encode('utf-8') if type(self._path) is unicode else self._path165 @property166 def steam(self):167 return self._steam168 def load(self, path):169 self._steam = self._steams[path] if path in self._steams else yaml.load(open(path))170 self._path = path171 def _get_selector(self, name):172 '''173 根据yaml数据文件中的name关键字或者selector174 :param name: 关键字175 :return:176 '''177 try:178 return self._get_selector_instance(None, self._steam[name])179 except TypeError:180 raise EnvironmentError("配置Selector UI的页面路径")181 def _get_selector_instance(self, instance, data):182 '''183 获取selector实例184 :param instance: 当前的selector实例185 :param data: 用例定位的数据186 :return:187 '''188 selector = dict([(item, data[item]) for item in data.keys() if item in self.__fields])189 if 'method' not in data:190 crt_instance = self.ftt_device(**selector)191 elif data['method'] == 'child_by_text':192 '''193 method: child_by_text194 txt: your child text195 ui selecotor196 '''197 crt_instance = instance.child_by_text(data['txt'], **selector)198 elif data['method'] == 'child_by_instance':199 '''200 method: child_by_instance201 instance: your instance202 ui selecotor203 '''204 crt_instance = instance.child_by_instance(int(data['instance']), **selector)205 elif data['method'] == 'child_by_description':206 '''207 method: child_by_description208 txt: your child text209 ui selecotor210 '''211 crt_instance = instance.child_by_instance(int(data['txt']), **selector)212 else:213 crt_instance = eval('.'.join(['instance', data['method']]))(**selector)214 if 'extand' not in data:215 return crt_instance216 else:217 return self._get_selector_instance(crt_instance, data['extand'])218 def __call__(self, name):219 return self._get_selector(name)220class FTTAdb(Adb):221 def __init__(self, serial=None, adb_server_host=None, adb_server_port=None):222 super(FTTAdb, self).__init__(serial=serial, adb_server_host=adb_server_host, adb_server_port=adb_server_port)223 self.__adb_cmd = None224 def adb(self):225 if self.__adb_cmd is None:226 '''227 if "ANDROID_HOME" in os.environ:228 filename = "adb.exe" if os.name == 'nt' else "adb"229 adb_cmd = os.path.join(os.environ["ANDROID_HOME"], "platform-tools", filename)230 if not os.path.exists(adb_cmd):231 raise EnvironmentError(232 "Adb not found in $ANDROID_HOME path: %s." % os.environ["ANDROID_HOME"])233 else:234 import distutils235 if "spawn" not in dir(distutils):236 import distutils.spawn237 adb_cmd = distutils.spawn.find_executable("adb")238 if adb_cmd:239 adb_cmd = os.path.realpath(adb_cmd)240 else:241 raise EnvironmentError("$ANDROID_HOME environment not set.")242 self.__adb_cmd = adb_cmd243 '''244 # @Modified by leochechen on 20171221.245 # use the specified adb on nt system246 filename = "adb.exe" if os.name == 'nt' else "adb"247 self.__adb_cmd = os.path.join(os.path.dirname(__file__), "../adb", filename)248 return self.__adb_cmd249class FTTAutomatorServer(AutomatorServer):250 __jar_files = {251 "bundle.jar": "libs/bundle.jar",252 "uiautomator-stub.jar": "libs/uiautomator-stub.jar"253 }254 __apk_files = ["libs/app-uiautomator.apk", "libs/app-uiautomator-test.apk"]255 __sdk = 0256 def __init__(self, serial=None, local_port=None, device_port=None, adb_server_host=None, adb_server_port=None):257 self.uiautomator_process = None258 self.adb = FTTAdb(serial=serial, adb_server_host=adb_server_host, adb_server_port=adb_server_port)259 self.device_port = int(device_port) if device_port else DEVICE_PORT260 if local_port:261 self.local_port = local_port262 else:263 try: # first we will try to use the local port already adb forwarded264 for s, lp, rp in self.adb.forward_list():265 if s == self.adb.device_serial() and rp == 'tcp:%d' % self.device_port:266 self.local_port = int(lp[4:])267 break268 else:269 self.local_port = next_local_port(adb_server_host)270 except:271 self.local_port = next_local_port(adb_server_host)272 def push(self):273 base_dir = os.path.dirname(__file__)274 for jar, url in self.__jar_files.items():275 filename = os.path.join(base_dir, "..", url)276 self.adb.cmd("push", filename, "/data/local/tmp/").wait()277 return list(self.__jar_files.keys())278 def install(self):279 base_dir = os.path.dirname(__file__)280 for apk in self.__apk_files:281 self.adb.cmd("install", "-r -t", os.path.join(base_dir, "..", apk)).wait()282 def start(self, timeout=5):283 # print "in FTTAutomatorServer start"284 if self.sdk_version() < 18:285 files = self.push()286 cmd = list(itertools.chain(287 ["shell", "uiautomator", "runtest"],288 files,289 ["-c", "com.github.uiautomatorstub.Stub"]290 ))291 else:292 self.install()293 cmd = ["shell", "am", "instrument", "-w",294 "com.github.uiautomator.test/android.support.test.runner.AndroidJUnitRunner"]295 self.uiautomator_process = self.adb.cmd(*cmd)296 self.adb.forward(self.local_port, self.device_port)297 while not self.alive and timeout > 0:298 time.sleep(0.1)299 timeout -= 0.1300 if not self.alive:301 raise IOError("RPC server not started!")302 def stop(self):303 # print "in FTTAutomatorServer stop"304 if self.uiautomator_process and self.uiautomator_process.poll() is None:305 res = None306 try:307 res = urllib2.urlopen(self.stop_uri)308 self.uiautomator_process.wait()309 except:310 self.uiautomator_process.kill()311 finally:312 if res is not None:313 res.close()314 self.uiautomator_process = None315 try:316 self.adb.cmd("shell", "am", "force-stop", "com.github.uiautomator").communicate()[0].decode("utf-8").strip().splitlines()317 except Exception, ex:318 pass319class FTTAutomatorDevice(AutomatorDevice):320 def __init__(self, serial=None, local_port=None, adb_server_host=None, adb_server_port=None):321 self.server = FTTAutomatorServer(322 serial=serial,323 local_port=local_port,324 adb_server_host=adb_server_host,325 adb_server_port=adb_server_port326 )327 self.adb = self.server.adb328 self.fttSelector = FTTUISelector(self)329 self.fttJobs = []330 @property331 def source(self):332 return self.fttSelector333 @source.setter334 def source(self, _path):335 self.fttSelector.load(_path)336 def wait_for_times(self, count, interval, error):337 '''338 每隔规定时间等待目前方法执行一次339 :param count: 重试的次数340 :param interval: 每一次重试的时间间隔341 :param error: 超时之后的错误提示342 :return: 一个目标函数的装饰器343 '''344 def decorator(func):345 @wraps(func)346 def wrap_function(*args, **kwargs):347 retry = count348 try:349 start_time = time.time()350 if retry == -1:351 while True:352 result = func(*args, **kwargs)353 if result:354 return result355 while retry > 0:356 # print "try to invoke {}".format(func)357 result = func(*args, **kwargs)358 if result:359 return result360 else:361 retry -= 1362 sleep(interval)363 else:364 raise EnvironmentError(error)365 finally:366 self.total_wait_time = time.time() - start_time367 return wrap_function368 return decorator369 def click_selector(self, name, count=20, interval=0.5):370 '''371 点击一个navtive控件372 :param name: ftt-ui-selector定位结构的名字373 :param count: 循环次数374 :param interval: 一次的时间间隔375 :return:376 '''377 return self.fttSelector(name).click() \378 if self.wait_exists_and_enabled(name=name, count=count, interval=interval) else None379 def wait_exists_and_enabled(self, name, count=20, interval=0.5):380 '''381 判断native控件是否存在并且有效382 :param name: ftt-ui-selector定位结构的名字383 :param count: 循环次数384 :param interval: 一次的时间间隔385 :return:386 '''387 ui_selector = self.fttSelector(name)388 @self.wait_for_times(count=count, interval=interval,389 error="在{0}s内,【{1}】【{2}】没有找到并生效".format(count*interval, self.fttSelector.path, name))390 def is_exists():391 return ui_selector.exists and ui_selector.info['enabled'] is True392 return is_exists()393 def text(self, name):394 '''395 获取ftt-ui-selector的文本内容396 :param name: ftt-ui-selector定位结构的关键字397 :return:398 '''399 return self.fttSelector(name).info['text'].encode('utf-8')400 def wait_exists(self, name, timeout=5000):401 '''402 在一定时间内等待控件出现403 :param name: ftt-ui-selector定位结构的关键字404 :param timeout: 超时时间405 :return:406 '''407 self.fttSelector(name).wait.exists(timeout=timeout)408 def wait_gone(self, name, timeout=5000):409 '''410 在一定时间内等待控件消失411 :param name: ftt-ui-selector定位结构的关键字412 :param timeout: 超时时间413 :return:414 '''415 self.fttSelector(name).wait.gone(timeout=timeout)416 def get_centre(self, name):417 '''418 获取ftt ui selector获取中心点的坐标419 :param name: ftt ui selector420 :return:421 '''422 # Bounds (left,top) (right,bottom)423 bounds = self.fttSelector(name).info['visibleBounds']424 return point((bounds['right'] - bounds['left'])/2 + bounds['left'],425 (bounds['bottom'] - bounds['top'])/2 + bounds['top'])426 def get_rect(self, name):427 '''428 获取ftt ui selector的矩阵大小429 :param name: ftt ui selector430 :return: {"top": top, "left": left, "bottom": bottom, "right": right}431 '''432 bounds = self.fttSelector(name).info['visibleBounds']433 return rect(**bounds)434 def screen_size(self):435 '''436 返回屏幕尺寸437 :return:438 '''439 return {"width": self.info['displayWidth'],440 "height": self.info['displayHeight']}441 def swipe_to(self, _from, _to, steps=50):442 '''443 从ftt ui selector的_from目标滑动到_to目标,以stps为步长444 :param _from: ftt ui selector445 :param _to: ftt ui selector446 :param steps: 步长447 :return:448 '''449 my_to = self.get_centre(_to)450 my_from = self.get_centre(_from)451 self.swipe(my_from['x'], my_from['y'], my_to['x'], my_to['y'], steps=steps)452 @property453 def swipe_until(self):454 '''455 :Usage:456 >>> # 从experience_device_first选择一个方向滑动到my_unknow_device存在为止457 >>> swipe_until.up('_from', '_to')458 >>> swipe_until('up', '_from', '_to')459 >>> swipe_until.down('_from', '_to')460 >>> swipe_until('down', '_from', '_to')461 >>> swipe_until.left('_from', '_to')462 >>> swipe_until('left', '_from', '_to')463 >>> swipe_until.right('_from', '_to')464 >>> swipe_until('right', '_from', '_to')465 :return:466 '''467 @param_to_property(orientation=['right', 'left', 'up', 'down'])468 def _swipe_until(orientation, _from, _to, steps=100, count=10, interval=0.1):469 '''470 从_from开始滑动直到 _to存在为止471 :param orientation: 滑动方向472 :param _from: ftt ui selector473 :param _to: ftt ui selector474 :param steps: 滑动步长475 :param count: 滑动次数476 :param interval: 滑动间隔477 '''478 obj = self479 class SwipeHandler(object):480 def __init__(self, name):481 self.start = obj.get_centre(name)482 @obj.wait_for_times(count=count, interval=interval,483 error="朝方向-{0}滑动{1}次后,没有发现{2}".format(orientation,count,_to))484 def until(self):485 if orientation == 'up':486 end = point(self.start['x'], self.start['y'] - steps)487 elif orientation == 'down':488 end = point(self.start['x'], self.start['y'] + steps)489 elif orientation == 'left':490 end = point(self.start['x'] - steps, self.start['y'])491 elif orientation == 'right':492 end = point(self.start['x'] + steps, self.start['y'])493 else:494 raise EnvironmentError("不支持的滚动方向-{}".format(orientation))495 obj.swipe(self.start['x'], self.start['y'], end['x'], end['y'], steps=10)496 return obj.fttSelector(_to).exists497 SwipeHandler(_from).until()498 return _swipe_until499 def watcher(self, name):500 obj = self501 class Watcher(object):502 def __init__(self):503 self.ftt_selectors = []504 @property505 def matched(self):506 @param_to_property(method=['click', 'press'])507 def _matched(method, args=(), kwargs={}):508 for selector in self.ftt_selectors:509 if not obj(**selector).exists:510 return False511 if method == 'click':512 if obj(**kwargs).exists:513 obj(**kwargs).click()514 elif method == 'press':515 for arg in args:516 obj.press(arg)517 return _matched518 def when(self, **kwargs):519 self.ftt_selectors.append(kwargs)520 return self521 def click(self, **kwargs):522 obj.fttJobs.append(FTTJob(name=name, target=lambda: self.matched.click(kwargs=kwargs), interval=1))523 @property524 def press(self):525 @param_to_property(526 "home", "back", "left", "right", "up", "down", "center",527 "search", "enter", "delete", "del", "recent", "volume_up",528 "menu", "volume_down", "volume_mute", "camera", "power")529 def _press(*args):530 obj.fttJobs.append(FTTJob(name=name, target=lambda: self.matched.press(args=args), interval=1))531 return _press532 return Watcher()533 @property534 def watchers(self):535 obj = self536 class Watchers(list):537 def __init__(self):538 pass539 def find(self, name):540 for job in obj.fttJobs:541 if job.name == name:542 return job543 raise EnvironmentError("没有找到task-{}".format(name))544 def pause(self, name):545 self.find(name).pause()546 def resume(self, name):547 self.find(name).resume()548 def run(self, name):549 return self.find(name).start()550 def remove(self, name):551 job = self.find(name)552 job.stop()553 obj.fttJobs.remove(job)554 @property555 def all(self):556 return obj.fttJobs557 return Watchers()558def get_device(serial=None, local_port=None):559 '''560 单例模式,获取创建设备连接561 :param serial: 设备serial562 :param local_port: 本地连接uiautomator的端口563 :return:564 '''565 if get_device.instance:566 return get_device.instance567 else:568 get_device.instance = FTTAutomatorDevice(serial=serial, local_port=local_port)569 return get_device.instance570get_device.instance = None571if __name__ == "__main__":572 FTTDevice = get_device()573 print FTTDevice.info574 FTTDevice.source = u"D:\workspace\IDDAutomation\workspace\layout\\ui\搜索.yaml"...

Full Screen

Full Screen

longclick.py

Source:longclick.py Github

copy

Full Screen

...89 d.wait.update()90@step(u'长按可滚动框架【%s】内的特征描述【%s】页面元素$' % (mode_pvs, mode_text))91def click_child_by_desc(step, scrollcond, trait):92 scroll = get_dict_from_cond(scrollcond)93 d(**scroll).child_by_description(trait,allow_scroll_search=True,descriptionContains=trait).long_click()94 d.wait.update()95@step(u'长按可滚动框架【%s】内的特征序号【%s】页面元素$' % (mode_pvs, mode_int))96def click_child_by_inst(step, framecond, trait):97 frame = get_dict_from_cond(framecond)98 d(**frame).child_by_instance(trait,instance=trait).long_click()99 d.wait.update()100# 完备写法101@step(u'长按可滚动框架【%s】内的页面元素【%s】且其子孙结点含text值【%s】$' % (mode_pvs, mode_pvs, mode_text))102def long_click_child_by_text(step, scrollcond, cond, text):103 scroll = get_dict_from_cond(scrollcond)104 my = get_dict_from_cond(cond)105 d(**scroll).child_by_text(text,allow_scroll_search=True,**my).long_click()106 d.wait.update()107@step(u'长按可滚动框架【%s】内的页面元素【%s】且其子孙结点含description值【%s】$' % (mode_pvs, mode_pvs, mode_text))108def long_click_child_by_desc(step, scrollcond, cond, desc):109 scroll = get_dict_from_cond(scrollcond)110 my = get_dict_from_cond(cond)111 d(**scroll).child_by_description(desc,allow_scroll_search=True,**my).long_click()112 d.wait.update()113#未提供长按左上角或右下角功能语句114@step(u'在框架【%s】内,长按页面元素【%s】且子孙结点含instance序号【%s】$' % (mode_pvs, mode_pvs, mode_int))115def long_click_child_by_inst(step, framecond, cond, inst):116 frame = get_dict_from_cond(framecond)117 my = get_dict_from_cond(cond)118 d(**frame).child_by_instance(inst,**my).long_click()119 d.wait.update()120# *-* 左上角 *-*121@step(u'长按页面元素左上角【%s】$' % (mode_pvs))122def long_click_tl(step, condition):123 dict = get_dict_from_cond(condition)124 d(**dict).long_click.topleft()125 d.wait.update()...

Full Screen

Full Screen

click.py

Source:click.py Github

copy

Full Screen

...90 d(**scroll).child_by_text(trait,allow_scroll_search=True,textContains=trait).click.wait()91@step(u'点击可滚动框架【%s】内的特征描述【%s】页面元素$' % (mode_pvs, mode_text))92def click_child_by_desc(step, scrollcond, trait):93 scroll = get_dict_from_cond(scrollcond)94 d(**scroll).child_by_description(trait,allow_scroll_search=True,descriptionContains=trait).click.wait()95@step(u'点击可滚动框架【%s】内的特征序号【%s】页面元素$' % (mode_pvs, mode_int))96def click_child_by_inst(step, framecond, trait):97 frame = get_dict_from_cond(framecond)98 d(**frame).child_by_instance(trait,instance=trait).click.wait()99# 完备写法100@step(u'点击可滚动框架【%s】内的页面元素【%s】且其子孙结点含text值【%s】$' % (mode_pvs, mode_pvs, mode_text))101def click_child_by_text(step, scrollcond, cond, text):102 print cond103 print text104 scroll = get_dict_from_cond(scrollcond)105 my = get_dict_from_cond(cond)106 d(**scroll).child_by_text(text,allow_scroll_search=True,**my).click.wait()107@step(u'点击可滚动框架【%s】内的页面元素【%s】且其子孙结点含description值【%s】$' % (mode_pvs, mode_pvs, mode_text))108def click_child_by_desc(step, scrollcond, cond, desc):109 scroll = get_dict_from_cond(scrollcond)110 my = get_dict_from_cond(cond)111 d(**scroll).child_by_description(desc,allow_scroll_search=True,**my).click.wait()112@step(u'点击可滚动框架【%s】内的页面元素【%s】且其子孙结点含instance序号【%s】$' % (mode_pvs, mode_pvs, mode_int))113def click_child_by_inst(step, framecond, cond, inst):114 frame = get_dict_from_cond(framecond)115 my = get_dict_from_cond(cond)116 d(**frame).child_by_instance(inst,**my).click.wait()117# *-* 左上角 *-*118@step(u'点击页面元素左上角【%s】$' % (mode_pvs))119def click_tl(step, condition):120 dict = get_dict_from_cond(condition)121 d(**dict).click.topleft()122 d.wait.update()123@step(u'点击页面元素左上角,父【%s】自【%s】$' % (mode_pvs, mode_pvs))124def click_child_tl(step, cond, childcond):125 father = get_dict_from_cond(cond)...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run uiautomator automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful