Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions tests/appium_tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import time

import pytest

from tests.screens.landing import LandingScreen
from testui.support import logger
from testui.support.appium_driver import NewDriver
from testui.support.testui_driver import TestUIDriver
Expand All @@ -20,9 +21,17 @@ def selenium_driver(self):
driver.quit()

@pytest.mark.signup
def test_sign_up_flow(self, selenium_driver: TestUIDriver):
def test_screenshot_methods(self, selenium_driver: TestUIDriver):
logger.log_test_name("T92701: Create an account")
selenium_driver.navigate_to("https://google.com")
landing_page = LandingScreen(selenium_driver)
landing_page.i_am_in_mobile_landing_screen()
selenium_driver.get_dimensions()
selenium_driver.navigate_to(
"https://github.com/testdevlab/Py-TestUI#image-recognition"
)
selenium_driver.start_recording_screen()
time.sleep(1)
selenium_driver.stop_recording_and_compare("./resources/comp.png", fps_reduction=30, keep_image_as="v_image.png")
selenium_driver.find_image_match(
"./resources/comp.png", 0.9, True, image_match="image.png"
)
selenium_driver.click_by_image("./resources/comp.png")
selenium_driver.raise_errors()
2 changes: 1 addition & 1 deletion tests/screens/landing.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ def i_am_in_mobile_landing_screen(self):
self.__log_in_button_2.wait_until_visible()

def i_am_in_google_play_landing_screen(self):
self.__google_play_screen.wait_until_visible().get_text()
self.__google_play_screen.wait_until_visible().screenshot()
17 changes: 13 additions & 4 deletions tests/selenium_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class TestStringMethods:
def selenium_driver(self):
options = Options()
options.add_argument("disable-user-media-security")
options.add_argument("headless")
driver = (
NewDriver()
.set_logger()
Expand All @@ -23,15 +24,23 @@ def selenium_driver(self):
driver.quit()

@pytest.mark.signup
def test_sign_up_flow(self, selenium_driver: TestUIDriver):
def test_template_matching(self, selenium_driver: TestUIDriver):
logger.log_test_name("T92701: Create an account")
selenium_driver.navigate_to("https://google.com")
landing_page = LandingScreen(selenium_driver)
landing_page.i_am_in_landing_screen()
selenium_driver.get_driver().set_window_size(1000, 1100)
selenium_driver.navigate_to(
"https://github.com/testdevlab/Py-TestUI#image-recognition"
)
selenium_driver.find_image_match(
"resources/comp.png", 0.9, True, image_match="image.png"
)
selenium_driver.raise_errors()

@pytest.mark.signup
def test_get_dimensions(self, selenium_driver: TestUIDriver):
logger.log_test_name("T92701: Create an account")
selenium_driver.get_driver().set_window_size(1000, 1100)
selenium_driver.navigate_to(
"https://github.com/testdevlab/Py-TestUI#image-recognition"
)
selenium_driver.get_dimensions()
selenium_driver.raise_errors()
86 changes: 40 additions & 46 deletions testui/elements/testui_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from os import path
from typing import List

from appium.webdriver.common.appiumby import AppiumBy
from appium.webdriver.common.touch_action import TouchAction
from appium.webdriver.webelement import WebElement
from selenium.webdriver import ActionChains
Expand All @@ -15,6 +16,7 @@
from testui.support.helpers import error_with_traceback
from testui.support.testui_images import Dimensions, ImageRecognition


def testui_error(driver, exception: str) -> None:
config = driver.configuration

Expand Down Expand Up @@ -118,21 +120,24 @@ def __find_by_element(self) -> WebElement:
return self.driver.find_element(By.XPATH, self.locator)

if self.locator_type == "android_id_match":
return self.driver.find_element_by_android_uiautomator(
f'resourceIdMatches("{self.locator}")'
)
return self.driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,
f"resourceIdMatches(\"{self.locator}\")"
)

if self.locator_type == "accessibility":
return self.driver.find_element_by_accessibility_id(self.locator)
return self.driver.find_element(
AppiumBy.ACCESSIBILITY_ID, self.locator)

if self.locator_type == "uiautomator":
return self.driver.find_element_by_android_uiautomator(self.locator)
return self.driver.find_element(
AppiumBy.ANDROID_UIAUTOMATOR, self.locator)

if self.locator_type == "classChain":
return self.driver.find_element_by_ios_class_chain(self.locator)
return self.driver.find_element(
AppiumBy.IOS_CLASS_CHAIN, self.locator)

if self.locator_type == "predicate":
return self.driver.find_element_by_ios_predicate(self.locator)
return self.driver.find_element(AppiumBy.IOS_PREDICATE, self.locator)

raise ElementException(f"locator not supported: {self.locator_type}")

Expand All @@ -157,23 +162,24 @@ def __find_by_collection(self) -> List[WebElement]:
return self.driver.find_elements(By.XPATH, self.locator)

if self.locator_type == "android_id_match":
return self.driver.find_elements_by_android_uiautomator(
f'resourceIdMatches("{self.locator}")'
)
return self.driver.find_elements(AppiumBy.ANDROID_UIAUTOMATOR,
f'resourceIdMatches("{self.locator}")'
)

if self.locator_type == "accessibility":
return self.driver.find_elements_by_accessibility_id(self.locator)
return self.driver.find_elements(AppiumBy.ACCESSIBILITY_ID, self.locator)

if self.locator_type == "uiautomator":
return self.driver.find_elements_by_android_uiautomator(
return self.driver.find_elements(
AppiumBy.ANDROID_UIAUTOMATOR,
self.locator
)

if self.locator_type == "classChain":
return self.driver.find_elements_by_ios_class_chain(self.locator)
return self.driver.find_elements(AppiumBy.IOS_CLASS_CHAIN, self.locator)

if self.locator_type == "predicate":
return self.driver.find_elements_by_ios_predicate(self.locator)
return self.driver.find_elements(AppiumBy.IOS_PREDICATE, self.locator)

raise ElementException(f"locator not supported: {self.locator_type}")

Expand Down Expand Up @@ -496,26 +502,24 @@ def screenshot(self, image_name="cropped_image.png"):
:return:
"""
self.wait_until_visible()
self.testui_driver.save_screenshot(f"{self.device_name}-crop_image.png")
dimensions = self.dimensions
top_left = self.location
ImageRecognition(
f"testui-{self.device_name}-crop_image.png"
).crop_original_image(
top_left.x + dimensions.x // 2,
top_left.y + dimensions.y // 2,
dimensions.x,
dimensions.y,
image_name,
)

root_dir = self.testui_driver.configuration.screenshot_path
if not root_dir:
root_dir = path.dirname(
path.dirname(path.dirname(path.abspath(__file__)))
try:
self.get_element().screenshot(image_name)
except Exception:
path_img = self.testui_driver.save_screenshot(f"{self.device_name}-crop_image.png")
dimensions = self.dimensions
top_left = self.location
logger.log_debug(f'crop dimensions (x,y,w,h):({top_left.x},{top_left.y},{dimensions.x},{dimensions.y})')
ImageRecognition(
path_img
).crop_original_image(
(top_left.x + dimensions.x // 2),
(top_left.y + dimensions.y // 2),
dimensions.x,
dimensions.y,
image_name,
)

os.remove(root_dir + f"/testui-{self.device_name}-crop_image.png")
os.remove(path_img)

return self

Expand Down Expand Up @@ -556,13 +560,8 @@ def find_image_match(
f"{self.device_name}: The images compared matched. "
f"Threshold={threshold}, matched = {precision}"
)
root_dir = (
os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
+ "/"
)
os.remove(root_dir + self.device_name + ".png")
root_dir = self.testui_driver.configuration.screenshot_path
os.remove(os.path.join(root_dir, self.device_name + ".png"))

return self

Expand Down Expand Up @@ -596,13 +595,8 @@ def is_image_match(
return False
if found and is_not:
return False
root_dir = (
os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
+ "/"
)
os.remove(root_dir + self.device_name + ".png")
root_dir = self.testui_driver.configuration.screenshot_path
os.remove(os.path.join(root_dir, self.device_name + ".png"))

return True

Expand Down
45 changes: 38 additions & 7 deletions testui/support/api_support.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import requests
import sys
import platform

from testui.support import logger
import xml.etree.ElementTree as ET


def get_chrome_version(version: str):
Expand All @@ -8,11 +13,37 @@ def get_chrome_version(version: str):
# TODO: it is not pulling the version. I just updated all phones to
# latest chrome
chrome_version = ""
for text in r.text.split(f"{version}."):
if text.__contains__("/chromedriver_mac64.zip"):
new_chrome_version = (
f'{version}.{text.split("/chromedriver_mac64.zip")[0]}'
)
if len(new_chrome_version) < 17:
chrome_version = new_chrome_version
mytree = ET.ElementTree(ET.fromstring(r.text))
root = mytree.getroot()
for child in root:
for child2 in child:
if not child2.text.__contains__(f"{version}."):
continue
if chrome_name() == "arm64" and \
child2.text.__contains__("m1") or \
child2.text.__contains__("mac_arm64"):
chrome_version = child2.text.split("/")[0]
elif child2.text.__contains__(chrome_name()):
chrome_version = child2.text.split("/")[0]

return chrome_version


def chrome_name():
pl = sys.platform
if pl == "linux" or pl == "linux2":
return "/chromedriver_linux64.zip"
elif pl == "darwin":
if os_architecture() == 64:
return "arm64"
else:
return "/chromedriver_mac64.zip"
elif pl == "win32":
return "/chromedriver_win32.zip"


def os_architecture():
if platform.machine().endswith("64"):
return 64
else:
return 32
6 changes: 3 additions & 3 deletions testui/support/appium_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ def set_app_path(self, path: str):
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__)))
)
root_dir = self.configuration.screenshot_path
self.__app_path = os.path.join(root_dir, path)
logger.log(self.__app_path)
return self
Expand Down Expand Up @@ -158,6 +156,7 @@ def set_chrome_driver(self, version="") -> "NewDriver":
if self.udid is None:
self.udid = get_device_udid(0)
mobile_version = check_chrome_version(self.udid)
logger.log(f"Installing chromedriver version: {mobile_version}")
chrome_driver = chrome.ChromeDriverManager(
version=mobile_version
).install()
Expand Down Expand Up @@ -504,6 +503,7 @@ def get_device_udid(number: int):
if len(devices) == 0:
raise Exception("There are 0 devices connected to the computer!")
if len(devices) > number:
logger.log(f"Setting device: {devices[number].get_serial_no()}")
return devices[number].get_serial_no()
else:
new_number = number - (number // len(devices)) * len(devices)
Expand Down
37 changes: 19 additions & 18 deletions testui/support/testui_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def find_image_match(
image_name = f"{self.device_udid}{current_time}.png"
image_path = self.save_screenshot(image_name)
found, p = ImageRecognition(
image_path, comparison, threshold, self.device_name
image_path, comparison, threshold, self.device_name, self.configuration.screenshot_path
).compare(image_match)
if assertion and not found and not not_found:
exception = self.new_error_message(
Expand All @@ -164,26 +164,27 @@ 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)
im_path = self.save_screenshot(image_name)
x, y = get_point_match(
f"testui-{image_name}", f"{image}", threshold, self.device_name
im_path, 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)
logger.log(f"{self.device_name}: element with image {image} clicked on point ({x},{y})")
self.__delete_screenshot(im_path)

def get_dimensions(self):
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)
path_s = self.save_screenshot(image_name)
dimensions = ImageRecognition(
f"testui-{image_name}"
original=path_s
).image_original_size()
self.__delete_screenshot(image_name)
logger.log(f"Deleting screenshot: {path_s}")
self.__delete_screenshot(path_s)
return dimensions

def click(self, x, y):
Expand Down Expand Up @@ -220,10 +221,7 @@ def save_screenshot(self, image_name=""):

@classmethod
def __delete_screenshot(cls, image_name):
root_dir = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
os.remove(root_dir + f"/testui-{image_name}")
os.remove(image_name)

def get_driver(self) -> WebDriver:
driver = self.__appium_driver
Expand Down Expand Up @@ -277,10 +275,9 @@ def start_recording_screen(self):
def stop_recording_screen(self, file_name="testui-video.mp4"):
file = self.get_driver().stop_recording_screen()
decoded_string = base64.b64decode(file)
root_dir = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
with open(root_dir + f"/{file_name}", "wb") as wfile:
root_dir = self.configuration.screenshot_path
logger.log(f"Recording stopped in {os.path.join(root_dir, file_name)}")
with open(os.path.join(root_dir, file_name), "wb") as wfile:
wfile.write(decoded_string)

def stop_recording_and_compare(
Expand All @@ -299,11 +296,15 @@ def stop_recording_and_compare(
root_dir = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
if self.__configuration.screenshot_path != "":
root_dir = self.__configuration.screenshot_path
found = ImageRecognition(
video_name, comparison, threshold, device_name=self.device_name
video_name, comparison, threshold,
device_name=self.device_name,
path=root_dir
).compare_video(keep_image_as, frame_rate_reduction=fps_reduction)

os.remove(root_dir + f"/{video_name}")
os.remove(os.path.join(root_dir, video_name))
if not found and not not_found:
if assertion:
raise Exception(
Expand Down
Loading