class EmailPassword: EMAIL_INPUT = "Email Input" PASSWORD_INPUT = "Password Input" EXISTING_EMAIL_DIALOG = "Email Already In Use Dialog" LOGIN_BUTTON = "Login Button" SIGN_UP_BUTTON = "Sign Up Button" INVALID_CREDENTIALS_DIALOG = "Invalid Credentials Dialog" VALIDATION_ERROR_WARNING = "Validation Error Warning" def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) def set_email(self, email): """ Inserts email of user into email input :param email: str """ self.ew.wait_till_element_is_visible(self.EMAIL_INPUT, 5) self.ew.get_element(self.EMAIL_INPUT).send_keys(email) def set_password(self, password): """ Inserts password of user into password input :param password: str """ self.ew.wait_till_element_is_visible(self.PASSWORD_INPUT, 5) self.ew.get_element(self.PASSWORD_INPUT).send_keys(password)
class MainCurrency: CURRENCY_PICKER = "Select currency Picker" if PLATFORM == "Android": SELECTED_CURRENCY = '//android.view.ViewGroup[@content-desc="Main Currency"]/android.view.ViewGroup/android.widget.TextView[2]' else: SELECTED_CURRENCY = 'label == "Main Currency"' def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) def set_currency(self, currency): """ Selecting main currency of user :param currency: str """ if currency == "random": currency = random.choice(vs.accessible_currencies) self.ew.wait_and_tap_element(f"Currency {currency}", 10) self.ew.wait_till_element_is_not_visible(self.CURRENCY_PICKER, 10) def get_currency(self): """ Getting selected main currency :return: str """ self.ew.wait_till_element_is_visible(self.SELECTED_CURRENCY, 10) if PLATFORM == "Android": return self.ew.get_text_of_element(self.SELECTED_CURRENCY) else: return self.ew.get_attribute(self.SELECTED_CURRENCY, "name")
class BankSearchScreen(): SEARCH_INPUT = "Search Input" if PLATFORM == "Android": BANK_ITEM = "Bank Item" else: BANK_ITEM = 'label == "Bank Item"' BACK_BUTTON = "Back Button" def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) def search_bank_by_search_box(self, bank): """ Searches for a bank via search textbox :param bank: str """ if bank == "random": bank = "Fake Bank Simple" self.ew.get_element(self.SEARCH_INPUT).send_keys(bank) if PLATFORM == "Android": self.ew.wait_till_element_is_visible(bank, 15) else: self.ew.wait_till_element_is_visible( f'label == "Bank Item" AND name == "{bank}"', 15) if self.driver.is_keyboard_shown(): self.driver.hide_keyboard() self.ew.wait_and_tap_element(self.BANK_ITEM, 15)
class AdvancedGeneral: ADVANCED_HEADER = "Advanced Header" EXPORT = "Export" def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) self.export_general = ExportGeneral(self.driver) def go_to_export(self): """Opens export screen""" self.ew.wait_and_tap_element(self.EXPORT, 10) self.ew.wait_till_element_is_visible(self.export_general.EXPORT_HEADER, 10)
class PeriodFilter: if PLATFORM == "Android": PERIOD_FILTER_BUTTON = "Period Filter Button" else: PERIOD_FILTER_BUTTON = 'label == "Period Filter Button"' # PERIODS WEEK_PERIOD = "Week" MONTH_PERIOD = "Month" YEAR_PERIOD = "Year" ALL_TIME_PERIOD = "All Time" def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) def open_period_filter(self): """Opens period filter picker""" self.ew.wait_and_tap_element(self.PERIOD_FILTER_BUTTON, 20) def set_filter_period(self, period): """ Selects requested period on picker :param period: str """ self.open_period_filter() self.ew.wait_till_element_is_visible(period, 10) if PLATFORM == "Android": self.ew.tap_element(period) else: self.driver.execute_script("mobile: tap", { "x": 100, "y": 50, "element": self.ew.get_element(period) }) periods = { self.WEEK_PERIOD: "By weeks", self.MONTH_PERIOD: "By months", self.YEAR_PERIOD: "By years", self.ALL_TIME_PERIOD: "All time" } if PLATFORM == "Android": self.ew.wait_till_element_is_visible(periods[period], 10) else: actual_period = self.ew.get_attribute(self.PERIOD_FILTER_BUTTON, "name") while actual_period != periods[period]: time.sleep(0.5) actual_period = self.ew.get_attribute( self.PERIOD_FILTER_BUTTON, "name")
class WalletsGeneral: NAVIGATION_WALLETS = "Navigation Wallets" WALLETS_ANIMATED_HEADER = "Wallets Animated Header" ADD_WALLET_BUTTON = "Add Wallet Button" CONNECT_BANK_BUTTON = "Connect Bank Button" if PLATFORM == "Android": WALLET_ITEM = '//android.widget.ScrollView[@content-desc="Wallets List"]/android.view.ViewGroup/android.view.ViewGroup[1]' else: WALLET_ITEM = '(//XCUIElementTypeOther[@name="Wallets List"])[2]/XCUIElementTypeScrollView//XCUIElementTypeOther//XCUIElementTypeOther' def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) def go_to_wallets(self): """Opens Wallets navigation section""" self.ew.wait_and_tap_element(self.NAVIGATION_WALLETS, 30) self.ew.wait_till_element_is_visible(self.WALLETS_ANIMATED_HEADER, 30)
class WelcomeScreen: WELCOME_SCREEN = "Welcome Screen" SIGN_UP_WITH_EMAIL_BUTTON = "Sign Up With Email" LOGIN_WITH_EMAIL_BUTTON = "Login With Email" SIGN_IN_WITH_GOOGLE_BUTTON = "Sign In With Google" SIGN_IN_WITH_FACEBOOK = "Sign In With Facebook" SIGN_IN_WITH_APPLE = "Sign In With Apple" NOTIFICATIONS_ALERT = '“Spendee” Would Like to Send You Notifications' ALLOW_NOTIFICATIONS_BUTTON = "Allow" ALLOW_FB_LOGIN_BUTTON = 'label == "Continue"' def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) def open_sign_up_email_screen(self): """Opens sign up screen for registration via email and password""" self.ew.wait_and_tap_element(self.SIGN_UP_WITH_EMAIL_BUTTON, 30) def open_login_by_email_screen(self): """Opens login screen for login via email and password""" self.ew.wait_and_tap_element(self.LOGIN_WITH_EMAIL_BUTTON, 30) def open_login_by_facebook(self): """Opens sign in screen of Facebook OAuth""" self.ew.wait_and_tap_element(self.SIGN_IN_WITH_FACEBOOK, 30) if PLATFORM == "iOS": self.ew.wait_and_tap_element(self.ALLOW_FB_LOGIN_BUTTON, 15) def open_login_by_google(self): """Opens sign in screen of Google OAuth""" self.ew.wait_and_tap_element(self.SIGN_IN_WITH_GOOGLE_BUTTON, 30) if PLATFORM == "iOS": self.ew.wait_and_tap_element(self.ALLOW_FB_LOGIN_BUTTON, 15) def skip_notifications_alert(self): """Allows notifications on iOS if the dialog is present""" try: self.ew.wait_till_element_is_visible(self.WELCOME_SCREEN, 1) except NoSuchElementException: pass if PLATFORM == "iOS" and self.ew.is_element_present(self.NOTIFICATIONS_ALERT): self.ew.tap_element(self.ALLOW_NOTIFICATIONS_BUTTON)
class TimelineGeneral: ADD_TRANSACTION_BUTTON = "Add Transaction Button" OVERVIEW_BUTTON = "Overview Button" NAVIGATION_TIMELINE = "Navigation Timeline" SCHEDULED = "Scheduled" SCHEDULED_SCREEN = "Scheduled Screen" TRANSACTION_CATEGORY_PICKER = "Transaction Category Picker" TRANSACTION_SECTION = "Transaction Section" def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) def go_to_timeline(self): """Opens Timeline section""" self.ew.wait_and_tap_element(self.NAVIGATION_TIMELINE, 30) self.ew.wait_till_element_is_visible(self.ADD_TRANSACTION_BUTTON, 10) def open_transaction_create_screen(self): """Opens transaction create screen""" self.ew.wait_and_tap_element(self.NAVIGATION_TIMELINE, 30) self.ew.wait_and_tap_element(self.ADD_TRANSACTION_BUTTON, 30) self.ew.wait_till_element_is_visible(self.TRANSACTION_CATEGORY_PICKER, 15) def open_scheduled_section(self): """Opens Scheduled section""" self.ew.wait_and_tap_element(self.SCHEDULED, 30) self.ew.wait_till_element_is_visible(self.SCHEDULED_SCREEN, 5)
class UserProfile: # More About You CONTINUE_BUTTON = "Continue Button" MORE_ABOUT_YOU_HEADER = "More About You Header" # Profile if PLATFORM == "Android": USER_PROFILE = "User Profile" else: USER_PROFILE = 'label == "User Profile"' BACK_BUTTON = "Back Button" if PLATFORM == "Android": FIRST_NAME = "First Name Input" LAST_NAME = "Last Name Input" else: FIRST_NAME = "(//XCUIElementTypeTextField[@name='RNE__Input__text-input'])[1]" LAST_NAME = "(//XCUIElementTypeTextField[@name='RNE__Input__text-input'])[2]" def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) self.more_general = MoreGeneral(self.driver) def set_first_name(self, first_name): """ Inserts first name into name input :param first_name: str """ self.ew.wait_till_element_is_visible(self.FIRST_NAME, 5) self.ew.get_element(self.FIRST_NAME).send_keys(first_name) def set_last_name(self, last_name): """ Inserts last name into name input :param last_name: str """ self.ew.wait_till_element_is_visible(self.LAST_NAME, 5) self.ew.get_element(self.LAST_NAME).send_keys(last_name) def clear_first_name(self): """Deletes first name""" self.ew.get_element(self.FIRST_NAME).clear() def clear_last_name(self): """Deletes last name""" self.ew.get_element(self.LAST_NAME).clear() def get_full_name(self): """ Gets first and last name as full name :return: str """ first_name = self.ew.get_text_of_element(self.FIRST_NAME) last_name = self.ew.get_text_of_element(self.LAST_NAME) return f"{first_name} {last_name}" def save_user_profile(self): """Goes back to More section""" self.ew.tap_element(self.BACK_BUTTON) self.ew.wait_till_element_is_visible(self.more_general.MORE_HEADER, 10)
class MarketingDialog: MARKETING_DIALOG = "Marketing Dialog" AGREE_BUTTON = "Agree" DISAGREE_BUTTON = "Don't Agree" ALLOW_BUTTON = 'Allow' def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) def agree_with_marketing(self): """Clicks on agree button on marketing dialog""" self.ew.wait_till_element_is_visible(self.MARKETING_DIALOG, 20) self.ew.wait_and_tap_element(self.AGREE_BUTTON, 5) def disagree_with_marketing(self): """Clicks on disagree button on marketing dialog""" self.ew.wait_till_element_is_visible(self.MARKETING_DIALOG, 20) self.ew.wait_and_tap_element(self.DISAGREE_BUTTON, 5) def agree_with_ios_notifications(self): """Clicks on agree button on ios notifications dialog""" if self.ew.is_element_present(self.ALLOW_BUTTON): self.ew.wait_and_tap_element(self.ALLOW_BUTTON, 30)
class BankAccountsActions(): if PLATFORM == "Android": LOGIN_INPUT = '//android.webkit.WebView[@content-desc="Spendee"]/android.view.View[2]/android.view.View[2]/android.widget.EditText' PASSWORD_INPUT = '//android.webkit.WebView[@content-desc="Spendee"]/android.view.View[2]/android.view.View[3]/android.widget.EditText' else: LOGIN_INPUT = '//XCUIElementTypeOther[@name="Spendee"]/XCUIElementTypeTextField' PASSWORD_INPUT = '//XCUIElementTypeOther[@name="Spendee"]/XCUIElementTypeSecureTextField' CONTINUE_BUTTON = "Continue" def __init__(self, driver): self.driver = driver self.bank_accounts_general = BankAccountsGeneral(self.driver) self.bank_search_screen = BankSearchScreen(self.driver) self.ew = ElementWrapper(self.driver) def connect_bank_account(self, bank): """ Connects bank account :param bank: str """ self.ew.wait_and_tap_element( self.bank_accounts_general.CONNECT_BANK_ACCOUNT_BUTTON, 10) self.ew.wait_till_element_is_visible( self.bank_search_screen.SEARCH_INPUT, 30) self.bank_search_screen.search_bank_by_search_box(bank) self.ew.wait_till_element_is_visible(self.LOGIN_INPUT, 15) self.ew.get_element(self.LOGIN_INPUT).send_keys(vs.login_fake_bank) self.ew.get_element(self.PASSWORD_INPUT).send_keys( vs.password_fake_bank) if self.driver.is_keyboard_shown(): self.driver.hide_keyboard() self.ew.wait_and_tap_element(self.CONTINUE_BUTTON, 5) self.ew.wait_till_element_is_visible( self.bank_search_screen.SEARCH_INPUT, 120) self.ew.tap_element(self.bank_search_screen.BACK_BUTTON) self.ew.wait_till_element_is_visible( self.bank_accounts_general.CONNECT_BANK_ACCOUNT_BUTTON, 10)
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"))
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 CategoryActions: def __init__(self, driver): self.driver = driver self.category_detail = CategoryDetail(self.driver) self.categories_general = CategoriesGeneral(self.driver) self.ew = ElementWrapper(self.driver) self.more_general = MoreGeneral(self.driver) def open_category_create_screen(self): """Opens category create screen""" self.ew.wait_and_tap_element( self.categories_general.ADD_CATEGORY_BUTTON, 10) self.ew.wait_till_element_is_visible( self.category_detail.CATEGORY_HEADER, 10) def open_category(self): """Opens detail of category""" if self.ew.is_element_present( self.categories_general.CATEGORY_ITEM) is False: self.create_category(type_of_category="random", name="random", color="random", image="random") self.save_category() self.ew.wait_and_tap_element(self.categories_general.CATEGORY_ITEM, 10) self.ew.wait_till_element_is_visible( self.category_detail.CATEGORY_HEADER, 10) def create_category(self, type_of_category, name, color, image): """ Sets requested parameters of category inside category detail :param type_of_category: str :param name: str :param color: str :param image: str or int :return: """ self.categories_general.set_type(type_of_category) self.open_category_create_screen() self.category_detail.set_name(name) self.category_detail.set_color(color) self.category_detail.set_image(image) def save_category(self): """Clicks on save category button""" self.ew.wait_and_tap_element(self.category_detail.SAVE_CATEGORY_BUTTON, 10) self.ew.wait_till_element_is_visible( self.more_general.CATEGORIES_HEADER, 10) def confirm_merge(self): """Confirms merge of categories""" self.ew.wait_and_tap_element( self.categories_general.MERGE_CATEGORIES_BUTTON, 10) self.ew.wait_and_tap_element( self.categories_general.CONFIRM_MERGE_BUTTON, 10) self.ew.wait_till_element_is_visible( self.more_general.CATEGORIES_HEADER, 10) def edit_category(self, type_of_category, name, color, image): """ Sets requested attributes inside category detail :param type_of_category: str or None :param name: str or None :param color: str or None :param image: str or int or None """ self.categories_general.set_type(type_of_category) self.open_category() if name is not None: self.category_detail.set_name(name) if color is not None: self.category_detail.set_color(color) if image is not None: self.category_detail.set_image(image) def delete_category(self): """Deletes category""" self.ew.wait_and_tap_element(self.category_detail.TRASH_ICON, 10) self.ew.wait_and_tap_element(self.category_detail.DELETE_BUTTON, 10) self.ew.wait_till_element_is_visible( self.more_general.CATEGORIES_HEADER, 10) def merge_categories(self): """Selects 2 visible categories""" self.ew.wait_and_tap_element( self.categories_general.MERGE_CATEGORIES_BUTTON, 10) all_visible_categories = self.ew.get_attributes( self.categories_general.CATEGORY_INFO, "content-desc") self.ew.tap_element(all_visible_categories[0]) self.ew.tap_element(all_visible_categories[1])
class AuthenticationActions: def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) self.email_password = EmailPassword(self.driver) self.facebook = Facebook(self.driver) self.google = Google(self.driver) self.marketing_dialog = MarketingDialog(self.driver) self.more_general = MoreGeneral(self.driver) self.timeline_general = TimelineGeneral(self.driver) self.user_profile = UserProfile(self.driver) self.welcome_screen = WelcomeScreen(self.driver) def register_by_email(self, email, password): """ Goes through registration process by email and password :param email: str :param password: str """ self.welcome_screen.open_sign_up_email_screen() self.email_password.set_email(email) self.email_password.set_password(password) self.ew.tap_element(self.email_password.SIGN_UP_BUTTON) time.sleep(0.5) if PLATFORM == "iOS": self.marketing_dialog.agree_with_ios_notifications() def login_by_facebook(self, email, password): """ Goes through sign in process by Facebook :param email: str :param password: str """ self.welcome_screen.open_login_by_facebook() self.ew.wait_till_element_is_visible(self.facebook.FACEBOOK_HEADER, 30) if self.ew.is_element_present(self.facebook.COOKIES_ACCEPT_BUTTON): self.ew.tap_element(self.facebook.COOKIES_ACCEPT_BUTTON) self.ew.get_element(self.facebook.EMAIL_TEXT_BOX).send_keys(email) self.ew.get_element( self.facebook.PASSWORD_TEXT_BOX).send_keys(password) self.ew.wait_and_tap_element(self.facebook.LOGIN_BUTTON, 10) self.ew.wait_and_tap_element(self.facebook.CONTINUE_BUTTON, 20) if PLATFORM == "iOS": self.marketing_dialog.agree_with_ios_notifications() def login_by_email(self, email, password): """ Goes through login process by email and password :param email: str :param password: str """ self.welcome_screen.open_login_by_email_screen() self.email_password.set_email(email) self.email_password.set_password(password) self.ew.tap_element(self.email_password.LOGIN_BUTTON) if PLATFORM == "iOS": self.marketing_dialog.agree_with_ios_notifications() def login_by_google(self): """Goes through sign in process by Google, when user was previously logged on device""" self.welcome_screen.open_login_by_google() self.ew.wait_and_tap_element(self.google.EMAIL_TO_SELECT, 20) def logout(self): """Logouts user from the application""" self.more_general.go_to_more_section() self.ew.swipe_if_element_not_present(self.more_general.LOGOUT_BUTTON) self.ew.tap_element(self.more_general.LOGOUT_BUTTON)
class TransactionActions: EXISTING_TRANSACTION = "Existing Item: regular-undefined" EXISTING_TRANSACTION_TEMPLATES = [ "Existing Item: regular-every day", "Existing Item: regular-every 2 days", "Existing Item: regular-every working day", "Existing Item: regular-every week", "Existing Item: regular-every 2 weeks", "Existing Item: regular-every 4 weeks", "Existing Item: regular-every month", "Existing Item: regular-every 2 months", "Existing Item: regular-every 3 months", "Existing Item: regular-every 6 months", "Existing Item: regular-every year" ] def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) self.timeline_general = TimelineGeneral(self.driver) self.transaction_detail = TransactionDetail(self.driver) self.transfer_destination_modal = TransferDestinationModal(self.driver) def create_transaction(self, transaction_type, category, amount, currency, wallet, start_date, note, label, photo, recurrence, end_date, reminder): """ Opens create transaction screen and sets requested attributes :param transaction_type: str or None :param category: str or None :param amount: str or None :param currency: str or None :param wallet: str or None :param start_date: str or None :param note: str or None :param label: str or None :param photo: bool :param recurrence: str or None :param end_date: str or None :param reminder: str or None """ self.timeline_general.open_transaction_create_screen() if transaction_type is not None: self.transaction_detail.set_type_of_transaction(transaction_type) self.transaction_detail.set_category(category) self.transaction_detail.set_amount(amount) if currency is not None: self.transaction_detail.set_currency(currency) if wallet is not None: self.transaction_detail.set_wallet(wallet, "transaction") if start_date is not None: self.transaction_detail.set_start_date(start_date) if note is not None: self.transaction_detail.set_note(note) if label is not None: self.transaction_detail.set_label(label) if photo is not None: self.transaction_detail.set_photo() if recurrence is not None: self.ew.wait_till_element_is_visible( self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) self.ew.swipe_if_element_not_present( self.transaction_detail.RECURRENCE) self.transaction_detail.set_recurrence(recurrence) if end_date is not None: self.ew.wait_till_element_is_visible( self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) self.ew.swipe_if_element_not_present( self.transaction_detail.END_DATE) self.transaction_detail.set_end_date(end_date) if reminder is not None: self.ew.wait_till_element_is_visible( self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) self.ew.swipe_if_element_not_present( self.transaction_detail.REMINDER) self.transaction_detail.set_reminder(reminder) self.ew.wait_till_element_is_visible( self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) def save_transaction(self): """Clicks on save transaction button""" self.ew.wait_and_tap_element( self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) if self.transfer_destination_modal.is_destination_modal_present( ) or self.transfer_destination_modal.is_origination_modal_present(): self.transfer_destination_modal.create_as_new_transaction() def open_transaction(self): """Opens existing transaction, if there is no one, it creates transaction""" self.ew.wait_till_element_is_visible( self.timeline_general.OVERVIEW_BUTTON, 30) self.timeline_general.go_to_timeline() if self.ew.is_element_present(self.EXISTING_TRANSACTION) is False: self.create_transaction(transaction_type="random", category="random", amount="random", currency=None, wallet=None, start_date=None, note=None, label=None, photo=None, recurrence=None, end_date=None, reminder=None) self.save_transaction() self.ew.wait_till_element_is_visible( self.timeline_general.NAVIGATION_TIMELINE, 30) self.ew.wait_and_tap_element(self.EXISTING_TRANSACTION, 15) self.ew.wait_till_element_is_visible( self.transaction_detail.TRANSACTION_HEADER_TITLE, 15) def open_transaction_template(self): """Opens existing transaction template, if there is no one, it creates transaction""" self.ew.wait_till_element_is_visible( self.timeline_general.TRANSACTION_SECTION, 60) if self.ew.is_element_present(self.timeline_general.SCHEDULED) is True: self.timeline_general.open_scheduled_section() for i in self.EXISTING_TRANSACTION_TEMPLATES: if self.ew.is_element_present(i): self.ew.tap_element(i) break elif i == "Existing Item: regular-every year": self.create_transaction(transaction_type="random", category="random", amount="random", currency=None, wallet=None, start_date=None, note=None, label=None, photo=None, recurrence="random", end_date=None, reminder=None) self.save_transaction() self.timeline_general.open_scheduled_section() for i in self.EXISTING_TRANSACTION_TEMPLATES: if self.ew.is_element_present(i): self.ew.tap_element(i) else: self.create_transaction(transaction_type="random", category="random", amount="random", currency=None, wallet=None, start_date=None, note=None, label=None, photo=None, recurrence="random", end_date=None, reminder=None) self.save_transaction() self.timeline_general.open_scheduled_section() for i in self.EXISTING_TRANSACTION_TEMPLATES: if self.ew.is_element_present(i): self.ew.tap_element(i) def edit_transaction(self, transaction_type, category, amount, wallet, start_date, note, label, photo, recurrence, end_date, reminder): """Edits requested attributes on transaction detail screen :param transaction_type: str or None :param category: str or None :param amount: str or None :param wallet: str or None :param start_date: str or None :param note: str or None :param label: str or None :param photo: bool :param recurrence: str or None :param end_date: str or None :param reminder: str or None """ if transaction_type is not None: self.ew.wait_and_tap_element(self.transaction_detail.CATEGORY_ICON, 10) if transaction_type == "transfer": self.transaction_detail.set_type_to_transfer() else: self.transaction_detail.set_type_of_transaction( transaction_type) self.transaction_detail.set_category("random") if category is not None: self.ew.wait_and_tap_element(self.transaction_detail.CATEGORY_ICON, 10) self.transaction_detail.set_category(category) if amount is not None: self.ew.wait_and_tap_element(self.transaction_detail.AMOUNT_INPUT, 10) self.ew.wait_till_element_is_visible( self.transaction_detail.NUMPAD_CLEAR, 10) for i in range(6): self.ew.tap_element(self.transaction_detail.NUMPAD_CLEAR) self.transaction_detail.set_amount(amount) if wallet is not None: self.transaction_detail.set_wallet(wallet, "transaction") if start_date is not None: self.transaction_detail.set_start_date(start_date) if note is not None: try: self.ew.wait_till_element_is_visible( self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) self.ew.get_element( self.transaction_detail.EXISTING_NOTE).clear() except NoSuchElementException: pass self.transaction_detail.set_note(note) if label is not None: self.transaction_detail.set_label(label) if photo is not None: self.transaction_detail.set_photo() if recurrence is not None: self.ew.wait_till_element_is_visible( self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) self.ew.swipe_if_element_not_present( self.transaction_detail.RECURRENCE) self.transaction_detail.set_recurrence(recurrence) if end_date is not None: self.ew.wait_till_element_is_visible( self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) self.ew.swipe_if_element_not_present( self.transaction_detail.END_DATE) self.transaction_detail.set_end_date(end_date) if reminder is not None: self.ew.wait_till_element_is_visible( self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) self.ew.swipe_if_element_not_present( self.transaction_detail.REMINDER) self.transaction_detail.set_reminder(reminder) self.ew.wait_till_element_is_visible( self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) def delete_transaction(self): """Deletes transaction from transaction detail screen""" self.ew.wait_and_tap_element(self.transaction_detail.TRASH_ICON, 10) self.ew.wait_and_tap_element(self.transaction_detail.DELETE_BUTTON, 10)
class CategoryDetail: CATEGORY_HEADER = "Category Header" SELECTED_ATTRIBUTES = '//android.view.ViewGroup[@content-desc="Category Icon"]/android.view.ViewGroup' SAVE_CATEGORY_BUTTON = "Save Category Button" TRASH_ICON = "Trash Icon" DELETE_BUTTON = "Delete" # NAME NAME_INPUT = "Name Input" SELECTED_NAME_IOS = '**/XCUIElementTypeTextField[`label == "Name Input"`]' def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) def set_name(self, name): """ Insets 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 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_color(self, color): """ Selects color from visible colors :param color: str """ if color == "random": color = random.choice(vs.accessible_colors) self.ew.wait_and_tap_element(color, 5) vr.validate_input_against_output(color, self.get_color()) def get_color(self): """ Gets #rgb of selected color :return: str """ self.ew.wait_till_element_is_visible(self.SELECTED_ATTRIBUTES, 5) name, color, image = self.ew.get_attribute(self.SELECTED_ATTRIBUTES, 'content-desc').split('/') return color def set_image(self, image): """ Sets image from visible images :param image: str or int """ if image == "random": image = random.randrange(1, 20) self.ew.wait_and_tap_element(image, 5) vr.validate_input_against_output(str(image), self.get_image()) def get_image(self): """ Gets id of selected image :return: str """ self.ew.wait_till_element_is_visible(self.SELECTED_ATTRIBUTES, 5) name, color, image = self.ew.get_attribute(self.SELECTED_ATTRIBUTES, 'content-desc').split('/') return image
class WalletDetail: # OTHER WALLET_HEADER = "Wallet Header" SAVE_WALLET_BUTTON = "Save Wallet 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 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 Subtraction" } NUMPAD_BACKDROP = "Numpad Backdrop" NUMPAD_CLEAR = "Numpad Clear" if PLATFORM == "Android": AMOUNT_INPUT = "Amount Input" else: AMOUNT_INPUT = '**/XCUIElementTypeOther[`label == "Amount Input"`][2]' SELECTED_AMOUNT = "Currency Input" # 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"' # CATEGORIES CATEGORIES_HEADER = "Categories Header" BACK_BUTTON = "Back Button" EYE_ICON = "Eye Icon" if PLATFORM == "Android": CATEGORIES = "Categories" EYE_ICON = "Eye Icon" 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: CATEGORIES = 'label == "Categories"' EYE_ICON = 'label == "Eye Icon"' # SHARING SHARE_WALLET_BUTTON = "Share Wallet Button" if PLATFORM == "Android": DENY_BUTTON = 'com.android.packageinstaller:id/permission_deny_button' else: DENY_BUTTON = 'Don’t Allow' def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) def set_name(self, name): """ Inserting 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) if self.driver.is_keyboard_shown(): self.driver.hide_keyboard() vr.validate_input_against_output(name, self.get_name()) def get_name(self): """ Getting name 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): """ Inserting amount into balance input :param amount: str """ if amount == "random": amount = str(random.randint(-99, 99)) elif amount == "random_positive": amount = str(random.randint(1, 99)) elif amount == "random_negative": amount = str(random.randint(-99, -1)) 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): """ Getting amount from balance 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): """ Selecting currency of wallet :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): """ Getting selected currency of wallet :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_categories(self, categories): """ Selecting visible categories of wallet :param categories: "random" or int """ if PLATFORM == "Android": v_input = self.get_categories() self.ew.wait_and_tap_element(self.CATEGORIES, 5) self.ew.wait_till_element_is_visible(self.CATEGORIES_HEADER, 5) if categories == "random": categories = random.randint(1, 5) visible_categories = self.ew.get_elements(self.EYE_ICON) x = 0 for i in visible_categories: x = x + 1 if x <= categories: i.click() self.ew.wait_and_tap_element(self.BACK_BUTTON, 5) vr.validate_input_against_output( int(v_input) - categories, int(self.get_categories())) def get_categories(self): """ Getting number of visible categories of wallet :return: str """ self.ew.wait_till_element_is_visible(self.CATEGORIES, 5) time.sleep(1) 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 invite_user(self): """Opening invitation screen""" self.ew.wait_and_tap_element(self.SHARE_WALLET_BUTTON, 15)
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 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 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 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 TransferActions(): EXISTING_TRANSFER = "Existing Item: transfer-undefined" EXISTING_TRANSFER_TEMPLATES = ["Existing Item: transfer-every day", "Existing Item: transfer-every 2 days", "Existing Item: transfer-every working day", "Existing Item: transfer-every week", "Existing Item: transfer-every 2 weeks", "Existing Item: transfer-every 4 weeks", "Existing Item: transfer-every month", "Existing Item: transfer-every 2 months", "Existing Item: transfer-every 3 months", "Existing Item: transfer-every 6 months", "Existing Item: transfer-every year"] def __init__(self, driver): self.driver = driver self.ew = ElementWrapper(self.driver) self.timeline_general = TimelineGeneral(self.driver) self.transaction_actions = TransactionActions(self.driver) self.transaction_detail = TransactionDetail(self.driver) def create_transfer(self, amount, outgoing_wallet, incoming_wallet, start_date, note, recurrence, end_date, reminder): """ Opens create transfer screen and sets requested attributes :param amount: str or None :param outgoing_wallet: str or None :param incoming_wallet: str or None :param start_date: str or None :param note: str or None :param recurrence: str or None :param end_date: str or None :param reminder: str or None """ self.timeline_general.open_transaction_create_screen() self.transaction_detail.set_type_to_transfer() self.transaction_detail.set_amount(amount) if outgoing_wallet is not None: self.transaction_detail.set_wallet(outgoing_wallet, "transfer_outgoing") if incoming_wallet is not None: self.transaction_detail.set_wallet(incoming_wallet, "transfer_incoming") if start_date is not None: self.transaction_detail.set_start_date(start_date) if note is not None: self.transaction_detail.set_note(note) if recurrence is not None: self.transaction_detail.set_recurrence(recurrence) if end_date is not None: self.transaction_detail.set_end_date(end_date) if reminder is not None: self.transaction_detail.set_reminder(reminder) def open_transfer(self): """Opens existing transfer, if there is no one, it creates transfer""" self.timeline_general.go_to_timeline() self.ew.wait_till_element_is_visible(self.timeline_general.ADD_TRANSACTION_BUTTON, 30) print(self.ew.is_element_present(self.EXISTING_TRANSFER)) if self.ew.is_element_present(self.EXISTING_TRANSFER) is False: self.create_transfer(amount="random", outgoing_wallet=None, incoming_wallet=None, start_date=None, note=None, recurrence=None, end_date=None, reminder=None) self.transaction_actions.save_transaction() self.ew.wait_till_element_is_visible(self.timeline_general.NAVIGATION_TIMELINE, 30) self.ew.wait_and_tap_element(self.EXISTING_TRANSFER, 15) self.ew.wait_till_element_is_visible(self.transaction_detail.TRANSACTION_HEADER_TITLE, 15) def open_transfer_template(self): """Opens existing transfer template""" self.ew.wait_till_element_is_visible(self.timeline_general.TRANSACTION_SECTION, 60) if self.ew.is_element_present(self.timeline_general.SCHEDULED) is True: self.timeline_general.open_scheduled_section() for i in self.EXISTING_TRANSFER_TEMPLATES: if self.ew.is_element_present(i): self.ew.tap_element(i) break elif i == "Existing Item: transfer-every year": self.create_transfer(amount="random", outgoing_wallet=None, incoming_wallet=None, start_date=None, note=None, recurrence="random", end_date=None, reminder=None) self.transaction_actions.save_transaction() self.timeline_general.open_scheduled_section() for i in self.EXISTING_TRANSFER_TEMPLATES: if self.ew.is_element_present(i): self.ew.tap_element(i) else: self.create_transfer(amount="random", outgoing_wallet=None, incoming_wallet=None, start_date=None, note=None, recurrence="random", end_date=None, reminder=None) self.transaction_actions.save_transaction() self.timeline_general.open_scheduled_section() for i in self.EXISTING_TRANSFER_TEMPLATES: if self.ew.is_element_present(i): self.ew.tap_element(i) def edit_transfer(self, transaction_type, amount, outgoing_wallet, incoming_wallet, start_date, note, recurrence, end_date, reminder): """ Edits requested attributes on transfer detail screen :param transaction_type: str or None :param amount: str or None :param outgoing_wallet: str or None :param incoming_wallet: str or None :param start_date: str or None :param note: str or None :param recurrence: str or None :param end_date: str or None :param reminder: str or None """ if transaction_type is not None: self.ew.tap_element(self.transaction_detail.CATEGORY_ICON) if transaction_type == "transfer": self.transaction_detail.set_type_to_transfer() else: self.transaction_detail.set_type_of_transaction(transaction_type) self.transaction_detail.set_category("random") if amount is not None: self.ew.tap_element(self.transaction_detail.AMOUNT_INPUT) self.ew.wait_till_element_is_visible(self.transaction_detail.NUMPAD_CLEAR, 10) for i in range(6): self.ew.wait_and_tap_element(self.transaction_detail.NUMPAD_CLEAR, 5) self.transaction_detail.set_amount(amount) if outgoing_wallet is not None: if self.transaction_detail.get_wallet("transfer_outgoing") == "Out of Spendee": self.transaction_detail.set_wallet(outgoing_wallet, "transfer_outgoing") if incoming_wallet is not None: if self.transaction_detail.get_wallet("transfer_incoming") == "Out of Spendee": self.transaction_detail.set_wallet(incoming_wallet, "transfer_incoming") if start_date is not None: self.transaction_detail.set_start_date(start_date) if note is not None: try: self.ew.get_element(self.transaction_detail.EXISTING_NOTE).clear() except NoSuchElementException: pass self.transaction_detail.set_note(note) if recurrence is not None: self.transaction_detail.set_recurrence(recurrence) if end_date is not None: self.transaction_detail.set_end_date(end_date) if reminder is not None: self.ew.wait_till_element_is_visible(self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5) self.ew.swipe_if_element_not_present(self.transaction_detail.REMINDER) self.transaction_detail.set_reminder(reminder) self.ew.wait_till_element_is_visible(self.transaction_detail.SAVE_TRANSACTION_BUTTON, 5)