def do_compare(self, str_arg): """ compare a snapshot file with an expected image file(by default in PNG format). this usually follows a takesnapshot step in a testcase. if the snapshot file is identical with the expected target file, return True. otherwise return False. (Note: UI checking depends on various external factors, for example, different screen brightness value would make the snapshots different, leading to unexpected compare results. therefore comparing snapshots is no longer recommended. If you insist on automated pixel-level UI testcases, make sure you have these factors well managed) format: compare <live captured snapshot> <target prepared snapshot> e.g. 'setup' is a predefined directory to hold prepared snapshots, you may define your own directories. takesnapshot app_drawer_icon_on_screen.png compare app_drawer_icon_on_screen.png setup/designed_app_drawer_icon.png """ arg = validateString(str_arg) source, target = arg.split(' ', 1) if os.path.isfile(source): # Mar 27 @swang: if target file doesn't exist, copy source file to setup directory for later test # 2015-08-27: decided to go to fail path if not os.path.isfile(target): # copy(source, target) self.resultFlag = False raise ValueError('COMPARE FAILED: target file not found.') # if not self.__compareImage(source, target): if not filecmp.cmp(source, target): printLog(self.threadName + 'COMPARE FAILED: source file and target file DIFFER!', logging.WARNING) self.resultFlag = False else: self.resultFlag = False raise ValueError('COMPARE FAILED: source file not found.')
def do_comparex(self, str_arg): """ compare a snapshot file with a set of expected files if the snapshot file is identical with one of the files, return True. otherwise return False. """ arg = validateString(str_arg) file1, fileset = arg.split(' ', 1) if len(fileset) == 0: self.resultFlag = False raise ValueError('Bad parameter. Please check your script.') if not os.path.isfile(file1): self.resultFlag = False raise ValueError(file1 + ' not exist, Please check your script.') # f_list=[pp1 for pp1 in fileset.split(' ') if pp1!=''] for fn in fileset.split(' '): # print file1, f2 if not os.path.isfile(fn): self.resultFlag = False raise ValueError(fn + ' not exist, Please check your script.') if self.__compareImage(file1, fn): self.resultFlag = True print('[Found match. %s and %s are identical.]' % (file1, fn)) return print('[No match found.]') self.resultFlag = False
def do_takesnapshot(self, str_arg): """ take snapshot of the full screen and save it to the file with the given filename format: takesnapshot [filename] e.g. takesnapshot a1.png @param str_arg: filename (string) """ img = None fname = validateString(str_arg) try: # self.adbc.wake() printLog(self.threadName + 'taking snapshot (0,50,%d,%d) ...' % (self.scn_width, self.scn_height)) img = self.adbc.takeSnapshot(reconnect=True) # PIL code img = img.crop((0, 50, self.scn_width, self.scn_height)) img.save(fname, SNAPSHOT_IMAGE_FORMAT) # if self.scn_width>SNAPSHOT_WIDTH: # self.compressImage(fname) # os.remove(fname) # im.save(fname) printLog(self.threadName + 'snapshot saved as %s' % fname) except EnvironmentError: self.resultFlag = False if DEBUG: traceback.print_exc() finally: img = None
def do_checkTextInclusion(self, str_arg): """ check if the given text is included in the message of the specified resource id. (2015-07-22) e.g. checkTextInclusion id/icon_descriptive_text icon to see your Zones. """ # printLog(self.threadName + "[running command 'checkTextInclusion %s']" % str_arg) arg = validateString(str_arg) ret = arg.split(' ', 1) if len(ret) == 1: self.resultFlag = False raise ValueError('Lacking argument of checkTextInclusion.') if iDevice.dump_view: self.__dumpview() try: viewId = ret[0].strip() printLog("finding view by id %s ..." % viewId, logging.DEBUG) tmpView = self.vc.findViewById(viewId) if not tmpView: self.resultFlag = False printLog(self.threadName + '%s is not visible.' % viewId, logging.ERROR) return else: # get element text, and compare it with the given text value tempText = tmpView.getText() printLog(self.threadName + '[text on screen: %s]' % tempText) if not ret[1].strip() in tempText.strip(): self.resultFlag = False except Exception, e: self.resultFlag = False printLog(self.threadName + 'Exception in do_check: %s' % e.message, logging.ERROR)
def do_swipe(self, str_arg=''): """ swipe the screen in the given direction (left, right, up or down) e.g. swipe left @param str_arg: the direction argument (string) @return: result (boolean) """ direction = validateString(str_arg) if direction == 'left': arg = '(%d,%d) (%d,%d)' % ( int(self.scn_width * 0.9), int(self.scn_height * 0.5), int(self.scn_width * 0.1), int(self.scn_height * 0.5)) elif direction == 'right': arg = '(%d,%d) (%d,%d)' % ( int(self.scn_width * 0.1), int(self.scn_height * 0.5), int(self.scn_width * 0.9), int(self.scn_height * 0.5)) elif direction == 'up': arg = '(%d,%d) (%d,%d)' % (int(self.scn_width * 0.5), self.scn_height - 200, int(self.scn_width * 0.5), 0) elif direction == 'down': arg = '(%d,%d) (%d,%d)' % (int(self.scn_width * 0.5), 100, int(self.scn_width * 0.5), self.scn_height) else: self.resultFlag = False raise ValueError("do_swipe: bad argument.") return self.do_drag(arg)
def do_check(self, str_arg): """ check id existency(not visibility! sometimes a view does not show up, e.g. widgets in the other launcher page), if text is given, check if it is identical with what shows on the screen. 2015-08-26: merged the checkchild method with this one. format: check <id>[(child path id sequence)] [text] Note: DO NOT INCLUDE SPACE IN THE CHILD PATH e.g. check id/title_text Personalize Homescreen e.g. check id/parent(4,3,2,2) my text is text @param str_arg: it takes two formats: 1. The target id, and text to be compared (optional) 2. The unique parent id, the path from parent to target child view, the target text (optional) @return boolean """ # printLog(self.threadName + "[running command 'check %s']" % str_arg) str_arg = validateString(str_arg) # parse the args args = str_arg.split(' ', 1) viewId = args[0].strip() if len(args) < 2: target_text = '' else: target_text = args[1] try: # get the target view tv = self.__getView(viewId) if tv: if DEBUG: printLog(self.threadName + 'Found target view %s.' % viewId, logging.DEBUG) if len(target_text) > 0: # get element text, and compare it with the given text value # tmpView=self.vc.findViewWithText(ret[1].strip()) tempText = tv.getText() printLog(self.threadName + '[Text on screen: %s, expected text: %s]' % (tempText, target_text), logging.DEBUG) if tempText == target_text: # printLog('CHECK PASS! Text match.', logging.DEBUG) self.resultFlag = True else: printLog(self.threadName + 'CHECK FAILED! Text not match!', logging.ERROR) self.resultFlag = False else: printLog(self.threadName + 'Target view %s not found.' % viewId, logging.ERROR) self.resultFlag = False except Exception, e: self.resultFlag = False printLog(self.threadName + 'Exception in do_check: %s' % e.message, logging.ERROR) if DEBUG: traceback.print_exc()
def do_type(self, str_arg): """ type the given string in the screen e.g. type I'm OK @param str_arg: the text to type (string) @return: result (boolean) """ try: self.adbc.type(validateString(str_arg)) except Exception, e: printLog(self.threadName + 'TYPE FAILED: %s' % e.message) self.resultFlag = False
def do_start(self, str_arg): """ start an activity (openActivity() in C{Android} can do the same thing) e.g. start com.android.dial @param str_arg: activity (string) """ try: # self.adbc.startActivity(validateString(str_arg)) # the above approach failed in unittest complaining device is offline, weird... return self.runAdbCmd('shell am start -n', validateString(str_arg)) except RuntimeError: self.resultFlag = False if DEBUG: traceback.print_exc()
def do_clickchild(self, str_arg): """ [obsoleted] This method is merged with 'click'. Kept here for backward compatibility. click a certain child for one unique ID use it while there are multiple same name ID, but there is one unique root parent format: clickchild <root node ID> <child branch id list> e.g. clickchild id/root (0,1) 2015-08-27: merged into click method, kept here for backward compatibility 2015-08-11: using AVC will no longer require including the offset parameter --------------------------------------------------------------------------------- Below instruction is for Monkeyrunner which is DEPRECATED. 2015-05-06: updated to include the offset parameter so that the tool can click on the right view center position format: clickchild <root node ID> <child branch id list> <root node relative position offset to screen> e.g. clickchild id/root (0,1) (18,338) """ # printLog(self.threadName + "[running 'clickchild %s']" % str_arg) # arg validation arg = validateString(str_arg) if iDevice.dump_view: self.__dumpview() try: # to avoid ' ' two spaces case # suppose string like: id/button1 (5,2,3,3,3) (0,50) # i = arg.index(' ') # ids = arg[0:i] # arg = arg[i + 1:].strip() # seqs = arg[1:-1].split(',') arg_list = arg.split(' ') if len(arg_list) == 2: printLog(self.threadName + 'do_clickChild: using default offset.') node_id, seqs = arg_list self.__clickChildView(node_id, seqs[1:-1].split(',')) elif len(arg_list) == 3: # node_id, seqs, offset = arg_list # self.__clickChildView(node_id, seqs[1:-1].split(','), self.__getPointXY(offset.strip())) raise ValueError("using AVC will NO LONGER require including the offset parameter.") else: raise ValueError('missing argument.') except ValueError: printLog(self.threadName + 'do_clickChild: click failed', logging.ERROR) traceback.print_exc() self.resultFlag = False time.sleep(1)
def do_click(self, str_arg): """ click by a view id(or parent id with child path), a point in (x, y) coordinates, or the text in a view (text box, button etc.). 2015-05-14: modified to include the way to click by text http://www.softteco.com/blog/android-decoding-click-low-level-event/ 2015-08-27: merged the clickchild method format: click <view_id>|<view_id>(child path id sequence)|text/<target text>|(x,y) e.g. click id/button e.g. click id/card_holder_id(2,0,0,0,0,1) e.g. click text/Show me e.g. click (100,200) """ arg = validateString(str_arg) for tmp in range(REPEAT_TIMES_ON_ERROR): try: if arg.startswith('('): point = self.__getPointXY(arg) printLog(self.threadName + '[clicking point %s...]' % arg, logging.DEBUG) self.adbc.touch(point[0], point[1], "DOWN_AND_UP") else: if "/" not in arg: raise ValueError('bad argument of do_click().') # get the target view tv = self.__getView(arg) if tv: if DEBUG: printLog('Found view %s.' % arg, logging.DEBUG) printLog(self.threadName + 'tinyStr: %s' % tv.__tinyStr__(), logging.DEBUG) # printLog(self.threadName + 'position and size: {}'.format(tv.getPositionAndSize()), # logging.DEBUG) printLog(self.threadName + '[clicking id %s...]' % arg, logging.DEBUG) tv.touch() else: printLog('Target view %s not found.' % arg, logging.ERROR) self.resultFlag = False return except Exception, e: printLog(self.threadName + 'the %dst try failed due to %s, will retry.' % (tmp, e.message), logging.ERROR) # self.reconnect() time.sleep(1) continue
def do_keypress(self, str_arg): """ press a key e.g. keypress KEYCODE_HOME check http://developer.android.com/reference/android/view/KeyEvent.html for the full list KEYCODE_DPAD_LEFT 21 KEYCODE_DPAD_RIGHT 22 KEYCODE_DPAD_UP 19 KEYCODE_DPAD_DOWN 20 KEYCODE_TAB 61 KEYCODE_ENTER 66 ... @param str_arg: the keycode """ arg = validateString(str_arg) self.adbc.press(arg, "DOWN_AND_UP")
def do_checkchild(self, str_arg): """ [obsoleted] This method is merged with 'check'. Kept here for backward compatibility. This is an extension to method 'check' to handle child elements whose id is not unique within the layout. @param str_arg: the unique parent ID, the path from parent to target child view, the target text @return: none, but resultFlag indicate the result, yes or not e.g. checkChild id/parent (4,3,2,2) my text is text note: the final text string is optinal. If not specified, will check if the child exists """ arg = validateString(str_arg).strip() try: # to avoid ' ' two spaces case # suppose string like: id/text1 (5,4,2,3,3,3) textfield i = arg.index(' ') ids = arg[0:i] arg = arg[i + 1:].strip() if iDevice.dump_view: self.__dumpview() if ' ' in arg: i = arg.index(' ') seqs = arg[1:i - 1].split(',') arg = arg[i + 1:].strip() texts = arg target_text = self.__getChildViewText(ids, seqs) printLog(self.threadName + '[text on screen: %s]' % target_text) self.resultFlag = True if texts != '': if texts == target_text: self.resultFlag = True else: self.resultFlag = False else: seqs = arg[1:-1].split(',') if self.__getChildView(ids, seqs): self.resultFlag = True else: self.resultFlag = False except Exception, e: # gbk problem self.resultFlag = False traceback.print_exc() printLog(self.threadName + 'Exception in do_checkchild: %s' % e.message, logging.ERROR)
def do_assert(self, str_arg): """ do assertion to the result of previous step to determine if the step passed or failed. e.g. if you expect the result of previous text check match, then write "assert true" following "check id/xx xxx" @param str_arg: true of false @return: none """ arg = validateString(str_arg) if arg not in ('true', 'false'): self.resultFlag = False raise ValueError('Bad parameter.') if (arg == 'true' and self.resultFlag) or (arg == 'false' and not self.resultFlag): printLog(self.threadName + '[ASSERT PASS]', logging.DEBUG) self.resultFlag = True else: # printLog(self.threadName+'[status=%s]' % self.resultFlag) printLog(self.threadName + '[ASSERT FAIL!]', logging.DEBUG) self.resultFlag = False raise AssertionError()
def do_takesnapshotx(self, str_arg): """ take a snapshot of the given area and save it to the file with the given filename format: takesnapshotx (x1,y1) (x2,y2) [filename] e.g. takesnapshotx (0,0) (400,400) a2.png @param str_arg: arguments and filename (string) """ # img = None fname = "" args = validateString(str_arg) # print args try: pa = re.compile('^(\(\d*,\d*\))\D*(\(\d*,\d*\))(.+)$') matches = pa.search(args.strip()).groups() # print matches point1 = self.__getPointXY(matches[0]) point2 = self.__getPointXY(matches[1]) fname = matches[2].strip() except AttributeError, e: printLog(self.threadName + "AttributeError: %s" % e.message, logging.ERROR) raise ValueError('do_takesnapshotx: Bad parameter.')
def do_longpress(self, str_arg): """ long press a UI element by view id, a point or text format: 1. longpress <view id> [seconds] 2. longpress <parent view id>(child path) [seconds] 3. longpress text/<target text> [seconds] 4. longpress (100,200) [seconds] 2015-08-27: add format2 support 2014-02-17: initial version @param str_arg: auguments """ arg = validateString(str_arg) # if arg.startswith(r'('): # raise ValueError('Bad argument, You may want to use longpress2 with coordinates as auguments.') x = 0 y = 0 seconds = 2000 try: if arg.startswith(r'('): point, sec = arg.split(')') if len(sec) > 0: seconds = int(validateDigit(sec)) x, y = self.__getPointXY(point + ')') if not isinstance(x, int): raise ValueError('bad x type: not int.') elif arg.startswith('id') or arg.startswith('text'): if ' ' in arg: view_id, sec = arg.split(' ') if len(sec) > 0: seconds = int(validateDigit(sec.strip())) else: view_id = arg # get the target view tv = self.__getView(view_id) if tv: if DEBUG: printLog('Found view %s.' % arg, logging.DEBUG) print tv.__tinyStr__() print tv.getPositionAndSize() x, y = tv.getCenter() if not isinstance(x, int): raise ValueError('Bad center coordinate: not int.') else: printLog('Target view %s not found.' % arg, logging.ERROR) self.resultFlag = False return else: raise ValueError('bad argument in longpress().') # perform long press if self.adbc.getSdkVersion() >= 19: printLog(self.threadName + "[running longTouch %s, %s...]" % (x, y)) self.adbc.longTouch(x, y, seconds) # solution for API level > 17: # http://stackoverflow.com/questions/11142843/how-can-i-use-adb-to-send-a-longpress-key-event elif self.adbc.getSdkVersion() > 17: cmd = 'adb shell input touchscreen swipe %s %s %s %s %d' % (x, y, x, y, seconds) printLog(self.threadName + "[running cmd %s...]" % cmd) if call(cmd, shell=True) != 0: printLog("LONGPRESS FAILED: Failed to execute command '%s'." % cmd, logging.ERROR) self.resultFlag = False else: printLog("LONGPRESS FAILED: API < 18 is not supported yet.", logging.ERROR) self.resultFlag = False except Exception, e: printLog(self.threadName + 'LONGPRESS FAILED:%s' % e.message, logging.WARNING) traceback.print_exc() self.resultFlag = False