def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.categories_general = CategoriesGeneral(self.driver) self.category_detail = CategoryDetail(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver)
def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.period_filter = PeriodFilter(self.driver) self.rs = Resolutions(self.driver) self.timeline_general = TimelineGeneral(self.driver) self.transaction_detail = TransactionDetail(self.driver)
def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver) self.wallets_general = WalletsGeneral(self.driver) self.wallet_detail = WalletDetail(self.driver) self.wallets_overview = WalletOverview(self.driver)
def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.budget_detail = BudgetDetail(self.driver) self.budgets_general = BudgetsGeneral(self.driver) self.budget_overview = BudgetOverview(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver) self.transaction_detail = TransactionDetail(self.driver)
class ElementWrapper: def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.log = logging.getLogger('log') self.rs = Resolutions(self.driver) def get_by_type(self, locator): """ :param locator: str :return: selecting method """ if str(locator).startswith("//") or str(locator).startswith("(//"): return MobileBy.XPATH elif str(locator).startswith("com.android") or str(locator).startswith("android:id"): return MobileBy.ID elif str(locator).startswith('label'): return MobileBy.IOS_PREDICATE elif str(locator).startswith('**'): return MobileBy.IOS_CLASS_CHAIN else: return MobileBy.ACCESSIBILITY_ID def get_element(self, locator): """ :param locator: str :return: element """ by_type = self.get_by_type(locator) element = self.driver.find_element(by_type, locator) return element def get_elements(self, locator): """ :param locator: str :return: list of elements """ by_type = self.get_by_type(locator) element_list = self.driver.find_elements(by_type, locator) if len(element_list) < 1 or element_list is None: self.log.error(f"element_list {locator} NOT found") return element_list def is_element_present(self, locator): """ Checking if element is present in DOM :param locator: str :return: bool """ try: element = self.get_element(locator) if element is not None: self.log.info(f"element {locator} found") return True else: return False except NoSuchElementException: self.log.info(f"element {locator} NOT found") return False def are_elements_present(self, locator): """Checking if elements are present in DOM :param locator: str :return: bool """ element_list = self.get_elements(locator) if len(element_list) > 0: self.log.info(f"element_list {locator} found") return True else: self.log.info(f"element list {locator} NOT found") return False def get_text_of_element(self, locator): """ Getting text of selected element :param locator: str :return: str """ try: element = self.get_element(locator) return element.text except NoSuchElementException: self.log.info(f"element {locator} NOT found, can't get the text of element") def get_text_of_elements(self, locator): """ Getting texts of selected elements :param locator: str :return: list of str """ try: element_list = self.get_elements(locator) texts = [] for i in element_list: texts.append(i.text) return texts except NoSuchElementException: self.log.info(f"elements {locator} NOT found, can't get the text of elements") def wait_till_element_is_visible(self, locator, timeout_seconds): """ Methods waits till element is visible in DOM :param locator: str :param timeout_seconds: int """ timeout = time.time() + timeout_seconds visibility_of_element = self.is_element_present(locator) while visibility_of_element is False: time.sleep(0.1) visibility_of_element = self.is_element_present(locator) if time.time() > timeout: raise NoSuchElementException(f"element {locator} NOT found") def wait_till_element_is_not_visible(self, locator, timeout_seconds): """ Method waits till element is no more visible in DOM :param locator: str :param timeout_seconds: int """ timeout = time.time() + timeout_seconds visibility_of_element = self.is_element_present(locator) while visibility_of_element is True: time.sleep(0.1) visibility_of_element = self.is_element_present(locator) if time.time() > timeout: raise NoSuchElementException(f"element {locator} dont't disappeared") def tap_element(self, locator): """ Method taps on element :param locator: str """ self.action.tap(self.get_element(locator)).perform() def wait_and_tap_element(self, locator, timeout_seconds): """ Method waits till element is visible in DOM and taps on it :param locator: str :param timeout_seconds: int """ self.wait_till_element_is_visible(locator, timeout_seconds) self.action.tap(self.get_element(locator)).perform() def get_attribute(self, locator, attribute): """ Getting attribute of selected element :param locator: str :param attribute: str :return: str """ byType = self.get_by_type(locator) return self.driver.find_element(byType, locator).get_attribute(attribute) def get_attributes(self, locator, attribute): """ Getting attribute of selected elements :param locator: str :param attribute: str :return: list of str """ by_type = self.get_by_type(locator) element_list = self.driver.find_elements(by_type, locator) attributes = [] for i in element_list: attributes.append(i.get_attribute(attribute)) return attributes def swipe_if_element_not_present(self, locator): """ If the element is not present in DOM, it will swipe to it :param locator: str """ element_present = self.is_element_present(locator) timeout = time.time() + 30 while element_present is False: res = self.rs.get_resolution() if PLATFORM == "Android": self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["element_not_present_swipe_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["element_not_present_swipe_y_end"]) \ .release().perform() else: self.driver.execute_script("mobile: dragFromToForDuration", {"duration": "0.1", "fromX": self.rs.all_resolutions[f"{res}"]["x"], "fromY": self.rs.all_resolutions[f"{res}"][ "element_not_present_swipe_y_start"], "toX": self.rs.all_resolutions[f"{res}"]["x"], "toY": self.rs.all_resolutions[f"{res}"][ "element_not_present_swipe_y_end"]}) element_present = self.is_element_present(locator) if time.time() > timeout: break
class WalletsActions: def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver) self.wallets_general = WalletsGeneral(self.driver) self.wallet_detail = WalletDetail(self.driver) self.wallets_overview = WalletOverview(self.driver) def create_wallet(self, name, amount, currency, categories): """ Opens wallet create screen and sets requested attributes :param name: str or None :param amount: str or None :param currency: str or None :param categories: str or int or None """ self.wallets_general.go_to_wallets() self.open_wallet_create_screen() self.wallet_detail.set_name(name) if amount is not None: self.wallet_detail.set_amount(amount) if currency is not None: self.wallet_detail.set_currency(currency) if categories is not None: self.wallet_detail.set_categories(categories) def open_wallet_create_screen(self): """Opens wallet create screen""" self.ew.wait_till_element_is_visible( self.wallets_general.WALLETS_ANIMATED_HEADER, 10) if PLATFORM == "Android": add_button_visible = self.ew.is_element_present( self.wallets_general.ADD_WALLET_BUTTON) while add_button_visible is False: res = self.rs.get_resolution() self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["wallets_overview_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["wallets_overview_y_end"]) \ .release().perform() add_button_visible = self.ew.is_element_present( self.wallets_general.ADD_WALLET_BUTTON) else: add_button_visible = self.ew.get_attribute( self.wallets_general.ADD_WALLET_BUTTON, "visible") while add_button_visible == "false": res = self.rs.get_resolution() self.driver.execute_script( "mobile: dragFromToForDuration", { "duration": "0.1", "fromX": self.rs.all_resolutions[f"{res}"]["x"], "fromY": self.rs.all_resolutions[f"{res}"] ["wallets_overview_y_start"], "toX": self.rs.all_resolutions[f"{res}"]["x"], "toY": self.rs.all_resolutions[f"{res}"] ["wallets_overview_y_end"] }) add_button_visible = self.ew.get_attribute( self.wallets_general.ADD_WALLET_BUTTON, "visible") self.ew.wait_and_tap_element(self.wallets_general.ADD_WALLET_BUTTON, 5) self.ew.wait_till_element_is_visible(self.wallet_detail.WALLET_HEADER, 10) def save_wallet(self): """Clicks on save wallet button""" if self.driver.is_keyboard_shown(): self.driver.hide_keyboard() self.ew.wait_and_tap_element(self.wallet_detail.SAVE_WALLET_BUTTON, 10) self.ew.wait_till_element_is_not_visible( self.wallet_detail.SAVE_WALLET_BUTTON, 10) def open_wallet(self): """Opens existing wallet""" self.wallets_general.go_to_wallets() self.ew.wait_till_element_is_visible( self.wallets_general.WALLETS_ANIMATED_HEADER, 10) self.ew.wait_and_tap_element(self.wallets_general.WALLET_ITEM, 5) self.ew.wait_and_tap_element(self.wallets_overview.EDIT_BUTTON, 5) self.ew.wait_till_element_is_visible(self.wallet_detail.WALLET_HEADER, 5) def edit_wallet(self, name, amount, currency, categories): """Changes requested attributes of wallet :param name: str or None :param amount: str or None :param currency: str or None :param categories: str or int or None """ self.open_wallet() if name is not None: if PLATFORM == "Android": self.ew.get_element(self.wallet_detail.NAME_INPUT).clear() else: self.ew.get_element( self.wallet_detail.SELECTED_NAME_IOS).clear() self.wallet_detail.set_name(name) if amount is not None: self.ew.wait_and_tap_element(self.wallet_detail.AMOUNT_INPUT, 5) self.ew.wait_till_element_is_visible( self.wallet_detail.NUMPAD_CLEAR, 10) for i in range(6): self.ew.tap_element(self.wallet_detail.NUMPAD_CLEAR) self.ew.tap_element(self.wallet_detail.NUMPAD_BACKDROP) self.wallet_detail.set_amount(amount) if currency is not None: self.wallet_detail.set_currency(currency) if categories is not None: self.wallet_detail.set_categories(categories) def delete_wallet(self): """Deletes wallet from wallet detail""" self.ew.wait_and_tap_element(self.wallet_detail.TRASH_ICON, 10) self.ew.wait_and_tap_element(self.wallet_detail.DELETE_BUTTON, 10) self.ew.wait_till_element_is_visible( self.wallets_general.WALLETS_ANIMATED_HEADER, 10) def invite_user_to_wallet(self): """Opens wallet and invitation screen""" self.open_wallet() self.wallet_detail.invite_user()
class BudgetDetail(): # OTHER BUDGET_HEADER = "Budget Header" SAVE_BUDGET_BUTTON = "Save Budget Button" TRASH_ICON = "Trash Icon" DELETE_BUTTON = "Delete" if PLATFORM == "Android": DISCARD_CHANGES = "android:id/button1" else: DISCARD_CHANGES = "Discard changes" # NAME NAME_INPUT = "Name Input" SELECTED_NAME_IOS = '**/XCUIElementTypeTextField[`label == "Name Input"`]' # AMOUNT if PLATFORM == "Android": AMOUNT_INPUT = "Amount Input" else: AMOUNT_INPUT = '**/XCUIElementTypeOther[`label == "Amount Input"`][2]' SELECTED_AMOUNT = "Currency Input" # KEYBOARD KEYBOARD = {"0": "Numpad 0", "1": "Numpad 1", "2": "Numpad 2", "3": "Numpad 3", "4": "Numpad 4", "5": "Numpad 5", "6": "Numpad 6", "7": "Numpad 7", "8": "Numpad 8", "9": "Numpad 9", ".": "Numpad Decimal Point", ",": "Numpad Decimal Point"} NUMPAD_BACKDROP = "Numpad Backdrop" NUMPAD_CLEAR = "Numpad Clear" # CURRENCY CURRENCY = "Currency" if PLATFORM == "Android": SELECTED_CURRENCY = '//android.view.ViewGroup[@content-desc="Currency"]/android.view.ViewGroup/android.view.ViewGroup/android.widget.EditText' CURRENCY_PICKER = "Select currency Picker" else: SELECTED_CURRENCY = '**/XCUIElementTypeOther[`label == "Currency"`][1]' CURRENCY_PICKER = 'label == "Select currency"' # WALLETS if PLATFORM == "Android": WALLET_ITEM = '//android.view.ViewGroup[@content-desc="Select Wallets Picker"]/android.widget.ScrollView/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup' WALLETS = "Wallets" else: WALLET_ITEM = "Wallet Item" WALLETS = 'label == "Wallets"' WALLET_PICKER = "Select Wallets Picker" SELECTED_WALLETS_ANDROID = '//android.view.ViewGroup[@content-desc="Wallets"]/android.view.ViewGroup/android.widget.TextView[2]' SELECTED_WALLETS_ANDROID_2 = '//android.view.ViewGroup[@content-desc="Wallets"]/android.widget.TextView[2]' # CATEGORIES CATEGORIES = "Categories" HEADER_BUDGET_FOR = "Header Budget For" SELECT_ALL_CHECKED = "Select All-checked" SELECT_ALL_UNCHECKED = "Select All-unchecked" SELECT_ALL_PART = "Select All-part" if PLATFORM == "Android": CATEGORIES = "Categories" CATEGORY_ITEM = '//android.view.ViewGroup[@content-desc="Category Item"]/android.view.ViewGroup' SELECTED_CATEGORIES_ANDROID = '//android.view.ViewGroup[@content-desc="Categories"]/android.widget.TextView[2]' SELECTED_CATEGORIES_ANDROID_2 = '//android.view.ViewGroup[@content-desc="Categories"]/android.view.ViewGroup/android.widget.TextView[2]' else: CATEGORY_ITEM = 'label == "Category Item"' CATEGORIES = 'label == "Categories"' BACK_BUTTON = "Back Button" # RECURRENCE if PLATFORM == "Android": RECURRENCE = "Recurrence" SELECTED_RECURRENCE_ANDROID = '//android.view.ViewGroup[@content-desc="Recurrence"]/android.widget.TextView[2]' SELECTED_RECURRENCE_ANDROID_EDIT = '//android.view.ViewGroup[@content-desc="Recurrence"]/android.view.ViewGroup/android.widget.TextView[2]' else: RECURRENCE = 'label == "Recurrence"' RECURRENCE_PICKER = "Recurrence Picker" # START DATE if PLATFORM == "Android": START_DATE = "Start Date" else: START_DATE = 'label == "Start Date"' CALENDAR_PICKER = "Select date Picker" # END DATE if PLATFORM == "Android": END_DATE = "End Date" else: END_DATE = 'label == "End Date"' def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver) self.transaction_detail = TransactionDetail(self.driver) def set_name(self, name): """ Insert name into name input :param name: str """ if name == "random": name = ''.join([random.choice(string.ascii_lowercase + string.digits) for n in range(0, 8)]) self.ew.wait_till_element_is_visible(self.NAME_INPUT, 5) self.ew.get_element(self.NAME_INPUT).send_keys(name) vr.validate_input_against_output(name, self.get_name()) def get_name(self): """ Gets name of budget from name input :return: str """ self.ew.wait_till_element_is_visible(self.NAME_INPUT, 5) if PLATFORM == "Android": return self.ew.get_text_of_element(self.NAME_INPUT) else: return self.ew.get_text_of_element(self.SELECTED_NAME_IOS) def set_amount(self, amount): """ Insert amount into amount input :param amount: str """ if amount == "random": amount = str(random.randint(1, 99)) self.ew.wait_and_tap_element(self.AMOUNT_INPUT, 5) self.ew.wait_till_element_is_visible(self.KEYBOARD["1"], 10) amount_list = list(amount) for i in amount_list: self.ew.wait_and_tap_element(self.KEYBOARD[i], 5) self.ew.wait_and_tap_element(self.NUMPAD_BACKDROP, 5) vr.validate_input_against_output(amount, self.get_amount()) def get_amount(self): """ Gets amount of budget from amount input :return: str """ self.ew.wait_till_element_is_visible(self.AMOUNT_INPUT, 5) if PLATFORM == "Android": return self.ew.get_text_of_element(self.SELECTED_AMOUNT) else: return self.ew.get_attribute(self.AMOUNT_INPUT, "name") def set_currency(self, currency): """ Selects currency of budget :param currency: str """ if currency == "random": currency = random.choice(vs.accessible_currencies) self.ew.wait_and_tap_element(self.CURRENCY, 5) self.ew.wait_till_element_is_visible(self.CURRENCY_PICKER, 10) self.ew.wait_and_tap_element(f"Currency {currency}", 10) self.ew.wait_till_element_is_not_visible(self.CURRENCY_PICKER, 10) vr.validate_input_against_output(currency, self.get_currency()) def get_currency(self): """ Gets selected currency of budget :return: str """ self.ew.wait_till_element_is_visible(self.CURRENCY, 5) if PLATFORM == "Android": return self.ew.get_text_of_element(self.SELECTED_CURRENCY) else: return self.ew.get_attribute(self.SELECTED_CURRENCY, "name") def set_wallets(self, wallets): """ Selects wallets from wallets picker :param wallets: str or int """ self.ew.wait_and_tap_element(self.WALLETS, 5) self.ew.wait_till_element_is_visible(self.WALLET_PICKER, 5) all_visible_wallets = self.count_wallets()[0] selected_wallets = self.count_wallets()[1] non_selected_wallets = self.count_wallets()[2] total_wallets = len(all_visible_wallets) total_selected_wallets = len(selected_wallets) total_non_selected_wallets = len(non_selected_wallets) if wallets == "random": wallets_to_select = random.sample(all_visible_wallets, random.randrange(0, len(all_visible_wallets))) for i in wallets_to_select: if PLATFORM == "Android": self.ew.tap_element(i) else: self.ew.tap_element(f'label == "{i}"') elif wallets == "all_selected": if total_wallets != total_selected_wallets: for i in non_selected_wallets: if PLATFORM == "Android": self.ew.tap_element(i) else: self.ew.tap_element(f'label == "{i}"') elif wallets == "all_unselected": if total_wallets != total_non_selected_wallets: for i in selected_wallets: if PLATFORM == "Android": self.ew.tap_element(i) else: self.ew.tap_element(f'label == "{i}"') elif isinstance(wallets, int): x = 0 actual_selected_wallets = self.count_wallets()[1] for i in all_visible_wallets: x = x + 1 if x <= wallets and len(actual_selected_wallets) > 1: if PLATFORM == "Android": self.ew.tap_element(i) else: self.ew.tap_element(f'label == "{i}"') actual_selected_wallets = self.count_wallets()[1] selected_wallets = self.count_wallets()[1] total_wallets = len(self.count_wallets()[0]) total_selected_wallets = len(selected_wallets) if total_wallets == total_selected_wallets: v_input = "All Wallets" elif total_selected_wallets == 1: v_input = selected_wallets[0].split('-')[0] else: v_input = str(total_selected_wallets) self.ew.tap_element('Backdrop') vr.validate_input_against_output(v_input, self.get_wallets()) def count_wallets(self): """ Gets all visible wallets, currently selected wallets and not_selected wallets from wallets picker :return: tuple of lists """ if PLATFORM == "Android": all_visible_wallets = self.ew.get_attributes(self.WALLET_ITEM, "content-desc") else: all_visible_wallets = self.ew.get_attributes(self.WALLET_ITEM, "label") selected_wallets = [] non_selected_wallets = [] for i in all_visible_wallets: if i.endswith('true'): selected_wallets.append(i) else: non_selected_wallets.append(i) return (all_visible_wallets, selected_wallets, non_selected_wallets) def get_wallets(self): """ Gets selected wallets (number, name or 'All Wallets') :return: str """ self.ew.wait_till_element_is_visible(self.WALLETS, 5) if PLATFORM == "Android": result = self.ew.get_text_of_element(self.SELECTED_WALLETS_ANDROID) if result is None: result = self.ew.get_text_of_element(self.SELECTED_WALLETS_ANDROID_2) else: result = self.ew.get_attribute(self.WALLETS, "name") return result def set_categories(self, categories): """ Selects requested number of categories :param categories: str """ self.ew.wait_and_tap_element(self.CATEGORIES, 5) self.ew.wait_till_element_is_visible(self.HEADER_BUDGET_FOR, 5) all_visible_categories = self.count_categories()[0] if categories == "random": categories = random.randrange(0, len(all_visible_categories)) if categories == "all_selected": if self.ew.is_element_present(self.SELECT_ALL_UNCHECKED): self.ew.tap_element(self.SELECT_ALL_UNCHECKED) elif self.ew.is_element_present(self.SELECT_ALL_PART): self.ew.tap_element(self.SELECT_ALL_PART) self.ew.tap_element(self.SELECT_ALL_UNCHECKED) elif categories == "all_unselected": if self.ew.is_element_present(self.SELECT_ALL_CHECKED): self.ew.tap_element(self.SELECT_ALL_CHECKED) elif self.ew.is_element_present(self.SELECT_ALL_PART): self.ew.tap_element(self.SELECT_ALL_PART) elif isinstance(categories, int): if self.ew.is_element_present(self.SELECT_ALL_CHECKED): self.ew.tap_element(self.SELECT_ALL_CHECKED) elif self.ew.is_element_present(self.SELECT_ALL_PART): self.ew.tap_element(self.SELECT_ALL_PART) x = 0 all_visible_categories = self.count_categories()[0] for i in all_visible_categories: x = x + 1 if x <= categories: self.ew.tap_element(i) if self.ew.is_element_present(self.SELECT_ALL_CHECKED): v_input = "All Expenses" else: v_input = str(len(self.count_categories()[1])) self.ew.tap_element(self.BACK_BUTTON) vr.validate_input_against_output(v_input, self.get_categories()) def count_categories(self): """ Gets all visible, currently selected and non selected categories inside category picker :return: tuple of lists """ if PLATFORM == "Android": all_visible_categories = self.ew.get_attributes(self.CATEGORY_ITEM, "content-desc") else: all_items = self.ew.get_attributes(self.CATEGORY_ITEM, "name") all_visible_categories = [] for i in all_items: if i != "Category Item": all_visible_categories.append(i) selected_categories = [] non_selected_categories = [] for i in all_visible_categories: if i.endswith('true'): selected_categories.append(i) else: non_selected_categories.append(i) return (all_visible_categories, selected_categories, non_selected_categories) def get_categories(self): """ Gets number of selected categories :return: str """ self.ew.wait_till_element_is_visible(self.CATEGORIES, 5) if PLATFORM == "Android": result = self.ew.get_text_of_element(self.SELECTED_CATEGORIES_ANDROID) if result is None: result = self.ew.get_text_of_element(self.SELECTED_CATEGORIES_ANDROID_2) return result else: return self.ew.get_attribute(self.CATEGORIES, "name") def set_recurrence(self, recurrence): """ Selects requested recurrence of budget :param recurrence: str """ self.ew.wait_and_tap_element(self.RECURRENCE, 5) self.ew.wait_till_element_is_visible(self.RECURRENCE_PICKER, 5) if recurrence == "random": recurrence = random.choice(vs.budget_recurrences) res = self.rs.get_resolution() if PLATFORM == "Android": item_visible = self.ew.is_element_present(recurrence) while item_visible is False: self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["default_picker_up_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["default_picker_up_y_end"]) \ .release().perform() item_visible = self.ew.is_element_present(recurrence) self.ew.wait_and_tap_element(recurrence, 5) else: item_visible = self.ew.get_attribute(recurrence, "visible") while item_visible == "false": self.driver.execute_script("mobile: dragFromToForDuration", {"duration": "0.1", "fromX": self.rs.all_resolutions[f"{res}"]["x"], "fromY": self.rs.all_resolutions[f"{res}"]["default_picker_up_y_start"], "toX": self.rs.all_resolutions[f"{res}"]["x"], "toY": self.rs.all_resolutions[f"{res}"]["default_picker_up_y_end"]}) item_visible = self.ew.get_attribute(recurrence, "visible") self.driver.execute_script("mobile: tap", {"x": 100, "y": 50, "element": self.ew.get_element(recurrence)}) vr.validate_input_against_output(recurrence, self.get_recurrence()) def get_recurrence(self): """ Gets selected recurrence :return: str """ self.ew.wait_till_element_is_visible(self.RECURRENCE, 5) if PLATFORM == "Android": recurrence = self.ew.get_text_of_element(self.SELECTED_RECURRENCE_ANDROID) if recurrence is None: recurrence = self.ew.get_text_of_element(self.SELECTED_RECURRENCE_ANDROID_EDIT) else: recurrence = self.ew.get_attribute(self.RECURRENCE, "name") return recurrence def set_start_date(self, start_date): """ Selects start date of budget :param start_date: str """ if start_date == "random": start_date = str( datetime.date(int(datetime.date.today().year), random.randint(1, 12), random.randint(1, 28))) elif start_date == "future": start_date = str(datetime.date.today() + datetime.timedelta(days=random.randint(1, 5))) elif start_date == "today": start_date = str(datetime.date.today()) elif start_date == "yesterday": start_date = str(datetime.date.today() - datetime.timedelta(days=1)) elif start_date == "tomorrow": start_date = str(datetime.date.today() + datetime.timedelta(days=1)) self.ew.wait_and_tap_element(self.START_DATE, 5) self.ew.wait_till_element_is_visible(self.CALENDAR_PICKER, 5) self.transaction_detail.set_calendar_month_year(start_date) self.transaction_detail.set_calendar_day(start_date) vr.validate_input_against_output(start_date, self.transaction_detail.get_date("start")) def set_end_date(self, end_date): """ Selects end date of budget :param end_date: str """ start_date = self.transaction_detail.get_date("start") year_start, month_start, day_start = (int(x) for x in start_date.split('-')) start_date = datetime.date(year_start, month_start, day_start) if end_date == "random": end_date = str(start_date + datetime.timedelta(days=random.randint(1, 30))) elif end_date == "day_after_start_date": end_date = str(start_date + datetime.timedelta(days=1)) else: year_end, month_end, day_end = (int(x) for x in end_date.split('-')) end_date = datetime.date(year_end, month_end, day_end) if start_date < end_date: end_date = str(end_date) else: raise ValueError(f"endDate {end_date} is not older than start_date {str(start_date)}") self.ew.wait_and_tap_element(self.END_DATE, 5) self.ew.wait_till_element_is_visible(self.CALENDAR_PICKER, 5) self.transaction_detail.set_calendar_month_year(end_date) self.transaction_detail.set_calendar_day(end_date) vr.validate_input_against_output(end_date, self.transaction_detail.get_date("end"))
def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver) self.transaction_detail = TransactionDetail(self.driver)
def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver)
class ExportActions: BACKDROP = "Backdrop" # WALLETS WALLETS = "Wallets" # PERIOD PERIOD = "Period" PERIOD_SIZE_PICKER = "Period size Picker" SELECT_DATE_RANGE_PICKER = "Select date range Picker" # FORMAT FORMAT = "Format" FORMAT_PICKER = "Format Picker" if PLATFORM == "Android": XLSX_TRUE = "Excel (.xlsx)-true" else: XLSX_TRUE = 'label == "Excel (.xlsx)-true"' def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver) def set_period(self, period): """ Selects period from period picker :param period: str """ self.ew.wait_and_tap_element(self.PERIOD, 10) self.ew.wait_till_element_is_visible(self.PERIOD_SIZE_PICKER, 10) if period == "random": period = random.choice(vs.export_periods) res = self.rs.get_resolution() if PLATFORM == "Android": item_visible = self.ew.is_element_present(period) while item_visible is False: self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["default_picker_up_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["default_picker_up_y_end"]) \ .release().perform() item_visible = self.ew.is_element_present(period) self.ew.wait_and_tap_element(period, 5) else: item_visible = self.ew.get_attribute(period, "visible") while item_visible == "false": self.driver.execute_script( "mobile: dragFromToForDuration", { "duration": "0.1", "fromX": self.rs.all_resolutions[f"{res}"]["x"], "fromY": self.rs.all_resolutions[f"{res}"] ["default_picker_up_y_start"], "toX": self.rs.all_resolutions[f"{res}"]["x"], "toY": self.rs.all_resolutions[f"{res}"] ["default_picker_up_y_end"] }) item_visible = self.ew.get_attribute(period, "visible") self.driver.execute_script("mobile: tap", { "x": 100, "y": 50, "element": self.ew.get_element(period) }) def set_format(self, format): """ Selects format of file from format picker :param format: str """ self.ew.wait_and_tap_element(self.FORMAT, 10) self.ew.wait_till_element_is_visible(self.FORMAT_PICKER, 10) if format == "random": format = random.choice(vs.export_formats) self.ew.wait_and_tap_element(format, 5)
class BudgetActions(): def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.budgets_general = BudgetsGeneral(self.driver) self.budget_detail = BudgetDetail(self.driver) self.budget_overview = BudgetOverview(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver) def create_budget(self, name, amount, currency, wallets, categories, recurrence, start_date, end_date): """ Opens budget create screen and sets requested attributes of budget :param name: str :param amount: str :param currency: str or None :param wallets: str or int or None :param categories: str or int or None :param recurrence: str or None :param start_date: str or None :param end_date: str or None """ self.budgets_general.go_to_budgets() self.open_budget_create_screen() self.budget_detail.set_name(name) self.budget_detail.set_amount(amount) if currency is not None: self.budget_detail.set_currency(currency) if wallets is not None: self.budget_detail.set_wallets(wallets) if categories is not None: self.budget_detail.set_categories(categories) if recurrence is not None: self.budget_detail.set_recurrence(recurrence) if start_date is not None: self.budget_detail.set_start_date(start_date) if end_date is not None: self.budget_detail.set_end_date(end_date) def save_budget(self): """Clicks on save budget button""" if self.driver.is_keyboard_shown(): self.driver.hide_keyboard() self.ew.wait_and_tap_element(self.budget_detail.SAVE_BUDGET_BUTTON, 10) self.ew.wait_till_element_is_not_visible( self.budget_detail.SAVE_BUDGET_BUTTON, 10) def open_budget_create_screen(self): """Opens budget create screen, if button is not visible it swipes to it""" self.ew.wait_till_element_is_visible( self.budgets_general.BUDGETS_HEADER, 10) if PLATFORM == "Android": add_button_visible = self.ew.is_element_present( self.budgets_general.ADD_BUDGET_BUTTON) while add_button_visible is False: res = self.rs.get_resolution() self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["budget_overview_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["budget_overview_y_end"]) \ .release().perform() add_button_visible = self.ew.is_element_present( self.budgets_general.ADD_BUDGET_BUTTON) else: add_button_visible = self.ew.get_attribute( self.budgets_general.ADD_BUDGET_BUTTON, "visible") while add_button_visible == "false": res = self.rs.get_resolution() self.driver.execute_script( "mobile: dragFromToForDuration", { "duration": "0.1", "fromX": self.rs.all_resolutions[f"{res}"]["x"], "fromY": self.rs.all_resolutions[f"{res}"] ["budget_overview_y_start"], "toX": self.rs.all_resolutions[f"{res}"]["x"], "toY": self.rs.all_resolutions[f"{res}"] ["budget_overview_y_end"] }) add_button_visible = self.ew.get_attribute( self.budgets_general.ADD_BUDGET_BUTTON, "visible") self.ew.wait_and_tap_element(self.budgets_general.ADD_BUDGET_BUTTON, 5) self.ew.wait_till_element_is_visible(self.budget_detail.BUDGET_HEADER, 10) def open_budget(self): """Opens existing budget detail screen, if there is no budget created yet, it creates one""" self.budgets_general.go_to_budgets() self.ew.wait_till_element_is_visible( self.budgets_general.BUDGETS_HEADER, 5) if self.ew.is_element_present( self.budgets_general.BUDGET_ITEM) is False: self.create_budget(name="random", amount="random", currency=None, wallets=None, categories=None, recurrence=None, start_date=None, end_date=None) self.save_budget() self.budgets_general.go_to_budgets() self.ew.wait_and_tap_element(self.budgets_general.BUDGET_ITEM, 5) self.ew.wait_and_tap_element( self.budget_overview.BUDGET_SETTINGS_BUTTON, 5) self.ew.wait_till_element_is_visible(self.budget_detail.BUDGET_HEADER, 5) def edit_budget(self, name, amount, currency, wallets, categories, recurrence, start_date, end_date): """ Opens budget edit screen and sets requested attributes of budget :param name: str or None :param amount: str or None :param currency: str or None :param wallets: str or int or None :param categories: str or int or None :param recurrence: str or None :param start_date: str or None :param end_date: str or None """ self.open_budget() if name is not None: if PLATFORM == "Android": self.ew.get_element(self.budget_detail.NAME_INPUT).clear() else: self.ew.get_element( self.budget_detail.SELECTED_NAME_IOS).clear() self.budget_detail.set_name(name) if amount is not None: self.ew.wait_and_tap_element(self.budget_detail.AMOUNT_INPUT, 5) self.ew.wait_till_element_is_visible( self.budget_detail.NUMPAD_CLEAR, 10) for i in range(6): self.ew.tap_element(self.budget_detail.NUMPAD_CLEAR) self.ew.tap_element(self.budget_detail.NUMPAD_BACKDROP) self.budget_detail.set_amount(amount) if currency is not None: self.budget_detail.set_currency(currency) if wallets is not None: self.budget_detail.set_wallets(wallets) if categories is not None: self.budget_detail.set_categories(categories) if recurrence is not None: self.budget_detail.set_recurrence(recurrence) if start_date is not None: self.budget_detail.set_start_date(start_date) if end_date is not None: self.budget_detail.set_end_date(end_date) def delete_budget(self): """Deletes existing budget from budget detail screen""" self.ew.wait_and_tap_element(self.budget_detail.TRASH_ICON, 10) self.ew.wait_and_tap_element(self.budget_detail.DELETE_BUTTON, 10) self.ew.wait_till_element_is_visible( self.budgets_general.BUDGETS_HEADER, 10)
class TransactionTemplateValidator: def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.period_filter = PeriodFilter(self.driver) self.rs = Resolutions(self.driver) self.timeline_general = TimelineGeneral(self.driver) self.transaction_detail = TransactionDetail(self.driver) self.transaction_validator = TransactionValidator(self.driver) def get_all_attributes(self): """ Getting all attributes of transaction template :return: dict """ all_attributes = { "category": self.transaction_detail.get_category(), "amount": self.transaction_detail.get_amount(), "wallet_amount": self.transaction_detail.get_wallet_amount(), "currency": self.transaction_detail.get_currency(), "wallet": self.transaction_detail.get_wallet("transaction"), "start_date": self.transaction_detail.get_date("start"), "note": self.transaction_detail.get_note(), "labels": self.transaction_detail.get_labels(True), "photo": self.transaction_detail.get_photo(), "recurrence": self.transaction_detail.get_recurrence(), "end_date": self.transaction_detail.get_date("end"), "reminder": self.transaction_detail.get_reminder(), } return all_attributes def is_transaction_template_on_timeline(self, attributes): """ Checking if template is visible inside Scheduled section :param attributes: dict :return: bool """ transaction_locator = f"regular/" \ f"{attributes['category']}/" \ f"{self.transaction_validator.adjust_amounts(attributes['amount'], attributes['wallet_amount'])[0]}/" \ f"{self.transaction_validator.adjust_amounts(attributes['amount'], attributes['wallet_amount'])[1]}/" \ f"{attributes['wallet']}/" \ f"undefined/" \ f"{self.transaction_validator.adjust_note(attributes['note'])}/" \ f"{self.transaction_validator.adjust_labels(attributes['labels'])}/" \ f"{str(attributes['photo']).lower()}/" \ f"{self.adjust_recurrence(attributes['recurrence'])}/" \ f"{self.adjust_end_date(attributes['end_date'])}/" \ f"{self.transaction_validator.adjust_reminder(attributes['reminder'])}" print(f'LOCATOR: {transaction_locator}') self.transaction_validator.prepare_timeline( attributes['start_date'], self.adjust_recurrence(attributes['recurrence'])) android_timeout = time.time() + 60 ios_timeout = time.time() + 5 res = self.rs.get_resolution() is_transaction_present = self.ew.is_element_present( transaction_locator) while is_transaction_present is False: if PLATFORM == "Android": self.transaction_validator.swipe_android(res) is_transaction_present = self.ew.is_element_present( transaction_locator) if time.time() > android_timeout: return False else: is_transaction_present = self.ew.is_element_present( transaction_locator) if time.time() > ios_timeout: return False return True def adjust_recurrence(self, recurrence): """ Adjusting recurrence for template locator :param recurrence: str :return: str """ if recurrence is None or recurrence == "never": return "undefined" else: return recurrence def adjust_end_date(self, end_date): """ Adjusting end date for template locator :param end_date: str :return: str """ if end_date is None: return "undefined" else: return end_date
def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.log = logging.getLogger('log') self.rs = Resolutions(self.driver)
class TransactionValidator: def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.period_filter = PeriodFilter(self.driver) self.rs = Resolutions(self.driver) self.timeline_general = TimelineGeneral(self.driver) self.transaction_detail = TransactionDetail(self.driver) def get_all_attributes(self): """ Getting all attributes of transaction :return: dict """ all_attributes = { "category": self.transaction_detail.get_category(), "amount": self.transaction_detail.get_amount(), "wallet_amount": self.transaction_detail.get_wallet_amount(), "currency": self.transaction_detail.get_currency(), "wallet": self.transaction_detail.get_wallet("transaction"), "start_date": self.transaction_detail.get_date("start"), "note": self.transaction_detail.get_note(), "labels": self.transaction_detail.get_labels(True), "photo": self.transaction_detail.get_photo(), "reminder": self.transaction_detail.get_reminder(), } return all_attributes def is_transaction_on_timeline(self, attributes): """ Checking if transaction is visible inside Timeline or Scheduled section :param attributes: dict :return: bool """ transaction_locator = f"regular/" \ f"{attributes['category']}/" \ f"{self.adjust_amounts(attributes['amount'], attributes['wallet_amount'])[0]}/" \ f"{self.adjust_amounts(attributes['amount'], attributes['wallet_amount'])[1]}/" \ f"{attributes['wallet']}/" \ f"undefined/" \ f"{self.adjust_note(attributes['note'])}/" \ f"{self.adjust_labels(attributes['labels'])}/" \ f"{str(attributes['photo']).lower()}/" \ f"undefined/" \ f"undefined/" \ f"{self.adjust_reminder(attributes['reminder'])}" print(f'LOCATOR: {transaction_locator}') self.prepare_timeline(attributes['start_date'], "undefined") android_timeout = time.time() + 60 ios_timeout = time.time() + 5 res = self.rs.get_resolution() is_transaction_present = self.ew.is_element_present( transaction_locator) while is_transaction_present is False: if PLATFORM == "Android": self.swipe_android(res) is_transaction_present = self.ew.is_element_present( transaction_locator) if time.time() > android_timeout: return False else: is_transaction_present = self.ew.is_element_present( transaction_locator) if time.time() > ios_timeout: return False return True def adjust_amounts(self, amount, wallet_amount): """ Adjusting amount for transaction locator :param amount: str :param wallet_amount: str :return: list of str """ if wallet_amount is None: amount_final = amount wallet_amount_final = "undefined" else: amount_final = "" for i in wallet_amount: if i in [ "-", ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ]: amount_final = amount_final + i wallet_amount_final = "{:.2f}".format(float(amount)) return ["{:.2f}".format(float(amount_final)), wallet_amount_final] def adjust_note(self, note): """ Adjusting note for transaction locator :param note: str :return: str """ if note is None: note = "" return note def adjust_labels(self, labels): """ Adjusting labels for transaction locator :param labels: list of str :return: list of str """ if len(labels) > 0: labels_final = "" for i in labels: labels_final = labels_final + f",{i}" labels_final = labels_final[1:] else: labels_final = "undefined" return labels_final def adjust_reminder(self, reminder): """ Adjusting reminder for transaction locator :param reminder: str :return: str """ if reminder is None or reminder == "Never": return "undefined" else: return reminder def prepare_timeline(self, start_date, recurrence): """ Prepares timeline for transaction search. Opening scheduled screen if transaction has future date. :param start_date: str :param recurrence: str """ self.ew.wait_till_element_is_visible( self.timeline_general.NAVIGATION_TIMELINE, 30) year, month, day = (int(x) for x in start_date.split('-')) date = datetime.date(year, month, day) today = datetime.date.today() if date > today or recurrence != "undefined": if self.ew.is_element_present( self.timeline_general.SCHEDULED_SCREEN) is False: self.ew.wait_till_element_is_visible( self.timeline_general.TRANSACTION_SECTION, 20) self.timeline_general.open_scheduled_section() else: if PLATFORM == "Android": time.sleep(5) else: time.sleep(2) elif date < today: self.period_filter.set_filter_period( self.period_filter.ALL_TIME_PERIOD) def swipe_android(self, resolution): """ Looks into past by swiping on android phones :param resolution: str :return: """ self.action.long_press(None, self.rs.all_resolutions[f"{resolution}"]["x"], self.rs.all_resolutions[f"{resolution}"]["transaction_timeline_up_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{resolution}"]["x"], self.rs.all_resolutions[f"{resolution}"]["transaction_timeline_up_y_end"]) \ .release().perform()
class BudgetValidator: def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.budget_detail = BudgetDetail(self.driver) self.budgets_general = BudgetsGeneral(self.driver) self.budget_overview = BudgetOverview(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver) self.transaction_detail = TransactionDetail(self.driver) def get_all_attributes(self): """ Getting all attributes of budget :return: dict """ all_attributes = { "name": self.budget_detail.get_name(), "amount": self.budget_detail.get_amount(), "currency": self.budget_detail.get_currency(), "wallets": self.budget_detail.get_wallets(), "categories": self.budget_detail.get_categories(), "recurrence": self.budget_detail.get_recurrence(), "start_date": self.transaction_detail.get_date("start"), "end_date": self.transaction_detail.get_date("end") } return all_attributes def is_budget_existing(self, attributes): """ Checking if budget is visible inside Budgets section :param attributes: dict :return: bool """ budget_locator = f"{attributes['name']}/" \ f"{attributes['amount']}/" \ f"{attributes['currency']}/" \ f"{self.adjust_wallets(attributes['wallets'])}/" \ f"{self.adjust_categories(attributes['categories'])}/" \ f"{self.adjust_recurrence(attributes['recurrence'])}/" \ f"{attributes['start_date']}/" \ f"{self.adjust_end_date(attributes['end_date'], attributes['start_date'], attributes['recurrence'])}" print(f'ATTRIBUTES: {attributes}') print(f'LOCATOR: {budget_locator}') if self.ew.is_element_present(self.budget_overview.OVERVIEW_BUTTON): self.ew.tap_element(self.budget_overview.BACK_BUTTON) self.ew.wait_till_element_is_visible( self.budgets_general.BUDGETS_HEADER, 10) android_timeout = time.time() + 30 ios_timeout = time.time() + 5 res = self.rs.get_resolution() is_budget_present = self.ew.is_element_present(budget_locator) while is_budget_present is False: if PLATFORM == "Android": self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["budget_overview_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["budget_overview_y_end"]) \ .release().perform() is_budget_present = self.ew.is_element_present(budget_locator) if time.time() > android_timeout: return False else: is_budget_present = self.ew.is_element_present(budget_locator) if time.time() > ios_timeout: return False return True def adjust_wallets(self, wallets): """ Adjusting wallets for budget locator :param wallets: str :return: str """ if wallets == "All Wallets": return "undefined" elif wallets in ["0", "2", "3", "4", "5", "6", "7", "8", "9", "10"]: return wallets else: return "1" def adjust_categories(self, categories): """ Adjusting categories for budget locator :param categories: str :return: str """ if categories == "All Expenses": return "undefined" else: return categories def adjust_recurrence(self, recurrence): """ Adjusting recurrence for recurrence locator :param recurrence: str :return: str """ recurrences_in_app = [ "once", "day", "week", "every two weeks", "month", "year" ] return recurrences_in_app[vs.budget_recurrences.index(recurrence)] def adjust_end_date(self, end_date, start_date, recurrence): """ Adjusting end date for budget locator :param end_date: str :param start_date: str :param recurrence: str :return: str """ if end_date is None: year_start, month_start, day_start = ( int(x) for x in start_date.split('-')) start_date = datetime.date(year_start, month_start, day_start) if (year_start % 4) == 0: if (year_start % 100) == 0: if (year_start % 400) == 0: is_year_leap = True else: is_year_leap = False else: is_year_leap = True else: is_year_leap = False if recurrence == "Daily": end_date = start_date elif recurrence == "Weekly": end_date = str(start_date + datetime.timedelta(days=6)) elif recurrence == "Biweekly": end_date = str(start_date + datetime.timedelta(days=13)) elif recurrence == "Monthly": if month_start in ["01", "03", "05", "07", "08", "10", "12"]: end_date = str(start_date + datetime.timedelta(days=30)) elif month_start in ["04", "06", "09", "11"]: end_date = str(start_date + datetime.timedelta(days=29)) else: if is_year_leap: end_date = str(start_date + datetime.timedelta(days=28)) else: end_date = str(start_date + datetime.timedelta(days=27)) elif recurrence == "Yearly": if is_year_leap: end_date = str(start_date + datetime.timedelta(days=365)) else: end_date = str(start_date + datetime.timedelta(days=364)) return end_date
class TransferTemplateValidator: def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.period_filter = PeriodFilter(self.driver) self.rs = Resolutions(self.driver) self.timeline_general = TimelineGeneral(self.driver) self.transaction_detail = TransactionDetail(self.driver) self.transaction_template_validator = TransactionTemplateValidator( self.driver) self.transaction_validator = TransactionValidator(self.driver) self.transfer_validator = TransferValidator(self.driver) def get_all_attributes(self): """ Getting all attributes of transfer template :return: dict """ all_attributes = { "amount": self.transaction_detail.get_amount(), "currency": self.transaction_detail.get_currency(), "wallet_amount": self.transaction_detail.get_wallet_amount(), "outgoing_wallet": self.transaction_detail.get_wallet("transfer_outgoing"), "incoming_wallet": self.transaction_detail.get_wallet("transfer_incoming"), "start_date": self.transaction_detail.get_date("start"), "note": self.transaction_detail.get_note(), "recurrence": self.transaction_detail.get_recurrence(), "end_date": self.transaction_detail.get_date("end"), "reminder": self.transaction_detail.get_reminder(), } return all_attributes def is_transfer_template_on_timeline(self, attributes): """ Checking if transfer template is visible inside Scheduled section :param attributes: dict :return: bool """ if "Out of Spendee" not in [ attributes['outgoing_wallet'], attributes['incoming_wallet'] ]: is_two_way_transfer = True else: is_two_way_transfer = False transfer_locator = f"transfer/" \ f"undefined/" \ f"{self.transfer_validator.adjust_amounts(attributes['amount'], attributes['wallet_amount'], attributes['currency'], attributes['outgoing_wallet'], attributes['incoming_wallet'])[0]}/" \ f"{self.transfer_validator.adjust_amounts(attributes['amount'], attributes['wallet_amount'], attributes['currency'], attributes['outgoing_wallet'], attributes['incoming_wallet'])[1]}/" \ f"{self.transfer_validator.adjust_wallets(attributes['outgoing_wallet'], attributes['incoming_wallet'])[0]}/" \ f"{self.transfer_validator.adjust_wallets(attributes['outgoing_wallet'], attributes['incoming_wallet'])[1]}/" \ f"{self.transaction_validator.adjust_note(attributes['note'])}/" \ f"undefined/" \ f"false/" \ f"{self.transaction_template_validator.adjust_recurrence(attributes['recurrence'])}/" \ f"{self.transaction_template_validator.adjust_end_date(attributes['end_date'])}/" \ f"{self.transaction_validator.adjust_reminder(attributes['reminder'])}" print(f'LOCATOR: {transfer_locator}') if is_two_way_transfer: _, _, amount, wallet_amount, outgoing_wallet, incoming_wallet, _, _, _, recurrence, _, _ = ( str(x) for x in transfer_locator.split('/')) s_out = transfer_locator.split("/") s_in = transfer_locator.split("/") s_out[2] = f"-{amount}" if wallet_amount != "undefined": s_out[3] = f"-{wallet_amount}" if recurrence == "undefined": s_in[4] = incoming_wallet s_in[5] = outgoing_wallet transfer_outgoing_locator = '/'.join(s_out) transfer_incoming_locator = '/'.join(s_in) print(f'OUTGOING LOCATOR: {transfer_outgoing_locator}') print(f'INCOMING LOCATOR: {transfer_incoming_locator}') self.transaction_validator.prepare_timeline( attributes['start_date'], self.transaction_template_validator.adjust_recurrence( attributes['recurrence'])) android_timeout = time.time() + 60 ios_timeout = time.time() + 5 res = self.rs.get_resolution() if is_two_way_transfer: locator = transfer_outgoing_locator else: locator = transfer_locator is_transfer_present = self.ew.is_element_present(locator) while is_transfer_present is False: if PLATFORM == "Android": self.transaction_validator.swipe_android(res) is_transfer_present = self.ew.is_element_present(locator) if time.time() > android_timeout: return False else: is_transfer_present = self.ew.is_element_present(locator) if time.time() > ios_timeout: return False if is_two_way_transfer and self.ew.is_element_present( transfer_incoming_locator) is False: return False return True
class TransactionDetail: # OTHER BACK_BUTTON = "Back Button" if PLATFORM == "Android": TRANSACTION_HEADER_TITLE = "Transaction Header Title" else: TRANSACTION_HEADER_TITLE = '**/XCUIElementTypeStaticText[`label == "Transaction Header Title"`]' SAVE_TRANSACTION_BUTTON = "Save Transaction Button" TRASH_ICON = "Trash Icon" DELETE_BUTTON = "Delete" # KEYBOARD KEYBOARD = { "0": "Numpad 0", "1": "Numpad 1", "2": "Numpad 2", "3": "Numpad 3", "4": "Numpad 4", "5": "Numpad 5", "6": "Numpad 6", "7": "Numpad 7", "8": "Numpad 8", "9": "Numpad 9", ".": "Numpad Decimal Point", ",": "Numpad Decimal Point" } NUMPAD_BACKDROP = "Numpad Backdrop" NUMPAD_CLEAR = "Numpad Clear" # TYPE AND CATEGORY CATEGORY_ICON = "Category Icon" EXPENSES_PICKER = "Expenses Picker" INCOME_PICKER = "Income Picker" TRANSACTION_PICKER = "Transaction Picker" TRANSFER_PICKER = "Transfer Picker" if PLATFORM == "Android": SELECTED_TYPE = "Selected Type" else: SELECTED_TYPE = '**/XCUIElementTypeStaticText[`label == "Selected Type"`]' GEAR_ICON = "Gear Icon" CONFIRM_CATEGORY_ICON = "Confirm Category Icon" # AMOUNT if PLATFORM == "Android": AMOUNT_INPUT = "//android.view.ViewGroup[@content-desc='Amount Input']/android.view.ViewGroup/android.widget.TextView" WALLET_AMOUNT = "//android.view.ViewGroup[@content-desc='Wallet Price']/android.widget.TextView" else: AMOUNT_INPUT = 'label == "Amount Input"' WALLET_AMOUNT = "//XCUIElementTypeOther[@name='Wallet Price']/XCUIElementTypeStaticText" # CURRENCY CONFIRM_BUTTON = "Confirm Button" if PLATFORM == "Android": CURRENCY = "Currency" else: CURRENCY = "(//XCUIElementTypeOther[@name='Currency'])[1]/XCUIElementTypeOther" SELECTED_CURRENCY_ANDROID = "//android.view.ViewGroup[@content-desc='Currency']/android.widget.TextView" # WALLET if PLATFORM == "Android": WALLET = "Wallet" OUTGOING_WALLET = "Outgoing Wallet" INCOMING_WALLET = "Incoming Wallet" WALLET_ITEM = '//android.view.ViewGroup[@content-desc="Select Wallet Picker"]/android.widget.ScrollView/' \ 'android.view.ViewGroup/android.widget.ScrollView/android.view.ViewGroup/android.view.ViewGroup' else: WALLET = 'label == "Wallet"' OUTGOING_WALLET = 'label == "Outgoing Wallet"' INCOMING_WALLET = 'label == "Incoming Wallet"' WALLET_ITEM = "Wallet Item" WALLET_PICKER = "Select Wallet Picker" SELECTED_WALLET_ANDROID = "//android.view.ViewGroup[@content-desc='Wallet']//android.widget.TextView[2]" SELECTED_OUTGOING_WALLET_ANDROID = "//android.view.ViewGroup[@content-desc='Outgoing Wallet']//android.widget.TextView[2]" SELECTED_INCOMING_WALLET_ANDROID = "//android.view.ViewGroup[@content-desc='Incoming Wallet']//android.widget.TextView[2]" # START DATE CALENDAR_PICKER = "Select date Picker" SELECTED_START_DATE_ANDROID = "//android.view.ViewGroup[@content-desc='Start Date']/android.view.ViewGroup/android.widget.TextView" SELECTED_START_DATE_ANDROID_2 = "//android.view.ViewGroup[@content-desc='Start Date']/android.widget.TextView" SELECTED_END_DATE_ANDROID = "//android.view.ViewGroup[@content-desc='End Date']/android.view.ViewGroup/android.widget.TextView[2]" SELECTED_END_DATE_ANDROID_2 = "//android.view.ViewGroup[@content-desc='End Date']/android.widget.TextView[2]" SELECTED_START_DATE_ANDROID_BUDGET = '//android.view.ViewGroup[@content-desc="Start Date"]/android.view.ViewGroup/android.widget.TextView[2]' SELECTED_START_DATE_ANDROID_BUDGET_2 = '//android.view.ViewGroup[@content-desc="Start Date"]/android.widget.TextView[2]' SELECTED_END_DATE_ANDROID_BUDGET = '//android.view.ViewGroup[@content-desc="End Date"]/android.view.ViewGroup/android.widget.TextView[2]' SELECTED_END_DATE_ANDROID_BUDGET_2 = '//android.view.ViewGroup[@content-desc="End Date"]/android.widget.TextView[2]' if PLATFORM == "Android": START_DATE = "Start Date" ACTUAL_MONTH_YEAR = "//android.widget.SeekBar/android.widget.TextView" else: START_DATE = 'label == "Start Date"' ACTUAL_MONTH_YEAR = "(//XCUIElementTypeOther[@name='Select date Picker']//XCUIElementTypeOther[contains(@name,'undefined')])[2]" # NOTE if PLATFORM == "Android": NOTE = "Note" EXISTING_NOTE = "Note" else: NOTE = "//XCUIElementTypeTextView[@name='Note Write a note']" EXISTING_NOTE = '**/XCUIElementTypeTextView[`label == "Note"`]' SELECTED_NOTE_IOS = "Note" NOTE_ELEMENT = "Note Element" # LABELS LABELS = "Labels" LABEL_ITEM = "Label Item" if PLATFORM == "Android": LABEL_INPUT = "//android.widget.EditText" else: LABEL_INPUT = "//XCUIElementTypeTextField" NON_EXISTING_LABEL = "Non Existing Label" VISIBLE_LABELS_ANDROID = "//android.view.ViewGroup[@content-desc='Label Item']/android.widget.TextView" VISIBLE_LABELS_IOS = "//XCUIElementTypeOther[@name='Label Item']/XCUIElementTypeOther" SELECTED_LABELS_ANDROID = "//android.view.ViewGroup[@content-desc='Check Mark']/android.view.ViewGroup/ancestor::*[1]/following-sibling::*[1]" PREMIUM_LABEL_ALERT = "Premium Label Alert" NOT_NOW_BUTTON = "Now now" # PHOTO PHOTO = "Photo" SELECTED_PHOTO = "Selected Photo" if PLATFORM == "Android": CHOOSE_PHOTO = "//android.widget.TextView[2]" PHOTO_FOLDER = "//android.widget.RelativeLayout" PHOTO_ITEM = "(//android.support.v7.widget.RecyclerView/android.view.ViewGroup)[1]" else: CHOOSE_PHOTO = "Choose from Library…" PHOTO_FOLDER = "All Photos" PHOTO_ITEM = "(//XCUIElementTypeImage)[1]" ALLOW_PHOTO_ACCESS_ANDROID = "com.android.packageinstaller:id/permission_allow_button" # RECURRENCE if PLATFORM == "Android": RECURRENCE = "Recurrence" else: RECURRENCE = 'label == "Recurrence"' RECURRENCE_PICKER = "Recurrence Picker" SELECTED_RECURRENCE_ANDROID = "//android.view.ViewGroup[@content-desc='Recurrence']/android.view.ViewGroup/android.widget.TextView[2]" SELECTED_RECURRENCE_ANDROID_EDIT = '//android.view.ViewGroup[@content-desc="Recurrence"]/android.widget.TextView[2]' # END DATE if PLATFORM == "Android": END_DATE = "End Date" else: END_DATE = 'label == "End Date"' # REMINDER if PLATFORM == "Android": REMINDER = "Reminder" else: REMINDER = 'label == "Reminder"' REMINDER_PICKER = "Reminder Picker" SELECTED_REMINDER_ANDROID = "//android.view.ViewGroup[@content-desc='Reminder']/android.view.ViewGroup/android.widget.TextView[2]" def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver) def set_type_of_transaction(self, transaction_type): """ Selects type of transaction :param transaction_type: str """ if transaction_type == "random": transaction_type = random.choice( [self.EXPENSES_PICKER, self.INCOME_PICKER]) elif transaction_type == "opposite": actual_type = self.get_type_of_transaction() if actual_type == "Expenses": transaction_type = self.INCOME_PICKER else: transaction_type = self.EXPENSES_PICKER elif transaction_type == "expenses": transaction_type = self.EXPENSES_PICKER elif transaction_type == "income": transaction_type = self.INCOME_PICKER if transaction_type == self.EXPENSES_PICKER: v_input = "Expenses" else: v_input = "Income" self.ew.wait_and_tap_element(transaction_type, 5) if PLATFORM == "Android": time.sleep(0.5) vr.validate_input_against_output(v_input, self.get_type_of_transaction()) def get_type_of_transaction(self): """ Gets type of transaction :return: str """ self.ew.wait_till_element_is_visible(self.SELECTED_TYPE, 5) if PLATFORM == "Android": return self.ew.get_text_of_element(self.SELECTED_TYPE) else: return self.ew.get_attribute(self.SELECTED_TYPE, "name") def set_type_to_transfer(self): """Will select type as transfer""" self.ew.wait_and_tap_element(self.TRANSFER_PICKER, 5) self.ew.wait_till_element_is_not_visible(self.TRANSFER_PICKER, 5) if self.ew.is_element_present(self.NUMPAD_BACKDROP): pass else: vr.validate_input_against_output("Transfer", self.get_category()) def open_type_picker(self): """Opens type picker""" self.ew.wait_and_tap_element(self.CATEGORY_ICON, 10) def set_category(self, category): """ Selects category from category picker :param category: str """ self.ew.wait_till_element_is_visible(self.TRANSACTION_PICKER, 5) if category == "random": category_visible = False timeout = time.time() + 15 while category_visible is False: category = random.choice(vs.default_set_of_categories) category_visible = self.ew.is_element_present( f"Category {category}") if time.time() > timeout: break self.ew.tap_element(f"Category {category}") self.ew.wait_till_element_is_not_visible(self.TRANSACTION_PICKER, 5) if self.ew.is_element_present(self.NUMPAD_BACKDROP): pass else: vr.validate_input_against_output(category, self.get_category()) def get_category(self): """ Gets selected category :return: str """ self.ew.wait_till_element_is_visible(self.TRANSACTION_HEADER_TITLE, 5) if PLATFORM == "Android": category = self.ew.get_text_of_element( self.TRANSACTION_HEADER_TITLE).split(" ")[1:] else: category = self.ew.get_attribute(self.TRANSACTION_HEADER_TITLE, "name").split(" ")[1:] return ' '.join(category) def set_amount(self, amount): """ Insert amount into amount input :param amount: str """ if amount == "random": amount = str(random.randint(1, 99)) self.ew.wait_till_element_is_visible(self.KEYBOARD["1"], 10) amount_list = list(amount) for i in amount_list: self.ew.wait_and_tap_element(self.KEYBOARD[i], 5) self.ew.wait_and_tap_element(self.NUMPAD_BACKDROP, 5) v_output = self.get_amount() if v_output.startswith("-"): v_output = v_output[1:] vr.validate_input_against_output(''.join(str(i) for i in amount_list), v_output) def get_amount(self): """ Gets amount from amount picker :return: str """ self.ew.wait_till_element_is_visible(self.AMOUNT_INPUT, 5) if PLATFORM == "Android": return self.ew.get_text_of_element(self.AMOUNT_INPUT) else: amount = self.ew.get_attribute(self.AMOUNT_INPUT, "name") if amount.startswith("+"): amount = amount[1:] return amount def get_wallet_amount(self): """ Gets wallet's amount when category has different currency :return: str """ self.ew.wait_till_element_is_visible(self.AMOUNT_INPUT, 5) try: if PLATFORM == "Android": return self.ew.get_text_of_element(self.WALLET_AMOUNT) else: return self.ew.get_attribute(self.WALLET_AMOUNT, "name") except NoSuchElementException: return None def set_currency(self, currency): """ Selects currency :param currency: str """ if currency == "random": currency = random.choice(vs.accessible_currencies) self.ew.wait_and_tap_element(self.CURRENCY, 5) self.ew.wait_and_tap_element(f"Currency {currency}", 10) self.set_exchange_rate() vr.validate_input_against_output(currency, self.get_currency()) def get_currency(self): """ Gets selected currency :return: str """ self.ew.wait_till_element_is_visible(self.CURRENCY, 5) if PLATFORM == "Android": return self.ew.get_attribute(self.SELECTED_CURRENCY_ANDROID, "content-desc") else: return self.ew.get_attribute(self.CURRENCY, "name") def set_exchange_rate(self): self.ew.wait_and_tap_element(self.CONFIRM_BUTTON, 10) def set_wallet(self, wallet, type_of_wallet): """ Selects requested wallet from requested wallet picker :param wallet: str :param type_of_wallet: str """ selected_wallet = self.get_wallet(type_of_wallet) if type_of_wallet == "transaction": self.ew.wait_and_tap_element(self.WALLET, 5) elif type_of_wallet == "transfer_outgoing": self.ew.wait_and_tap_element(self.OUTGOING_WALLET, 5) elif type_of_wallet == "transfer_incoming": self.ew.wait_and_tap_element(self.INCOMING_WALLET, 5) self.ew.wait_till_element_is_visible(self.WALLET_PICKER, 5) wallets_in_picker = self.get_wallets_in_picker() if wallet == "random": wallet = random.choice(wallets_in_picker) if PLATFORM == "Android": self.ew.tap_element(wallet) else: self.ew.tap_element(f'label == "{wallet}"') elif wallet == "different": wallets_in_picker.remove(selected_wallet) wallet = random.choice(wallets_in_picker) if PLATFORM == "Android": self.ew.tap_element(wallet) else: self.ew.tap_element(f'label == "{wallet}"') elif wallet == "oos": for i in wallets_in_picker: if i.startswith('Out of Spendee'): postfix_oos = i.split('-')[1] wallet = f"Out of Spendee-{postfix_oos}" if PLATFORM == "Android": self.ew.tap_element(wallet) else: self.ew.tap_element(f'label == "{wallet}"') elif wallet == "not_oos": if self.ew.is_element_present("Out of Spendee-false"): wallets_in_picker.remove("Out of Spendee-false") elif self.ew.is_element_present("Out of Spendee-true"): wallets_in_picker.remove("Out of Spendee-true") wallet = random.choice(wallets_in_picker) if PLATFORM == "Android": self.ew.tap_element(wallet) else: self.ew.tap_element(f'label == "{wallet}"') else: if PLATFORM == "Android": self.ew.tap_element(wallet) else: self.ew.tap_element(f'label == "{wallet}"') self.ew.wait_till_element_is_not_visible(self.WALLET_PICKER, 5) if self.ew.is_element_present(self.CONFIRM_BUTTON): self.set_exchange_rate() v_input = wallet.split('-')[0] vr.validate_input_against_output(v_input, self.get_wallet(type_of_wallet)) def get_wallet(self, type_of_wallet): """ Gets wallet name from requested wallet picker :param type_of_wallet: str :return: str """ if PLATFORM == "Android": if type_of_wallet == "transaction": self.ew.wait_till_element_is_visible( self.SELECTED_WALLET_ANDROID, 5) return self.ew.get_text_of_element( self.SELECTED_WALLET_ANDROID) elif type_of_wallet == "transfer_outgoing": self.ew.wait_till_element_is_visible( self.SELECTED_OUTGOING_WALLET_ANDROID, 5) return self.ew.get_text_of_element( self.SELECTED_OUTGOING_WALLET_ANDROID) elif type_of_wallet == "transfer_incoming": self.ew.wait_till_element_is_visible( self.SELECTED_INCOMING_WALLET_ANDROID, 5) return self.ew.get_text_of_element( self.SELECTED_INCOMING_WALLET_ANDROID) else: if type_of_wallet == "transaction": self.ew.wait_till_element_is_visible(self.WALLET, 5) return self.ew.get_attribute(self.WALLET, "name") elif type_of_wallet == "transfer_outgoing": self.ew.wait_till_element_is_visible(self.OUTGOING_WALLET, 5) return self.ew.get_attribute(self.OUTGOING_WALLET, "name") elif type_of_wallet == "transfer_incoming": self.ew.wait_till_element_is_visible(self.INCOMING_WALLET, 5) return self.ew.get_attribute(self.INCOMING_WALLET, "name") def get_wallets_in_picker(self): """ Gets wallets names visible inside picker :return: list of str """ if PLATFORM == "Android": return self.ew.get_attributes(self.WALLET_ITEM, "content-desc") else: return self.ew.get_attributes(self.WALLET_ITEM, "label") def set_start_date(self, start_date): """ Sets start date :param start_date: str """ if start_date == "random": start_date = str( datetime.date(int(datetime.date.today().year), random.randint(1, 12), random.randint(1, 28))) elif start_date == "past": start_date = str(datetime.date.today() - datetime.timedelta(days=random.randint(1, 30))) elif start_date == "future": start_date = str(datetime.date.today() + datetime.timedelta(days=random.randint(1, 30))) elif start_date == "today": start_date = str(datetime.date.today()) elif start_date == "yesterday": start_date = str(datetime.date.today() - datetime.timedelta(days=1)) elif start_date == "tomorrow": start_date = str(datetime.date.today() + datetime.timedelta(days=1)) self.ew.wait_and_tap_element(self.START_DATE, 5) self.ew.wait_till_element_is_visible(self.CALENDAR_PICKER, 5) self.set_calendar_month_year(start_date) self.set_calendar_day(start_date) vr.validate_input_against_output(start_date, self.get_date("start")) def set_calendar_month_year(self, date): """ Swipes to requested month and year inside date picker :param date: str """ year, month, day = (int(x) for x in date.split('-')) if PLATFORM == "Android": month_in_app = vs.calendar_months[self.ew.get_text_of_element( self.ACTUAL_MONTH_YEAR).split(" ")[0]] year_in_app = int( self.ew.get_text_of_element( self.ACTUAL_MONTH_YEAR).split(" ")[1]) else: month_in_app = vs.calendar_months[self.ew.get_attribute( self.ACTUAL_MONTH_YEAR, "label").split(" ")[0]] year_in_app = int( self.ew.get_attribute(self.ACTUAL_MONTH_YEAR, "label").split(" ")[1]) direction = None if (year > year_in_app) or (year == year_in_app and month > month_in_app): direction = "up" elif (year < year_in_app) or (year == year_in_app and month < month_in_app): direction = "down" iterations = abs((year - year_in_app) * 12 + (month - month_in_app)) res = self.rs.get_resolution() if PLATFORM == "Android": if direction == "up": for i in range(iterations): self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["calendar_picker_up_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["calendar_picker_up_y_end"]) \ .release().perform() elif direction == "down": for i in range(iterations): for d in range(2): self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["calendar_picker_down_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["calendar_picker_down_y_end"]) \ .release().perform() elif PLATFORM == "iOS": if direction == "up": for i in range(iterations): self.driver.execute_script( "mobile: dragFromToForDuration", { "duration": "0.1", "fromX": self.rs.all_resolutions[f"{res}"]["x"], "fromY": self.rs.all_resolutions[f"{res}"] ["calendar_picker_up_y_start"], "toX": self.rs.all_resolutions[f"{res}"]["x"], "toY": self.rs.all_resolutions[f"{res}"] ["calendar_picker_up_y_end"] }) elif direction == "down": for i in range(iterations): self.driver.execute_script( "mobile: dragFromToForDuration", { "duration": "0.1", "fromX": self.rs.all_resolutions[f"{res}"]["x"], "fromY": self.rs.all_resolutions[f"{res}"] ["calendar_picker_down_y_start"], "toX": self.rs.all_resolutions[f"{res}"]["x"], "toY": self.rs.all_resolutions[f"{res}"] ["calendar_picker_down_y_end"] }) def set_calendar_day(self, date): """ Selects requested day inside date picker :param date: str """ if PLATFORM == "Android": year, month, day = (int(x) for x in date.split('-')) if date == str(datetime.date.today()): self.ew.tap_element( f"today {datetime.date(year, month, day).strftime('%A')} {datetime.date(year, month, day).strftime('%B')} {day} selected You have no entries for this day " ) else: self.ew.tap_element( f" {datetime.date(year, month, day).strftime('%A')} {datetime.date(year, month, day).strftime('%B')} {day} " ) elif PLATFORM == "iOS": self.ew.wait_and_tap_element( f"native.calendar.SELECT_DATE_SLOT-{date}", 10) def get_date(self, type_of_date): """ Gets selected date :param type_of_date: str """ is_transaction = self.ew.is_element_present( self.TRANSACTION_HEADER_TITLE) if type_of_date == "start": date_ios = self.START_DATE if is_transaction: date_android = self.SELECTED_START_DATE_ANDROID else: date_android = self.SELECTED_START_DATE_ANDROID_BUDGET else: date_ios = self.END_DATE if is_transaction: date_android = self.SELECTED_END_DATE_ANDROID else: date_android = self.SELECTED_END_DATE_ANDROID_BUDGET try: if PLATFORM == "Android": try: self.ew.wait_till_element_is_visible(date_android, 5) except NoSuchElementException: if type_of_date == "start": if is_transaction: date_android = self.SELECTED_START_DATE_ANDROID_2 else: date_android = self.SELECTED_START_DATE_ANDROID_BUDGET_2 else: if is_transaction: date_android = self.SELECTED_END_DATE_ANDROID_2 else: date_android = self.SELECTED_END_DATE_ANDROID_BUDGET_2 date_in_app = self.ew.get_text_of_element(date_android) else: self.ew.wait_till_element_is_visible(date_ios, 5) date_in_app = self.ew.get_attribute(date_ios, "name") except (NoSuchElementException, AttributeError): return None if date_in_app == "Today" or date_in_app == "Yesterday?": date = str(datetime.date.today()) elif date_in_app == "Yesterday": date = str(datetime.date.today() - datetime.timedelta(days=1)) elif date_in_app == "Tomorrow": date = str(datetime.date.today() + datetime.timedelta(days=1)) elif date_in_app is None or date_in_app == "Never": return None else: try: month, day, year = (str(x) for x in date_in_app.split(' ')) day = day.replace(",", "") except ValueError: month, day = (str(x) for x in date_in_app.split(' ')) year = str(datetime.date.today().year) month = str(datetime.datetime.strptime(month, "%B").month).zfill(2) date = f"{year}-{month}-{day.zfill(2)}" return date def set_note(self, note): """ Insert note into note input :param note: str """ if note == "random": note = ''.join([ random.choice(string.ascii_lowercase + string.digits) for n in range(0, 8) ]) self.ew.wait_till_element_is_visible(self.NOTE_ELEMENT, 5) self.ew.get_element(self.NOTE).send_keys(note) if self.driver.is_keyboard_shown(): self.ew.tap_element(self.NOTE_ELEMENT) vr.validate_input_against_output(note, self.get_note()) def get_note(self): """ Gets note from note picker :return: str """ try: if PLATFORM == "Android": note = self.ew.get_text_of_element(self.NOTE) if note == "Write a note": note = "" return note else: return self.ew.get_text_of_elements(self.SELECTED_NOTE_IOS)[2] except IndexError: return None def set_label(self, label): """ Selects label from visible labels, if there is no requested label, it creates one :param label: str """ self.ew.wait_till_element_is_visible(self.LABELS, 5) if label == "random": if self.ew.is_element_present(self.LABEL_ITEM): labels = self.get_labels(False) label = random.choice(labels) if PLATFORM == "Android": self.ew.tap_element(label) time.sleep(0.5) else: i = labels.index(label) self.action.tap(self.ew.get_elements( self.LABEL_ITEM)[i]).perform() vr.validate_input_against_more_outputs(label, self.get_labels(True)) else: self.create_label(label) else: if PLATFORM == "Android": if self.ew.is_element_present(label): self.ew.tap_element(label) time.sleep(0.5) vr.validate_input_against_more_outputs( label, self.get_labels(True)) else: self.create_label(label) else: labels = self.get_labels(False) if label in labels: i = labels.index(label) self.action.tap(self.ew.get_elements( self.LABEL_ITEM)[i]).perform() vr.validate_input_against_more_outputs( label, self.get_labels(True)) else: self.create_label(label) def fast_select_labels(self, number): """ Selects more labels on transaction detail screen :param number: int """ self.ew.wait_till_element_is_visible(self.LABELS, 5) if self.ew.is_element_present(self.LABEL_ITEM): labels = self.get_labels(False) x = 0 for i in labels: x = x + 1 if x <= number: if PLATFORM == "Android": self.ew.tap_element(i) time.sleep(0.5) else: label = labels.index(i) self.action.tap( self.ew.get_elements( self.LABEL_ITEM)[label]).perform() def create_label(self, name): """ Creates labels on label picker :param name: str :return: """ if name == "random": name = ''.join([ random.choice(string.ascii_lowercase + string.digits) for n in range(0, 8) ]) self.ew.tap_element(self.LABELS) self.ew.wait_and_tap_element(self.LABEL_INPUT, 5) self.ew.get_element(self.LABEL_INPUT).send_keys(name) self.ew.wait_and_tap_element(self.NON_EXISTING_LABEL, 5) self.ew.tap_element(self.BACK_BUTTON) vr.validate_input_against_more_outputs(name, self.get_labels(True)) def get_labels(self, only_selected): """ Returns all visible or only selected labels :param only_selected: bool :return: list of str """ self.ew.wait_till_element_is_visible(self.LABELS, 5) if PLATFORM == "Android": if only_selected: labels = self.ew.get_text_of_elements( self.SELECTED_LABELS_ANDROID) else: labels = self.ew.get_text_of_elements( self.VISIBLE_LABELS_ANDROID) else: attributes = self.ew.get_attributes(self.VISIBLE_LABELS_IOS, "name") labels = [] for i in attributes: if only_selected: if i.endswith("false") is False: labels.append(i.split("-")[0]) else: labels.append(i.split("-")[0]) return labels def set_photo(self): """Selects photo""" self.ew.wait_and_tap_element(self.PHOTO, 5) self.ew.wait_and_tap_element(self.CHOOSE_PHOTO, 5) if self.ew.is_element_present(self.ALLOW_PHOTO_ACCESS_ANDROID): self.ew.tap_element(self.ALLOW_PHOTO_ACCESS_ANDROID) if PLATFORM == "Android": self.ew.wait_and_tap_element(self.PHOTO_FOLDER, 5) self.ew.wait_and_tap_element(self.PHOTO_ITEM, 5) vr.validate_input_against_output(True, self.get_photo()) def get_photo(self): """ Returns true if photo is selected :return: bool """ try: self.ew.wait_till_element_is_visible(self.PHOTO, 5) self.ew.wait_till_element_is_visible(self.SELECTED_PHOTO, 3) except: NoSuchElementException() return self.ew.is_element_present(self.SELECTED_PHOTO) def set_recurrence(self, recurrence): """ Swipes to and selects requested recurrence :param recurrence: string """ if recurrence == "random": recurrence = random.choice(vs.recurrences) self.ew.wait_and_tap_element(self.RECURRENCE, 5) self.ew.wait_till_element_is_visible(self.RECURRENCE_PICKER, 5) res = self.rs.get_resolution() if PLATFORM == "Android": item_visible = self.ew.is_element_present(recurrence) while item_visible is False: self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["default_picker_up_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["default_picker_up_y_end"]) \ .release().perform() item_visible = self.ew.is_element_present(recurrence) self.ew.wait_and_tap_element(recurrence, 5) else: item_visible = self.ew.get_attribute(recurrence, "visible") while item_visible == "false": self.driver.execute_script( "mobile: dragFromToForDuration", { "duration": "0.1", "fromX": self.rs.all_resolutions[f"{res}"]["x"], "fromY": self.rs.all_resolutions[f"{res}"] ["default_picker_up_y_start"], "toX": self.rs.all_resolutions[f"{res}"]["x"], "toY": self.rs.all_resolutions[f"{res}"] ["default_picker_up_y_end"] }) item_visible = self.ew.get_attribute(recurrence, "visible") self.driver.execute_script( "mobile: tap", { "x": 100, "y": 50, "element": self.ew.get_element(recurrence) }) vr.validate_input_against_output(recurrence, self.get_recurrence()) def get_recurrence(self): """ Gets selected recurrence :return: str """ try: self.ew.wait_till_element_is_visible(self.RECURRENCE, 5) if PLATFORM == "Android": try: recurrence = self.ew.get_text_of_element( self.SELECTED_RECURRENCE_ANDROID).lower() except AttributeError: recurrence = self.ew.get_text_of_element( self.SELECTED_RECURRENCE_ANDROID_EDIT).lower() else: recurrence = self.ew.get_attribute(self.RECURRENCE, "name").lower() if recurrence != "never" and PLATFORM == "Android": recurrences_in_app = [ "every day", "every 2 days", "every work day", "every week", "every 2 weeks", "every 4 weeks", "every month", "every 2 months", "every 3 months", "every 6 months", "every year" ] recurrence = vs.recurrences[recurrences_in_app.index( recurrence)] return recurrence except (AttributeError, NoSuchElementException): return None def set_end_date(self, end_date): """ Selects end date from date picker :param end_date: str """ start_date = self.get_date("start") year_start, month_start, day_start = (int(x) for x in start_date.split('-')) start_date = datetime.date(year_start, month_start, day_start) if end_date == "random": end_date = str(start_date + datetime.timedelta(days=random.randint(1, 30))) elif end_date == "day_after_start_date": end_date = str(start_date + datetime.timedelta(days=1)) else: year_end, month_end, day_end = (int(x) for x in end_date.split('-')) end_date = datetime.date(year_end, month_end, day_end) if start_date < end_date: end_date = str(end_date) else: raise ValueError( f"endDate {end_date} is not older than start_date {str(start_date)}" ) self.ew.wait_and_tap_element(self.END_DATE, 5) self.ew.wait_till_element_is_visible(self.CALENDAR_PICKER, 5) self.set_calendar_month_year(end_date) self.set_calendar_day(end_date) vr.validate_input_against_output(end_date, self.get_date("end")) def set_reminder(self, reminder): """ Swipes to and selects requested reminder :param reminder: str """ if reminder == "random": reminder = random.choice(vs.reminders) self.ew.wait_and_tap_element(self.REMINDER, 5) self.ew.wait_till_element_is_visible(self.REMINDER_PICKER, 5) res = self.rs.get_resolution() if PLATFORM == "Android": item_visible = self.ew.is_element_present(reminder) while item_visible is False: self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["default_picker_up_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["default_picker_up_y_end"]) \ .release().perform() item_visible = self.ew.is_element_present(reminder) self.ew.wait_and_tap_element(reminder, 5) else: item_visible = self.ew.get_attribute(reminder, "visible") while item_visible == "false": self.driver.execute_script( "mobile: dragFromToForDuration", { "duration": "0.1", "fromX": self.rs.all_resolutions[f"{res}"]["x"], "fromY": self.rs.all_resolutions[f"{res}"] ["default_picker_up_y_start"], "toX": self.rs.all_resolutions[f"{res}"]["x"], "toY": self.rs.all_resolutions[f"{res}"] ["default_picker_up_y_end"] }) item_visible = self.ew.get_attribute(reminder, "visible") self.driver.execute_script("mobile: tap", { "x": 100, "y": 50, "element": self.ew.get_element(reminder) }) vr.validate_input_against_output(reminder, self.get_reminder()) def get_reminder(self): """ Gets selected reminder :return: str """ try: self.ew.wait_till_element_is_visible(self.REMINDER, 5) if PLATFORM == "Android": reminder = self.ew.get_text_of_element( self.SELECTED_REMINDER_ANDROID) else: reminder = self.ew.get_attribute(self.REMINDER, "name") if reminder != "Never": reminders_in_app = [ "On a transaction date", "1 day before", "2 days before", "3 days before", "4 days before", "5 days before", "6 days before", "7 days before" ] reminder = vs.reminders[reminders_in_app.index(reminder)] return reminder except (ValueError, NoSuchElementException): return None
class CategoryValidator: def __init__(self, driver): self.driver = driver self.action = TouchAction(self.driver) self.categories_general = CategoriesGeneral(self.driver) self.category_detail = CategoryDetail(self.driver) self.ew = ElementWrapper(self.driver) self.rs = Resolutions(self.driver) def get_all_attributes(self): """ Getting all attributes of category :return: dict """ all_attributes = { "name": self.category_detail.get_name(), "color": self.category_detail.get_color(), "image": self.category_detail.get_image() } return all_attributes def is_category_existing(self, attributes): """ Checking if category is visible in category list :param attributes: dict :return: bool """ category_locator = f"{attributes['name']}/" \ f"{attributes['color']}/" \ f"{attributes['image']}" print(f'ATTRIBUTES: {attributes}') print(f'LOCATOR: {category_locator}') android_timeout = time.time() + 30 ios_timeout = time.time() + 5 res = self.rs.get_resolution() is_category_present = self.ew.is_element_present(category_locator) while is_category_present is False: if PLATFORM == "Android": self.action.long_press(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["categories_y_start"]) \ .move_to(None, self.rs.all_resolutions[f"{res}"]["x"], self.rs.all_resolutions[f"{res}"]["categories_y_end"]) \ .release().perform() is_category_present = self.ew.is_element_present( category_locator) if time.time() > android_timeout: return False else: is_category_present = self.ew.is_element_present( category_locator) if time.time() > ios_timeout: return False return True def get_selected_categories(self): """ Gets all values of selected categories in merge process :return: tuple """ categories = self.ew.get_attributes( self.categories_general.CATEGORY_INFO, "content-desc") name1, color1, image1 = categories[0].split('/') attributes1 = {"name": name1, "color": color1, "image": image1} name2, color2, image2 = categories[1].split('/') attributes2 = {"name": name2, "color": color2, "image": image2} return (attributes1, attributes2)