def compare_video_image(video, comparison, threshold, image_match, frame_rate_reduction=1, max_scale=2.0): root_dir = os.path.dirname( os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) cap = cv2.VideoCapture(root_dir + '/' + video) template = cv2.imread(root_dir + '/' + comparison) i = 0 percentage = 0.0 while cap.isOpened(): # Capture frame-by-frame ret, frame = cap.read() if ret and i % frame_rate_reduction == 0: found, percentage = __compare(frame, template, threshold, image_match, root_dir, max_scale) if found: cap.release() logger.log(f'Match found in the {i}th frame of the video') return True, percentage elif not ret: break # sleep(frame_rate_reduction) i += 1 cap.release() return False, percentage
def wait_until_attribute(self, attr_type: list, attr: list, seconds=10): start = time.time() if len(attr_type) != len(self.args) or len(attr_type) != len(attr): raise Exception( 'The number of attributes checked must be the same as number of elements in collection' ) threads = list() i = 0 element: Elements for element in self.args: threads.append( threading.Thread(target=self.__wait_until_attribute, args=(element, attr_type[i], attr[i], seconds))) i += 1 for thread in threads: thread.start() for thread in threads: thread.join() if time.time() < start + seconds: logger.log( f"{self.args[0].device_name}: Collection of elements has been found with the correct attributes " f"after {time.time() - start}s") else: compose_error = '' error: str for error in self.__errors: compose_error = compose_error + f'{error} \n' self.__show_error( '{self.args[0].device_name}: Collection of elements has not been found with the correct attributes ' f'after {time.time() - start}s: \n {compose_error}')
def set_app_path(self, path: str): self.__app_path = path if os.path.isabs(self.__app_path): return self else: root_dir = os.path.dirname( os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) self.__app_path = os.path.join(root_dir, path) logger.log(self.__app_path) return self
def set_chrome_driver(self, version=''): mobile_version = version if version == '': if self.udid is None: self.udid = get_device_udid(0) mobile_version = check_chrome_version(self.udid) chrome_driver = chrome.ChromeDriverManager( version=mobile_version).install() logger.log(f'Driver installed in {chrome_driver}', True) self.__desired_capabilities['chromedriverExecutable'] = chrome_driver return self
def compare_images(original: str, comparison: str, threshold=0.9, image_match='', max_scale=2.0, min_scale=0.3): # Read the images from the file global found_image global matched import time start = time.time() matched = 0.0 found_image = False root_dir = os.path.dirname( os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) template = cv2.imread(root_dir + '/' + comparison) image = cv2.imread(root_dir + '/' + original) # loop over the scales of the image threads = list() parts = max_scale / 5.0 if min_scale > parts: min_scale = parts threads.append( threading.Thread(target=__compare, args=(image, template, threshold, image_match, root_dir, parts, min_scale))) threads.append( threading.Thread(target=__compare, args=(image, template, threshold, image_match, root_dir, parts * 2.0, parts))) threads.append( threading.Thread(target=__compare, args=(image, template, threshold, image_match, root_dir, parts * 3.0, parts * 2.0))) threads.append( threading.Thread(target=__compare, args=(image, template, threshold, image_match, root_dir, parts * 4.0, parts * 3.0))) threads.append( threading.Thread(target=__compare, args=(image, template, threshold, image_match, root_dir, parts * 5.0, parts * 4.0))) for thread in threads: thread.start() while not found_image: alive = False for thread in threads: if thread.is_alive(): alive = True if not alive: break logger.log(f'Image Recognition took {time.time() - start}s') return found_image, matched
def click_by_image(self, image: str, threshold=0.9, webview=False): now = datetime.now() current_time = now.strftime("%Y-%m-%d%H%M%S") image_name = f'{self.device_udid}{current_time}.png' self.save_screenshot(image_name) x, y = get_point_match(f'testui-{image_name}', f'{image}', threshold, self.device_name) ta = TouchAction(self.__appium_driver) if webview: y = y + 120 ta.tap(x=x, y=y).perform() logger.log(f'{self.device_name}: element with image {image} clicked') self.__delete_screenshot(image_name)
def start_selenium_driver(desired_caps, url=None, debug=None, browser=None, chrome_options=None, firefox_options=None) -> WebDriver: options = chrome_options if firefox_options is not None: options = firefox_options if options is not None: logger.log("setting options: " + options.to_capabilities().__str__()) logger.log("setting capabilities: " + desired_caps.__str__()) logger.log(f"starting selenium {browser.lower()} driver...") err = None for x in range(2): try: if url is not None: logger.log(f"selenium running on {url}. \n") driver = webdriver.Remote(url, desired_caps, options=options) else: if browser.lower() == 'chrome': driver = webdriver.Chrome( desired_capabilities=desired_caps, options=options) elif browser.lower() == 'firefox': import geckodriver_autoinstaller try: geckodriver_autoinstaller.install() except Exception as error: logger.log_warn("Could not retrieve geckodriver: " + error.__str__()) if "marionette" not in desired_caps: desired_caps["marionette"] = True driver = webdriver.Firefox( firefox_options=options, desired_capabilities=desired_caps) elif browser.lower() == 'safari': driver = webdriver.Safari( desired_capabilities=desired_caps) elif browser.lower() == 'edge': driver = webdriver.Edge(capabilities=desired_caps) elif browser.lower() == 'ie': driver = webdriver.Ie(capabilities=desired_caps) elif browser.lower() == 'opera': driver = webdriver.Opera(desired_capabilities=desired_caps) elif browser.lower() == 'phantomjs': driver = webdriver.PhantomJS( desired_capabilities=desired_caps) else: raise Exception( f"Invalid browser '{browser}'. Please choose one from: chrome,firefox,safari,edge," f"ie,opera,phantomjs") atexit.register(__quit_driver, driver, debug) return driver except Exception as error: err = error raise err
def __local_run(url, desired_caps, use_port, udid, log_file): if url is None: port = use_port bport = use_port + 1 device = 0 if os.getenv('PYTEST_XDIST_WORKER') is not None: device += os.getenv('PYTEST_XDIST_WORKER').split("w")[1] port += int(os.getenv('PYTEST_XDIST_WORKER').split("w")[1]) * 2 desired_caps['chromeDriverPort'] = 8200 + int( os.getenv('PYTEST_XDIST_WORKER').split("w")[1]) desired_caps['systemPort'] = 8300 + int( os.getenv('PYTEST_XDIST_WORKER').split("w")[1]) bport += int(os.getenv('PYTEST_XDIST_WORKER').split("w")[1]) * 2 logger.log( f"running: appium -p {port.__str__()} -bp {bport.__str__()}") if udid is None: desired_caps = __set_android_device(desired_caps, device) logger.log(f'setting device for automation: {desired_caps["udid"]}') root_dir = os.path.dirname( os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/' Path(root_dir + "appium_logs").mkdir(parents=True, exist_ok=True) file_path: str if log_file == 'appium-stdout.log': file = f'appium_logs/testui-{udid}-' + log_file else: file = f'appium_logs/{log_file}' with open(root_dir + file, 'wb') as out: process = subprocess.Popen( ['appium', '-p', port.__str__(), '-bp', bport.__str__()], stdout=out, stderr=subprocess.STDOUT) atexit.register(process.kill) file_path = root_dir + file while True: sleep(0.5) out = open(file_path) text = out.read() if text.__contains__("already be in use") or text.__contains__( "listener started"): out.close() break out.close() return f"http://localhost:{port.__str__()}/wd/hub", desired_caps, process, file_path return url, desired_caps, None
def find_visible(self, seconds=10, return_el_number=False): start = time.time() arg: Elements i = 0 while time.time() < start + seconds or i < 1: for i, arg in enumerate(self.args): if arg.is_visible(log=False): logger.log(f'{self.args[i].device_name}: element ' f'"{self.args[i].locator_type}: {self.args[i].locator}" found visible') if return_el_number: return arg, i else: return arg i += 1 self.__show_error( f"{self.args[0].device_name}: No element within the collection was found visible " f"after {time.time() - start}s:")
def start_selenium_driver(desired_caps, url=None, debug=None, browser=None, chrome_options=None, firefox_options=None): options = chrome_options if firefox_options is not None: options = firefox_options if options is not None: logger.log("setting options: " + options.to_capabilities().__str__()) logger.log("setting capabilities: " + desired_caps.__str__()) logger.log(f"starting selenium {browser.lower()} driver...") err = None for x in range(2): try: if url is not None: driver = webdriver.Remote(url, desired_caps, options=options) else: if browser is None: driver = webdriver.Chrome( desired_capabilities=desired_caps, chrome_options=options) elif browser.lower() == 'firefox': driver = webdriver.Firefox( firefox_options=options, desired_capabilities=desired_caps) elif browser.lower() == 'safari': driver = webdriver.Safari( desired_capabilities=desired_caps) elif browser.lower() == 'edge': driver = webdriver.Edge(capabilities=desired_caps) elif browser.lower() == 'ie': driver = webdriver.Ie(capabilities=desired_caps) elif browser.lower() == 'opera': driver = webdriver.Opera(desired_capabilities=desired_caps) elif browser.lower() == 'phantomjs': driver = webdriver.PhantomJS( desired_capabilities=desired_caps) else: driver = webdriver.Chrome() atexit.register(__quit_driver, driver, debug) logger.log(f"selenium running on {url}. \n") return driver except Exception as error: err = error raise err
def wait_until_all_visible(self, seconds=10.0, log=True): start = time.time() threads = list() for arg in self.args: threads.append(threading.Thread(target=arg.wait_until_visible, args=(seconds, log))) for thread in threads: thread.start() for thread in threads: thread.join() if time.time() < start + seconds: logger.log( f"{self.args[0].device_name}: Collection of elements has been found after {time.time() - start}s" ) else: compose_error = '' error: str for error in self.__errors: compose_error = compose_error + f'{error} \n' self.__show_error( f'{self.args[0].device_name}: Collection of elements has not been found ' f'after {time.time() - start}s: \n {compose_error}')
def switch_to_context(self, context=0, last=False): if last: context = len(self.__appium_driver.contexts) - 1 try: if len(self.__appium_driver.contexts) == 1: logger.log( f'{self.device_name}: There is only one context: {self.__appium_driver.contexts[context]}' ) elif context >= len(self.__appium_driver.contexts): logger.log_warn( f'{self.device_name}: Cannot switch to context {context}: there are just ' f'{len(self.__appium_driver.contexts)} contexts') self.__appium_driver.execute( 'switchToContext', {'name': self.__appium_driver.contexts[context]}) logger.log( f'{self.device_name}: Switched to context: {self.__appium_driver.contexts[context]}' ) except Exception as err: if self.__soft_assert: logger.log_error(err) else: raise err return self
def start_driver(desired_caps, url, debug, port, udid, log_file): lock = threading.Lock() lock.acquire() logger.log("setting capabilities: " + desired_caps.__str__()) logger.log("starting appium driver...") process = None if desired_caps['platformName'].lower().__contains__('android'): url, desired_caps, process, file = __local_run(url, desired_caps, port, udid, log_file) else: url, desired_caps, file = __local_run_ios(url, desired_caps, port, udid, log_file) err = None for x in range(2): try: driver = Remote(url, desired_caps) atexit.register(__quit_driver, driver, debug) logger.log(f"appium running on {url}. \n") lock.release() return driver, process, file except Exception as error: err = error lock.release() raise err
def image_comparison_size(self): size_image = size(self.__comparison) logger.log(f'The size of the image is {size_image}') return Dimensions(size_image[0], size_image[1])
def image_original_size(self): size_image = size(self.__original) logger.log(f'The size of the image is {size_image}') return Dimensions(size_image[0], size_image[1])
def click(self, x, y): ta = TouchAction(self.__appium_driver) ta.tap(x=x, y=y).perform() logger.log(f'Clicked over "x={x}: y={y}"')
def navigate_to(self, url): self.get_driver().get(url) logger.log(f'{self.device_name}: Navigating to: {url}')
def __put_log(self, message): if self.logger is not None: if self.logger == 'behave': logger.log(f'{message} \n') else: logger.log(message)