from contextlib import nullcontext, suppress from io import BytesIO import allure from appium.webdriver.common.touch_action import TouchAction from appium.webdriver.webdriver import WebDriver from PIL import Image from selenium.common.exceptions import ElementNotSelectableException, ElementNotVisibleException, NoSuchElementException, StaleElementReferenceException from waiting import TimeoutExpired from app.src.helpers.waiting_wrapper import wait class ListItem: def __init__(self, driver=None, locator=None, element=None): self.driver = driver self.locator = locator self.__element = element def scroll_to(self): self.driver.execute_script("mobile: scroll", {"element": self.element, "toVisible": True}) @property def element(self): return self.__element or self.driver.find_element(*self.locator) def click(self): self.wait(to_assert=False) self.element.click() def is_enabled(self): return self.element.is_enabled() def wait(self, timeout=5, to_assert=True): cm = nullcontext() if to_assert else suppress(TimeoutExpired) with cm: wait( self.is_visible, timeout=timeout, exceptions=( NoSuchElementException, ElementNotVisibleException, ElementNotSelectableException, StaleElementReferenceException, ), ) @property def label(self): return self.element.get_attribute("label") @property def text(self): return self.element.text @property def height(self): return self.element.size["height"] @property def width(self): return self.element.size["width"] @property def image(self): return Image.open(BytesIO(self.element.screenshot_as_png)).convert("RGB") def is_visible(self): with suppress(NoSuchElementException, ElementNotVisibleException, ElementNotSelectableException): return self.element.is_displayed() return False def swipe_right_long(self): # aka mobile_horizontal_swipe_right size = self.driver.get_window_size() location = self.element.location TouchAction(self.driver).long_press(x=size["width"] * 0.07, y=location["y"] + 30).move_to(x=size["width"] * 0.9, y=location["y"] + 30).release().perform() def swipe_left_long(self): # aka mobile_horizontal_swipe_left size = self.driver.get_window_size() location = self.element.location TouchAction(self.driver).long_press(x=size["width"] * 0.9, y=location["y"] + 30).move_to(x=size["width"] * 0.07, y=location["y"] + 30).release().perform() class ListUIElement: def __init__(self, driver: WebDriver, by_position_locator=None, by_text_locator=None, all_elements_locator=None, name=""): self.driver = driver self._by_position_locator = by_position_locator self._by_text_locator = by_text_locator self.all_elements_locator = all_elements_locator self.name = name def get_item_by_position(self, position): return ListItem(self.driver, (self._by_position_locator[0], self._by_position_locator[1].format(position))) def get_item_by_text(self, text): return ListItem(self.driver, (self._by_text_locator[0], self._by_text_locator[1].format(text))) @allure.step("Selecting item with position {1} from {0}") def select_by_position(self, position, to_assert=True): item = self.get_item_by_position(position) item.wait(to_assert=to_assert) item.click() @allure.step("Selecting item with text {1} from {0}") def select_by_text(self, text): item = self.get_item_by_text(text) item.click() @property def elements(self): return [ListItem(element=item, driver=self.driver) for item in self.driver.find_elements(*self.all_elements_locator)] @property def visible_elements(self): return [e for e in self.elements if e.is_visible()] @property @allure.step("Getting text of all elements of {0}") def texts(self): return [e.text for e in self.elements] def __str__(self): return f"List {self.name}" def __repr__(self): return self.__str__()