From 295f0e71d813267c73a8dd80a9bed7dfa7f13ebe Mon Sep 17 00:00:00 2001 From: hassineabd Date: Tue, 16 Jul 2024 22:27:20 +0200 Subject: [PATCH 1/2] add image strategy add image to doc add image strategy --- AppiumLibrary/__init__.py | 2 ++ AppiumLibrary/keywords/_element.py | 13 ++++++++----- AppiumLibrary/locators/elementfinder.py | 24 +++++++++++++++++++++--- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/AppiumLibrary/__init__.py b/AppiumLibrary/__init__.py index a814eae7..df78e1bd 100644 --- a/AppiumLibrary/__init__.py +++ b/AppiumLibrary/__init__.py @@ -56,7 +56,9 @@ class AppiumLibrary( | id | Click Element `|` id=my_element | Matches by @resource-id attribute | | | accessibility_id | Click Element `|` accessibility_id=button3 | Accessibility options utilize. | | | xpath | Click Element `|` xpath=//UIATableView/UIATableCell/UIAButton | Matches with arbitrary XPath | | + | image | Click Element `|` image=icon1.png | Matches by image | | | class | Click Element `|` class=UIAPickerWheel | Matches by class | | + | image | Click Element `|` image=icon.png | Matches by image | | | android | Click Element `|` android=UiSelector().description('Apps') | Matches by Android UI Automator | | | ios | Click Element `|` ios=.buttons().withName('Apps') | Matches by iOS UI Automation | | | predicate | Click Element `|` predicate=name=="login" | Matches by iOS Predicate | Check PR: #196 | diff --git a/AppiumLibrary/keywords/_element.py b/AppiumLibrary/keywords/_element.py index c20fcfc0..ebc09f41 100644 --- a/AppiumLibrary/keywords/_element.py +++ b/AppiumLibrary/keywords/_element.py @@ -41,7 +41,7 @@ def click_element(self, locator): """ self._info("Clicking element '%s'." % locator) self._element_find(locator, True, True).click() - + def click_button(self, index_or_name): """*DEPRECATED!!* in selenium v4, use `Click Element` keyword. Click button @@ -638,7 +638,10 @@ def _element_find(self, locator, first_only, required, tag=None): _locator = locator elements = self._element_finder.find(application, _locator, tag) if required and len(elements) == 0: - raise ValueError("Element locator '" + locator + "' did not match any elements.") + if self._element_finder._is_image_locator(locator) : + raise ValueError("Image at '" + locator + "' did not match any elements.") + else: + raise ValueError("Element locator '" + locator + "' did not match any elements.") if first_only: if len(elements) == 0: return None return elements[0] @@ -647,9 +650,9 @@ def _element_find(self, locator, first_only, required, tag=None): return locator else: elements = [locator] - # do some other stuff here like deal with list of webelements - # ... or raise locator/element specific error if required - return elements + # do some other stuff here like deal with list of webelements + # ... or raise locator/element specific error if required + return elements def _element_find_by_text(self, text, exact_match=False): if self._get_platform() == 'ios': diff --git a/AppiumLibrary/locators/elementfinder.py b/AppiumLibrary/locators/elementfinder.py index 16df8c1a..26d35424 100644 --- a/AppiumLibrary/locators/elementfinder.py +++ b/AppiumLibrary/locators/elementfinder.py @@ -3,7 +3,8 @@ from AppiumLibrary import utils from appium.webdriver.common.appiumby import AppiumBy from robot.api import logger - +import base64 +import os class ElementFinder(object): @@ -14,6 +15,7 @@ def __init__(self): 'name': self._find_by_name, 'xpath': self._find_by_xpath, 'class': self._find_by_class_name, + 'image': self._find_by_image, 'accessibility_id': self._find_element_by_accessibility_id, 'android': self._find_by_android, 'viewtag': self._find_by_android_viewtag, @@ -30,15 +32,18 @@ def __init__(self): def find(self, application, locator, tag=None): assert application is not None assert locator is not None and len(locator) > 0 - (prefix, criteria) = self._parse_locator(locator) - prefix = 'default' if prefix is None else prefix + if prefix is None: + prefix = 'image' if (self._is_image_locator(locator)) else 'default' strategy = self._strategies.get(prefix) if strategy is None: raise ValueError("Element locator with prefix '" + prefix + "' is not supported") (tag, constraints) = self._get_tag_and_constraints(tag) return strategy(application, criteria, tag, constraints) + def _is_image_locator(self, locator): + return isinstance(locator, str) and (locator.endswith(('.png', '.jpg', '.jpeg'))) + # Strategy routines, private def _find_by_identifier(self, application, criteria, tag, constraints): @@ -97,6 +102,19 @@ def _find_by_class_name(self, application, criteria, tag, constraints): application.find_elements(by=AppiumBy.CLASS_NAME, value=criteria), tag, constraints) + def _find_by_image(self, application, criteria, tag, constraints): + return self._filter_elements( + application.find_elements(by=AppiumBy.IMAGE, value=self._encode_image_to_base64(criteria)), + tag, constraints) + + def _encode_image_to_base64(self, image_path): + if not os.path.exists(image_path): + raise FileNotFoundError(f"Image file does not exist: {image_path}") + with open(image_path, 'rb') as image_file: + image_data = image_file.read() + image_base64 = base64.b64encode(image_data).decode('utf-8') + return image_base64 + def _find_element_by_accessibility_id(self, application, criteria, tag, constraints): return self._filter_elements( application.find_elements(by=AppiumBy.ACCESSIBILITY_ID, value=criteria), From 84c61e5a2fbdd12e42a0cd22c9b6568b646fa293 Mon Sep 17 00:00:00 2001 From: hassineabd Date: Wed, 17 Jul 2024 17:39:49 +0200 Subject: [PATCH 2/2] Remove duplicate comment line --- AppiumLibrary/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/AppiumLibrary/__init__.py b/AppiumLibrary/__init__.py index df78e1bd..d16ff233 100644 --- a/AppiumLibrary/__init__.py +++ b/AppiumLibrary/__init__.py @@ -56,7 +56,6 @@ class AppiumLibrary( | id | Click Element `|` id=my_element | Matches by @resource-id attribute | | | accessibility_id | Click Element `|` accessibility_id=button3 | Accessibility options utilize. | | | xpath | Click Element `|` xpath=//UIATableView/UIATableCell/UIAButton | Matches with arbitrary XPath | | - | image | Click Element `|` image=icon1.png | Matches by image | | | class | Click Element `|` class=UIAPickerWheel | Matches by class | | | image | Click Element `|` image=icon.png | Matches by image | | | android | Click Element `|` android=UiSelector().description('Apps') | Matches by Android UI Automator | |