diff --git a/.github/workflows/p1p2-tests.yml b/.github/workflows/p1p2-tests.yml index 5188b8ba8..e27e281d0 100644 --- a/.github/workflows/p1p2-tests.yml +++ b/.github/workflows/p1p2-tests.yml @@ -4,6 +4,12 @@ name: Priority Escape Defects Tests on: + push: + branches-ignore: + - master # run on all branches except master + pull_request: + branches-ignore: + - master # ignore PRs targeting master workflow_dispatch: inputs: environment: @@ -67,6 +73,8 @@ jobs: DIMAGIQA_MAIL_USERNAME: ${{ secrets.DIMAGIQA_MAIL_USERNAME }} DIMAGIQA_MAIL_PASSWORD: ${{ secrets.DIMAGIQA_MAIL_PASSWORD }} DIMAGIQA_IMAP_PASSWORD: ${{secrets.DIMAGIQA_IMAP_PASSWORD}} + DIMAGIQA_BS_USER: ${{ secrets.DIMAGIQA_BS_USER }} + DIMAGIQA_BS_KEY: ${{ secrets.DIMAGIQA_BS_KEY }} run: | echo "client_payload: ${{ toJson(github.event.client_payload) }}" echo "matrix environment: ${{ matrix.environment }}" @@ -181,14 +189,14 @@ jobs: SLACK_WEBHOOK_URL = '${{ secrets.SLACK_WEBHOOK_URL_SMOKE }}'; SLACK_CHANNEL_ID = '${{ secrets.SLACK_CHANNEL_ID_SMOKE }}'; console.log("Staging Failure"); - } else if (CC_EVENT != 'repository_dispatch' && CC_ENV == 'india') { + } else if (CC_EVENT != 'repository_dispatch' && CC_ENV == 'india' && JOB_STATUS == 'failure') { SLACK_WEBHOOK_URL = '${{ secrets.SLACK_WEBHOOK_URL_SMOKE }}'; SLACK_CHANNEL_ID = '${{ secrets.SLACK_CHANNEL_ID_SMOKE }}'; console.log("India Failure"); - } else if (CC_EVENT != 'repository_dispatch' && CC_ENV == 'india' && CC_ENV == 'eu' && JOB_STATUS == 'failure') { + } else if (CC_EVENT != 'repository_dispatch' && CC_ENV == 'eu' && JOB_STATUS == 'failure') { SLACK_WEBHOOK_URL = '${{ secrets.SLACK_WEBHOOK_URL_SMOKE }}'; SLACK_CHANNEL_ID = '${{ secrets.SLACK_CHANNEL_ID_SMOKE }}'; - console.log("India Success"); + console.log("EU Trigger"); } else { SLACK_WEBHOOK_URL = ''; SLACK_CHANNEL_ID = ''; diff --git a/HQSmokeTests/testPages/android/android_screen.py b/HQSmokeTests/testPages/android/android_screen.py index 017b2bc6a..ee44dddff 100644 --- a/HQSmokeTests/testPages/android/android_screen.py +++ b/HQSmokeTests/testPages/android/android_screen.py @@ -111,6 +111,7 @@ def __init__(self, settings): self.form = "//android.widget.TextView[@text='" + UserData.new_form_name + "']" self.text_field = "//android.widget.EditText" self.submit_button = "//android.widget.TextView[@text='FINISH']" + self.log_out = "//android.widget.TextView[@text='Log out of CommCare']" def click_xpath(self, locator): element = self.driver.find_element(AppiumBy.XPATH, locator) @@ -156,5 +157,50 @@ def install_app_and_submit_form(self, code, random_text): self.driver.find_element(AppiumBy.XPATH, self.sync_button).click() time.sleep(3) + def verify_app_install(self, code): + time.sleep(10) + self.driver.find_element(AppiumBy.XPATH, self.enter_code).click() + self.driver.find_element(AppiumBy.ID, self.profile_code).send_keys(code) + self.driver.find_element(AppiumBy.ID, self.start_install).click() + time.sleep(3) + self.driver.find_element(AppiumBy.XPATH, self.install).click() + time.sleep(30) + assert self.driver.find_element(AppiumBy.XPATH, "//android.widget.TextView[@text='Welcome back! Please log in.']").is_displayed(), "App not installed" + print("App installed successfully") + + def verify_login_with_old_password(self, code, username, password): + time.sleep(10) + self.driver.find_element(AppiumBy.XPATH, self.enter_code).click() + self.driver.find_element(AppiumBy.ID, self.profile_code).send_keys(code) + self.driver.find_element(AppiumBy.ID, self.start_install).click() + time.sleep(3) + self.driver.find_element(AppiumBy.XPATH, self.install).click() + time.sleep(30) + assert self.driver.find_element(AppiumBy.XPATH, "//android.widget.TextView[@text='Welcome back! Please log in.']").is_displayed(), "App not installed" + print("App installed successfully") + self.driver.find_element(AppiumBy.ID, self.username).send_keys(username) + self.driver.find_element(AppiumBy.ID, self.password).send_keys(password) + self.driver.find_element(AppiumBy.ID, self.login).click() + time.sleep(40) + self.driver.find_element(AppiumBy.XPATH, self.log_out).click() + print("Successfully logged in and logged out with old password:", username, password) + time.sleep(3) + assert self.driver.find_element(AppiumBy.XPATH, + "//android.widget.TextView[@text='Welcome back! Please log in.']" + ).is_displayed(), "App not installed" + + def verify_login_with_new_password(self, username, password): + time.sleep(30) + assert self.driver.find_element(AppiumBy.XPATH, "//android.widget.TextView[@text='Welcome back! Please log in.']").is_displayed(), "App not installed" + print("Welcome screen present") + self.driver.find_element(AppiumBy.ID, self.username).send_keys(username) + self.driver.find_element(AppiumBy.ID, self.password).send_keys(password) + self.driver.find_element(AppiumBy.ID, self.login).click() + time.sleep(40) + self.driver.find_element(AppiumBy.XPATH, self.log_out).click() + print("Successfully logged in and logged out with new password :", username, password) + time.sleep(3) + + def close_android_driver(self): self.driver.quit() diff --git a/HQSmokeTests/testPages/applications/app_preview.py b/HQSmokeTests/testPages/applications/app_preview.py index 3a115a60e..b1bbc6c2d 100644 --- a/HQSmokeTests/testPages/applications/app_preview.py +++ b/HQSmokeTests/testPages/applications/app_preview.py @@ -85,8 +85,8 @@ def submit_form_with_loc(self): self.driver.switch_to.frame(self.find_element(self.iframe_app_preview)) self.login_as_app_preview() self.wait_to_click(self.start_option) - - self.wait_for_element((By.XPATH, self.case_list_menu.format(UserData.case_list_name))) + time.sleep(10) + self.wait_for_element((By.XPATH, self.case_list_menu.format(UserData.case_list_name)), 100) self.wait_to_click((By.XPATH, self.case_list_menu.format(UserData.case_list_name))) self.wait_for_element((By.XPATH, self.case_list_menu.format("Reg Form"))) @@ -105,18 +105,19 @@ def submit_form_with_loc(self): lat = self.get_text(self.latitude) lon = self.get_text(self.longitude) self.wait_to_click(self.next_question) - + + self.wait_for_element(self.complete_form, 60) self.wait_to_click(self.complete_form) - self.wait_for_element(self.success_message) + self.wait_for_element(self.success_message, 60) print("Form submitted") time.sleep(2) self.wait_for_element(self.home_button) self.js_click(self.home_button) - time.sleep(2) + time.sleep(5) self.wait_for_element(self.sync_button) self.js_click(self.sync_button) - time.sleep(5) + time.sleep(10) self.switch_to_default_content() print("Sleeping for sometime so the form data is updated") time.sleep(70) diff --git a/HQSmokeTests/testPages/applications/application_page.py b/HQSmokeTests/testPages/applications/application_page.py index 80d9272bc..23622ec24 100644 --- a/HQSmokeTests/testPages/applications/application_page.py +++ b/HQSmokeTests/testPages/applications/application_page.py @@ -83,6 +83,11 @@ def __init__(self, driver): self.advanced_settings_tab = (By.XPATH, "//a[@href='#commcare-settings']") self.advanced_settings_tab_content = (By.ID, "app-settings-options") self.form_settings_tab = (By.XPATH, "//a[@href='#form-settings']") + self.case_management_tab = (By.XPATH, "//a[@href='#case-configuration']") + self.user_properties = (By.XPATH, "//a[@href='#usercase-configuration']") + self.form_actions_tab = (By.XPATH, "//a[@href='#advanced']") + + # Form Field Edit self.add_new_form = (By.XPATH,"//a[@class='appnav-secondary js-add-new-item']") @@ -230,7 +235,7 @@ def app_settings_exploration(self): assert self.is_present_and_displayed(self.actions_tab_content) self.wait_to_click(self.add_ons_tab) assert self.is_present_and_displayed(self.add_ons_tab_content) - + self.wait_to_click(self.advanced_settings_tab) assert self.is_present_and_displayed(self.advanced_settings_tab_content) print("App Settings loading successfully!") @@ -251,7 +256,7 @@ def update_form_field(self): # self.wait_to_clear_and_send_keys(self.edit_form_name_text, UserData.new_form_name) # self.wait_to_click(self.form_name_save_button) # self.wait_to_click(self.add_questions) - # + # # self.wait_to_click(self.text_question) # self.send_keys(self.question_display_text, self.field_name) # assert self.is_present_and_displayed(self.app_created) @@ -267,7 +272,7 @@ def update_form_field(self): assert self.is_displayed(self.updates_text), "Fields not updated" print("Fields successfully updated") self.wait_to_click((By.XPATH, self.field_edit_app_name.format(UserData.reassign_cases_application))) - + self.wait_to_click(self.make_new_version_button) time.sleep(2) self.reload_page() @@ -290,7 +295,7 @@ def update_form_field(self): - def create_application_with_verifications(self): + def create_application_with_verifications(self, app_p1p2_name): time.sleep(2) self.switch_to_default_content() self.wait_for_element(self.applications_menu_id) @@ -298,7 +303,7 @@ def create_application_with_verifications(self): self.wait_to_click(self.new_application) self.wait_to_click(self.edit_app_name) self.clear(self.app_name_textbox) - self.send_keys(self.app_name_textbox, self.app_p1p2_name) + self.send_keys(self.app_name_textbox, app_p1p2_name) self.wait_to_click(self.confirm_change) self.wait_to_click(self.add_module) self.wait_to_click(self.add_case_list) @@ -314,7 +319,7 @@ def create_application_with_verifications(self): self.wait_to_click(self.edit_form_name_icon) self.wait_to_clear_and_send_keys(self.edit_form_name_text, self.reg_form_name) self.wait_to_click(self.form_name_save_button) - + assert self.check_for_html_char(self.get_text(self.reg_form_head_text)), "html characters are present" assert self.check_for_html_char(self.get_text(self.reg_form_variable_name)), "html characters are present" assert self.get_text(self.reg_form_head_text) == self.get_text(self.reg_form_variable_name) @@ -325,7 +330,7 @@ def create_application_with_verifications(self): self.send_keys(self.question_display_text, "Location") self.wait_to_clear_and_send_keys(self.question_ID_field, "location_id") self.wait_to_click(self.save_button) - + if self.is_present(self.override_btn): self.wait_to_click(self.override_btn) time.sleep(3) @@ -337,12 +342,12 @@ def create_application_with_verifications(self): self.wait_to_click(self.edit_form_name_icon) self.wait_to_clear_and_send_keys(self.edit_form_name_text, self.followup_form_name) self.wait_to_click(self.form_name_save_button) - + assert self.check_for_html_char(self.get_text(self.reg_form_head_text)), "html characters are present" assert self.check_for_html_char(self.get_text(self.reg_form_variable_name)), "html characters are present" assert self.get_text(self.reg_form_head_text) == self.get_text(self.reg_form_variable_name) self.wait_to_click(self.add_questions) - + self.wait_to_click(self.text_question) self.wait_for_element(self.question_display_text) self.send_keys(self.question_display_text, "Text") @@ -351,14 +356,15 @@ def create_application_with_verifications(self): self.wait_to_click(self.override_btn) time.sleep(3) self.hover_on_element((By.XPATH, self.form_link.format("Followup Form"))) - self.wait_to_click((By.XPATH, self.form_settings_btn.format("Followup Form"))) + self.wait_for_element((By.XPATH, self.form_settings_btn.format("Followup Form"))) + self.js_click((By.XPATH, self.form_settings_btn.format("Followup Form"))) time.sleep(2) assert self.is_present_and_displayed(self.form_settings_tab) - assert self.is_present_and_displayed((By.XPATH, self.app_created.format(self.app_p1p2_name))) + assert self.is_present_and_displayed((By.XPATH, self.app_created.format(app_p1p2_name))) print("New App created successfully!") - self.wait_to_click((By.XPATH, self.field_edit_app_name.format(self.app_p1p2_name))) - + self.wait_to_click((By.XPATH, self.field_edit_app_name.format(app_p1p2_name))) + self.wait_to_click(self.make_new_version_button) time.sleep(2) self.reload_page() @@ -366,7 +372,7 @@ def create_application_with_verifications(self): self.wait_to_click(self.release_button) print("Sleeping for the installation code to generate") time.sleep(2) - return self.app_p1p2_name + return app_p1p2_name def check_for_html_char(self, text): matched = re.search(r'\b&\w+;\b', text) @@ -378,7 +384,7 @@ def check_for_html_char(self, text): def delete_p1p2_application(self, app_name): self.wait_to_click(self.applications_menu_id) self.wait_to_click((By.LINK_TEXT, app_name)) - + self.wait_for_element(self.settings, 50) self.click(self.settings) self.wait_for_element(self.actions_tab, 50) @@ -408,36 +414,36 @@ def create_application(self, app_name): def delete_and_add_app(self, app): self.wait_to_click(self.applications_menu_id) - + if self.is_present((By.LINK_TEXT, app)): print("App is already pesent so deleting it") self.wait_to_click((By.LINK_TEXT, app)) self.delete_application() - + print("Creating the app") self.wait_to_click(self.dashboard_tab) - + self.create_application(app) else: print("App is not present so creating it") self.wait_to_click(self.dashboard_tab) - + self.create_application(app) def add_language(self, lang): self.wait_for_element(self.settings) self.wait_to_click(self.settings) - + self.wait_for_element(self.languages_tab) if self.is_present((By.XPATH, self.language_option.format(lang))): print("Language is already present") else: self.wait_to_click(self.add_language_button) self.wait_to_click(self.language_selector) - + self.scroll_to_element((By.XPATH, self.language_option_select.format(lang))) self.wait_to_click((By.XPATH, self.language_option_select.format(lang))) - + self.wait_to_click(self.save_language) @@ -473,3 +479,35 @@ def delete_all_application(self, apps): self.click(self.delete_confirm) assert self.is_present_and_displayed(self.delete_success, 200), "Application "+app+" not deleted." print("Deleted the application", app) + + def verify_form_settings_page(self, form_name): + self.hover_on_element((By.XPATH, self.form_link.format(form_name))) + self.wait_to_click((By.XPATH, self.form_settings_btn.format(form_name))) + time.sleep(5) + assert self.is_present_and_displayed(self.form_settings_tab) + assert self.is_present_and_displayed(self.case_management_tab) + assert self.is_present_and_displayed(self.form_actions_tab) + assert self.is_present_and_displayed(self.user_properties) + print("Form Settings page correctly displayed") + + def verify_app_version_page(self): + self.wait_to_click((By.XPATH, self.field_edit_app_name.format(UserData.reassign_cases_application))) + time.sleep(2) + assert self.is_present_and_displayed(self.make_new_version_button) + print("Make New Version Page is correctly displayed") + + def get_app_code(self, app_name): + self.wait_to_click((By.XPATH, self.field_edit_app_name.format(app_name))) + time.sleep(2) + self.wait_for_element(self.make_new_version_button) + self.wait_to_click(self.publish_button) + if self.is_present_and_displayed(self.enter_app_code_link): + self.wait_to_click(self.enter_app_code_link) + else: + print("Enter App Code link is not present") + code_text = self.wait_to_get_text(self.code) + self.wait_to_click(self.close) + # self.wait_to_click(self.delete_form) + # self.wait_to_click(self.delete_form_confirm) + print("App code: ", code_text) + return code_text diff --git a/HQSmokeTests/testPages/data/copy_cases_page.py b/HQSmokeTests/testPages/data/copy_cases_page.py index d2ac0a6df..549f9db70 100644 --- a/HQSmokeTests/testPages/data/copy_cases_page.py +++ b/HQSmokeTests/testPages/data/copy_cases_page.py @@ -1,6 +1,6 @@ import time -from selenium.webdriver import ActionChains +from selenium.webdriver import ActionChains, Keys from selenium.webdriver.common.by import By from common_utilities.selenium.base_page import BasePage from HQSmokeTests.userInputs.user_inputs import UserData @@ -16,9 +16,8 @@ def __init__(self, driver, settings): self.env_url = settings["url"] self.copy_cases_menu = (By.LINK_TEXT, "Copy Cases") self.apply = (By.ID, "apply-btn") - self.case_type = (By.XPATH, "//label[.='Case Type']//following-sibling::div/*[@class='select2 select2-container select2-container--default select2-container--below']") - self.case_type_dropdown = (By.XPATH, "//label[.='Case Type']//following-sibling::div/select[@name='case_type']") - + self.case_type = (By.XPATH, "//select[@name='case_type']") + self.case_type_option_value = (By.XPATH, "//option[@value='reassign']") self.select_first_case = (By.XPATH, "(//td[2][not(contains(.,'no name'))]//preceding-sibling::td/input[@type='checkbox'])[1]") self.first_case_name = (By.XPATH, "(//a[contains(@class, 'ajax_dialog')][not(contains(.,'no name'))])[1]") @@ -36,57 +35,79 @@ def __init__(self, driver, settings): self.copy_dropdown = (By.ID, "select2-reassign_owner_select-container") self.copy_to_user_dropdown_input = (By.XPATH, "//input[@class='select2-search__field']") self.copied_user_from_list = "//li[starts-with(text(), '{}')]" - self.success_message = (By.XPATH, "//*[@data-bind='html: message' and contains(.,'Cases copied')]") + self.success_message = (By.XPATH, "//*[contains(@class,'alert-success')]") self.empty_list = (By.XPATH, "//td[.='No data available to display. Please try changing your filters.']") - + self.users_field = (By.XPATH, "(//textarea[@class='select2-search__field'])[1]") + self.users_list_item = "//ul[@role='listbox']/li[contains(.,'{}')]" + self.remove_buttons = (By.XPATH, "//select[@name='case_list_filter']//following-sibling::span//ul//button") def sort_for_latest_on_top(self): self.wait_to_click(self.last_modified) self.wait_for_element(self.last_modified_ascending, 50) - time.sleep(2) + time.sleep(5) self.wait_to_click(self.last_modified) self.wait_for_element(self.last_modified_descending, 50) - def get_cases(self): + def remove_default_users(self): + self.wait_for_element(self.users_field) + count = self.find_elements(self.remove_buttons) + print(len(count)) + for i in range(len(count)): + count[0].click() + time.sleep(2) + if len(count) != 1: + ActionChains(self.driver).send_keys(Keys.TAB).perform() + time.sleep(2) + count = self.find_elements(self.remove_buttons) + ActionChains(self.driver).send_keys(Keys.ESCAPE).perform() + + def get_cases(self, username): self.wait_to_click(self.copy_cases_menu) - time.sleep(2) - self.wait_for_element(self.apply, 70) - self.select_by_text(self.user_search_dropdown, UserData.searched_user) - self.select_by_value(self.case_type_dropdown, UserData.case_pregnancy) + self.wait_for_element(self.case_type, 60) + self.select_by_value(self.case_type, UserData.case_reassign) + self.remove_default_users() + self.send_keys(self.users_field, username) + self.wait_to_click((By.XPATH, self.users_list_item.format(username))) + time.sleep(1) self.wait_to_click(self.apply) + def copy_case(self): self.sort_for_latest_on_top() - time.sleep(2) + time.sleep(5) self.wait_to_click(self.select_first_case) case_being_copied = self.get_text(self.first_case_name) self.wait_to_click(self.copy_dropdown) - + time.sleep(1) self.send_keys(self.copy_to_user_dropdown_input, UserData.mobile_testuser) - + time.sleep(1) assigned_username = self.get_text((By.XPATH,self.copied_user_from_list.format(UserData.mobile_testuser))) print("Assigned Username:", assigned_username) - self.move_to_element_and_click((By.XPATH,self.copied_user_from_list.format(UserData.mobile_testuser))) + self.move_to_element_and_click((By.XPATH, self.copied_user_from_list.format(UserData.mobile_testuser))) + time.sleep(5) self.wait_to_click(self.copy_btn) - time.sleep(2) - self.wait_for_element(self.success_message, 30) + time.sleep(5) + self.wait_for_element(self.success_message, 130) print("Sleeping for sometimes for the case to be copied") time.sleep(60) - self.wait_to_click(self.copy_cases_menu) - time.sleep(2) - self.wait_for_element(self.apply, 70) - self.select_by_text(self.user_search_dropdown, assigned_username) + self.driver.refresh() + time.sleep(5) + self.remove_default_users() + self.send_keys(self.users_field, assigned_username) + self.wait_to_click((By.XPATH, self.users_list_item.format(assigned_username))) + time.sleep(3) self.send_keys(self.search_query, case_being_copied) self.wait_to_click(self.apply) - time.sleep(2) + time.sleep(5) self.scroll_to_bottom() + self.sort_for_latest_on_top() if self.is_present(self.empty_list): print("No Case Copied, List is empty") assert False else: self.wait_for_element(self.new_owner_name, 60) self.sort_for_latest_on_top() - time.sleep(2) + time.sleep(5) self.wait_for_element(self.new_owner_name, 60) copied_username = self.get_text(self.new_owner_name) time_modified = self.get_text(self.copied_time) diff --git a/HQSmokeTests/testPages/data/export_data_page.py b/HQSmokeTests/testPages/data/export_data_page.py index de6a1123c..cd5ab119e 100644 --- a/HQSmokeTests/testPages/data/export_data_page.py +++ b/HQSmokeTests/testPages/data/export_data_page.py @@ -70,6 +70,7 @@ def __init__(self, driver): self.date_range = (By.ID, "id_date_range") self.close_date_picker = (By.XPATH, "//div[@data-action='close']") self.case_owner = (By.XPATH, "//span[@class='select2-selection select2-selection--multiple']") + self.export_sharing = (By.XPATH, "//select[@id='sharing-select']") # Export Form and Case data variables self.export_form_data_link = (By.LINK_TEXT, 'Export Form Data') @@ -126,6 +127,7 @@ def __init__(self, driver): self.copy_dashfeed_link = "//*[contains(@data-bind,'hasEmailedExport')][.//span[.='{}']]//following-sibling::div//*[contains(@data-bind, 'copyLinkRequested')]" self.dashboard_feed_link = "//*[contains(@data-bind,'hasEmailedExport')][.//span[.='{}']]//following-sibling::div//input" self.check_data = (By.XPATH, "//*[contains(text(), '@odata.context')]") + self.data_upload_complete_text = "(//*[contains(@data-bind,'hasEmailedExport')][.//span[.='{}']]/following-sibling::div//p[contains(@class,'text-success')][contains(.,'Data update complete')])" # Power BI / Tableau Integration, Form self.powerBI_tab_int = (By.LINK_TEXT, 'PowerBi/Tableau Integration') @@ -172,6 +174,14 @@ def __init__(self, driver): os.path.join(UserData.USER_INPUT_BASE_DIR, "test_data/import_parent_child_case.xlsx") ) + self.repeat_checkbox = (By.XPATH, "//span[./span[@data-bind='text: table.label()'][contains(.,'Repeat') or contains(.,'repeat')]]//preceding-sibling::span/input[@type='checkbox'][contains(@data-bind,'disabled: false')]") + + # Shared Export + self.shared_export_name = "//div[@class='card-header'][.='Exports Shared with Me']//following-sibling::div//td[.//span[.='{}']]" + self.shared_export_view_button = "//td[.//span[.='{}']]//following-sibling::td//a[contains(@data-bind,'editUrl')]//span[contains(.,'View')][not(@style)]" + self.shared_export_edit_button = "//td[.//span[.='{}']]//following-sibling::td//a[contains(@data-bind,'editUrl')]//span[contains(.,'Edit')][not(@style)]" + + def get_url_paste_browser(self, username, password, item): if item == 'cases': odata_feed_link = self.wait_to_get_value(self.copy_odata_link_case) @@ -501,9 +511,10 @@ def excel_dashboard_integration_case(self): self.wait_for_element((By.XPATH, self.update_data_conf.format(UserData.dashboard_feed_case)), 20) self.wait_to_click((By.XPATH, self.update_data_conf.format(UserData.dashboard_feed_case))) # self.wait_and_sleep_to_click((By.XPATH, self.update_data_conf.format(UserData.dashboard_feed_case))) - self.wait_for_element(self.data_upload_msg, 50) - if self.is_present(self.data_upload_msg): + self.wait_for_element((By.XPATH, self.data_upload_complete_text.format(UserData.dashboard_feed_case)), 50) + if self.is_present((By.XPATH, self.data_upload_complete_text.format(UserData.dashboard_feed_case))): print("Data uploaded successfully.") + self.reload_page() else: print("Data not uploaded successfully.") time.sleep(10) @@ -830,7 +841,7 @@ def download_export_without_condition(self, name, type=None): self.wait_and_sleep_to_click(self.prepare_export_button, timeout=10) try: self.wait_till_progress_completes("exports") - self.wait_for_element(self.success_progress, 100) + self.wait_for_element(self.success_progress, 200) self.wait_for_element(self.download_button, 300) self.js_click(self.download_button) wait_for_download_to_finish() @@ -878,7 +889,10 @@ def add_case_exports_reassign(self): self.assert_downloaded_file(newest_file, UserData.p1p2_case_export_name), "Download Not Completed!" else: print("Not the expected file. Downloading again...") - self.js_click(self.download_button) + self.wait_for_element(self.download_button) + time.sleep(4) + self.wait_to_click(self.download_button) + time.sleep(4) wait_for_download_to_finish() newest_file = latest_download_file() self.assert_downloaded_file(newest_file, UserData.p1p2_case_export_name), "Download Not Completed!" @@ -958,3 +972,97 @@ def verify_case_import(self, text): self.wait_for_element((By.XPATH, self.case_id_value.format(parent_id))) assert self.is_present(self.related_cases_tab), "Parent not reassigned" self.validate_child_case_data() + + def add_repeat_form_exports(self, app, case, form, export_name): + self.wait_for_element(self.add_export_button, 100) + self.delete_bulk_exports() + self.wait_and_sleep_to_click(self.add_export_button) + time.sleep(100) + self.is_visible_and_displayed(self.app_type, 200) + self.wait_for_element(self.app_type, 200) + self.is_clickable(self.app_type) + self.select_by_text(self.app_type, UserData.app_type) + self.select_by_text(self.application, app) + self.select_by_text(self.module, case) + self.select_by_text(self.form, form) + self.wait_to_click(self.add_export_conf) + self.wait_for_element(self.export_name, 200) + self.clear(self.export_name) + self.send_keys(self.export_name, export_name+Keys.TAB) + time.sleep(5) + self.scroll_to_bottom() + list_repeat = self.find_elements(self.repeat_checkbox) + if len(list_repeat) > 0: + assert True + else: + print("Repeat checkbox are either absent or not enabled") + assert False + time.sleep(5) + self.js_click(self.export_settings_create) + print("Export created!!") + + def check_for_case_id(self, case_id): + self.wait_for_element(self.find_data_by_ID) + self.wait_to_click(self.find_data_by_ID) + self.wait_to_clear_and_send_keys(self.find_data_by_case_ID_textbox, case_id) + self.wait_and_sleep_to_click(self.find_data_by_case_ID_button) + self.wait_for_element(self.view_FormID_CaseID) + link = self.get_attribute(self.view_FormID_CaseID, "href") + print(link) + self.driver.get(link) + self.wait_for_element((By.XPATH, self.case_id_value.format(case_id))) + if self.is_present_and_displayed((By.XPATH, self.case_id_value.format(case_id))): + assert True, "Case ID not present" + print("Case ID present") + else: + print("Case ID not present") + assert False + + def add_shared_form_exports(self, name, private='NO'): + self.wait_for_element(self.add_export_button, 100) + self.wait_and_sleep_to_click(self.add_export_button) + time.sleep(100) + self.is_visible_and_displayed(self.app_type, 200) + self.wait_for_element(self.app_type, 200) + self.is_clickable(self.app_type) + self.select_by_text(self.app_type, UserData.app_type) + self.select_by_text(self.application, UserData.village_application) + self.select_by_text(self.module, UserData.case_list_name) + self.select_by_text(self.form, UserData.form_name) + self.wait_to_click(self.add_export_conf) + self.wait_for_element(self.export_name, 200) + self.clear(self.export_name) + self.send_keys(self.export_name, name+Keys.TAB) + time.sleep(5) + if private == 'YES': + self.scroll_to_element(self.export_sharing) + self.select_by_value(self.export_sharing, 'private') + time.sleep(2) + else: + self.scroll_to_element(self.export_sharing) + self.select_by_value(self.export_sharing, 'edit_and_export') + time.sleep(2) + self.scroll_to_bottom() + time.sleep(5) + self.js_click(self.export_settings_create) + print("Export created!!") + time.sleep(10) + + def verify_shared_export_section(self, shared_export, private_export, permission='YES'): + self.wait_to_click(self.export_form_data_link) + self.wait_for_element(self.add_export_button) + assert self.is_present_and_displayed((By.XPATH, self.shared_export_name.format(shared_export))), "Shared export not present" + assert not self.is_present_and_displayed((By.XPATH, self.shared_export_name.format(private_export)), 5 + ), "Private export present" + if permission == 'YES': + assert self.is_present_and_displayed((By.XPATH, self.shared_export_edit_button.format(shared_export)) + ), "Shared export edit button not present" + assert not self.is_present_and_displayed((By.XPATH, self.shared_export_view_button.format(private_export)), 5 + ), "Shared export view button present" + elif permission == 'NO': + assert self.is_present_and_displayed((By.XPATH, self.shared_export_view_button.format(shared_export)) + ), "Shared export view button not present" + assert not self.is_present_and_displayed((By.XPATH, self.shared_export_edit_button.format(private_export)), 5 + ), "Shared export edit button present" + else: + print("Permission value is missing.") \ No newline at end of file diff --git a/HQSmokeTests/testPages/email/email_verification.py b/HQSmokeTests/testPages/email/email_verification.py index aaba96828..5f591d08c 100644 --- a/HQSmokeTests/testPages/email/email_verification.py +++ b/HQSmokeTests/testPages/email/email_verification.py @@ -1,4 +1,5 @@ import datetime +import time from imap_tools import MailBox from imap_tools import AND, OR, NOT @@ -18,18 +19,31 @@ def __init__(self, settings): self.imap_user = settings['login_username'] self.imap_pass = settings['imap_password'] - def get_hyperlink_from_latest_email(self, subject, url): + def get_hyperlink_from_latest_email_old(self, subject, url): if 'www' in url: from_email = UserData.from_email_prod elif 'india' in url: from_email = UserData.from_email_india + elif "eu" in url: + from_email = UserData.from_email_eu else: from_email = UserData.from_email - + print(f"Subject to be fetched: {subject} from email: {from_email}") with MailBox(self.imap_host).login(self.imap_user, self.imap_pass, 'INBOX') as mailbox: - bodies = [msg.html for msg in - mailbox.fetch(AND(subject=subject, from_ =from_email, date=datetime.date.today()))] - soup = BeautifulSoup(str(bodies[len(bodies)-1]), "html.parser") + bodies = list(mailbox.fetch(AND(subject=subject, from_=from_email, + date=datetime.date.today() + ), + reverse=True, limit=2 + )) + if not bodies: + raise AssertionError("No matching emails found") + + # Sort by date explicitly + bodies.sort(key=lambda m: m.date, reverse=True) + latest_msg = str(bodies[0]) # guaranteed newest by timestamp + print(latest_msg) + soup = BeautifulSoup(latest_msg, "html.parser") + # soup = BeautifulSoup(str(bodies[len(bodies) - 1]), "html.parser") links = [] for link in soup.findAll('a', attrs={'href': re.compile("^https://")}): links.append(link.get('href')) @@ -39,17 +53,103 @@ def get_hyperlink_from_latest_email(self, subject, url): print(links[0]) return str(links[0]) + from imap_tools import MailBox, AND + from bs4 import BeautifulSoup + import datetime, time, re + + def get_hyperlink_from_latest_email(self, subject, url): + # --- Determine sender based on environment URL --- + if 'www' in url: + from_email = UserData.from_email_prod + elif 'india' in url: + from_email = UserData.from_email_india + elif "eu" in url: + from_email = UserData.from_email_eu + else: + from_email = UserData.from_email + + print(f"📧 Looking for subject: '{subject}' from: {from_email}") + + max_retries = 3 + all_msgs = [] + now = datetime.datetime.now() + five_min_ago = now - datetime.timedelta(minutes=5) + + for attempt in range(max_retries): + try: + # --- Search both Inbox and Spam --- + for folder in ["INBOX", "[Gmail]/Spam"]: + with MailBox(self.imap_host).login(self.imap_user, self.imap_pass, folder) as mailbox: + msgs = list(mailbox.fetch( + AND( + from_=from_email, + subject=subject, + date=datetime.date.today() + ), + reverse=True, + limit=10 + ) + ) + if msgs: + print(f"✅ Found {len(msgs)} message(s) in {folder}") + all_msgs.extend(msgs) + + if not all_msgs: + print(f"Attempt {attempt + 1}: No matching emails found. Retrying...") + time.sleep(5) + continue + + # --- Filter to only emails from the last 5 minutes --- + recent_msgs = [ + m for m in all_msgs + if m.date and (now - m.date.replace(tzinfo=None)) <= datetime.timedelta(minutes=5) + ] + + if not recent_msgs: + print(f"Attempt {attempt + 1}: Found emails, but none within last 5 minutes. Retrying...") + time.sleep(5) + continue + + # --- Sort by message date (latest first) --- + recent_msgs.sort(key=lambda m: m.date, reverse=True) + latest_msg = recent_msgs[0] + + print(f"✅ Latest message found: {latest_msg.subject}") + print(f"📅 Received at: {latest_msg.date}") + + # --- Parse HTML body for hyperlinks --- + soup = BeautifulSoup(latest_msg.html or "", "html.parser") + links = [ + link.get('href') + for link in soup.find_all('a', attrs={'href': re.compile(r"^https://")}) + ] + + if links: + print(f"✅ Found {len(links)} link(s). First: {links[0]}") + return links[0] + + print(f"Attempt {attempt + 1}: No links found in recent email. Retrying...") + time.sleep(5) + + except Exception as e: + print(f"⚠️ IMAP error on attempt {attempt + 1}: {e}") + time.sleep(3) + + raise AssertionError("❌ No recent hyperlink email found (within last 5 minutes, Inbox/Spam).") + def get_email_body_from_latest_email(self, subject, url): if 'www' in url: from_email = UserData.from_email_prod elif 'india' in url: from_email = UserData.from_email_india + elif "eu" in url: + from_email = UserData.from_email_eu else: from_email = UserData.from_email print(subject) with MailBox(self.imap_host).login(self.imap_user, self.imap_pass, 'INBOX') as mailbox: bodies = [msg.html for msg in - mailbox.fetch(AND(subject=subject, from_=from_email, date=datetime.date.today()))] + mailbox.fetch(AND(subject=subject, from_=from_email, date=datetime.date.today()))] print(len(bodies)) n = '' end = -1 @@ -61,7 +161,7 @@ def get_email_body_from_latest_email(self, subject, url): end = None else: end = -1 - soup = BeautifulSoup(str(bodies[len(bodies)-1]), "html.parser") + soup = BeautifulSoup(str(bodies[len(bodies) - 1]), "html.parser") tr = [] table = [] @@ -82,13 +182,15 @@ def get_email_body_from_latest_email_proj_perf(self, subject, url): from_email = UserData.from_email_prod elif 'india' in url: from_email = UserData.from_email_india + elif "eu" in url: + from_email = UserData.from_email_eu else: from_email = UserData.from_email print(subject) with MailBox(self.imap_host).login(self.imap_user, self.imap_pass, 'INBOX') as mailbox: bodies = [msg.html for msg in mailbox.fetch(AND(subject=subject, from_=from_email, date=datetime.date.today()))] - soup = BeautifulSoup(str(bodies[len(bodies)-1]), "html.parser") + soup = BeautifulSoup(str(bodies[len(bodies) - 1]), "html.parser") tr = [] td = [] table = [] @@ -128,7 +230,6 @@ def get_email_body_from_latest_email_proj_perf(self, subject, url): print("tab low", tab_low) - if len(table_inactive.findAll('td')) > 0: print(len(table_inactive.findAll('td'))) for row in table_inactive.select("tr"): @@ -183,4 +284,83 @@ def get_email_body_from_latest_email_proj_perf(self, subject, url): print("tab high", tab_high) table_data = [tab_low + tab_inactive + tab_high] - return table_data \ No newline at end of file + return table_data + + def verify_email_sent(self, subject, url, sleep = 'NO'): + if 'www' in url: + from_email = UserData.from_email_prod + elif 'india' in url: + from_email = UserData.from_email_india + elif "eu" in url: + from_email = UserData.from_email_eu + else: + from_email = UserData.from_email + + print(f"📧 Checking for subject: '{subject}' from email: {from_email}") + if sleep != 'NO': + print("Sleeping a couple of minutes for the emails to get triggered") + time.sleep(120) + now = datetime.datetime.now() + + # --- Search both Inbox and Spam folders --- + for folder in ["INBOX", "[Gmail]/Spam"]: + with MailBox(self.imap_host).login(self.imap_user, self.imap_pass, folder) as mailbox: + msgs = list(mailbox.fetch( + AND( + from_=from_email, + subject=subject, + date=datetime.date.today() + ), + reverse=True, + limit=10 + ) + ) + + for msg in msgs: + msg_time = msg.date.replace(tzinfo=None) + time_diff = (now - msg_time).total_seconds() / 60 # minutes + + if ( + msg.subject + and msg.subject.strip().lower() == subject.strip().lower() + and time_diff <= 5 # within last 5 minutes + ): + print(f"✅ Email received in {folder}") + print(f"📅 Received at: {msg.date}") + return True + + raise AssertionError("❌ No email received within the last 5 minutes (Inbox/Spam).") + + def verify_email_sent_new(self, subject, url): + if 'www' in url: + from_email = UserData.from_email_prod + elif 'india' in url: + from_email = UserData.from_email_india + elif "eu" in url: + from_email = UserData.from_email_eu + else: + from_email = UserData.from_email + print(f"Subject to be fetched: {subject} from email: {from_email}") + max_retries = 3 + for attempt in range(max_retries): + try: + with MailBox(self.imap_host).login(self.imap_user, self.imap_pass, 'INBOX') as mailbox: + # Fetch only recent few (reverse=True gives most recent first) + msgs = list(mailbox.fetch( + AND(from_=from_email, date=datetime.date.today()), + reverse=True, # newest first + limit=5 # fetch only 5 recent emails + ) + ) + + for msg in msgs: + if msg.subject.strip() == subject.strip(): + print("✅ Email is received") + return True + + print(f"Attempt {attempt + 1}: Email not found yet. Retrying...") + time.sleep(5) + except Exception as e: + print(f"IMAP error on attempt {attempt + 1}: {e}") + time.sleep(3) + raise AssertionError("❌ Email not received after multiple retries") diff --git a/HQSmokeTests/testPages/home/home_page.py b/HQSmokeTests/testPages/home/home_page.py index 635ac796d..5a6955545 100644 --- a/HQSmokeTests/testPages/home/home_page.py +++ b/HQSmokeTests/testPages/home/home_page.py @@ -64,7 +64,15 @@ def reports_menu(self): self.open_menu(self.reports_menu_id) else: raise TimeoutException - self.wait_to_click(self.view_all) + try: + self.wait_to_click(self.view_all) + except Exception: + print("View All has been already clicked") + url = self.get_current_url() + if "staging" in url: + time.sleep(50) + self.wait_for_page_title(self.REPORTS_TITLE, 300) + time.sleep(10) assert self.REPORTS_TITLE in self.driver.title, "This is not the Reports menu page." def data_menu(self): @@ -118,14 +126,14 @@ def open_menu(self, menu): self.wait_to_click(self.show_full_menu) self.driver.get(self.dashboard_link) self.accept_pop_up() - self.wait_for_element(menu) + self.wait_for_element(menu, 60) self.wait_to_click(menu) except TimeoutException: if self.is_present(login.username_textbox_id): login.login(self.settings["login_username"], self.settings["login_password"]) self.driver.get(self.dashboard_link) self.accept_pop_up() - self.wait_for_element(menu) + self.wait_for_element(menu, 60) self.wait_to_click(menu) else: print(TimeoutException) diff --git a/HQSmokeTests/testPages/messaging/messaging_page.py b/HQSmokeTests/testPages/messaging/messaging_page.py index de335faae..4e5e2810a 100644 --- a/HQSmokeTests/testPages/messaging/messaging_page.py +++ b/HQSmokeTests/testPages/messaging/messaging_page.py @@ -17,6 +17,7 @@ class MessagingPage(BasePage): def __init__(self, driver): super().__init__(driver) + self.cond_alert_no_value_name_input = "cond_alert_no_value_" + fetch_random_string() # Messaging Dashboard self.messaging_menu_id = (By.ID, "MessagingTab") self.dashboard_linked_text = (By.LINK_TEXT, "Dashboard") @@ -32,6 +33,7 @@ def __init__(self, driver): self.broadcasts = (By.LINK_TEXT, "Broadcasts") self.add_broadcast = (By.XPATH, "//div[@class='btn-group']") self.broadcast_name = (By.XPATH, "//input[@name='schedule-schedule_name']") + self.recipients_select_cond_alert = (By.XPATH, "//select[@name='schedule-recipient_types']") self.recipients = (By.XPATH, "(//span[@class='select2-selection select2-selection--multiple'])[1]") self.user_recipient = (By.XPATH, "(//span[@class='select2-selection select2-selection--multiple'])[2]") self.select_value_dropdown = (By.XPATH, "//ul[@class='select2-results__options']/li[.='"+UserData.app_login+"']") @@ -55,6 +57,7 @@ def __init__(self, driver): By.XPATH, "//case-property-input//span[@class='select2-selection select2-selection--single'][@role='combobox']") self.select_case_property = ( By.XPATH, "//select[@data-bind='value: valueObservable, autocompleteSelect2: casePropertyNames']") + self.select_match_type = (By.XPATH, "//select[@data-bind='value: match_type']") self.case_property_value = (By.XPATH, "//input[contains(@data-bind,'value: property_value')]") self.case_property_input = (By.XPATH, "//input[@class='select2-search__field']") self.continue_button_rule_tab = ( @@ -160,9 +163,9 @@ def compose_sms(self): self.wait_to_click(self.compose_sms_menu) self.wait_for_element(self.recipients_select) self.select_by_value(self.recipients_select, "[send to all]") - + self.send_keys(self.message_textarea, "sms_" + fetch_random_string()) - + self.scroll_to_element(self.send_message) self.wait_to_click(self.send_message) try: @@ -171,9 +174,9 @@ def compose_sms(self): self.wait_to_click(self.compose_sms_menu) self.wait_for_element(self.recipients_select) self.select_by_value(self.recipients_select, "[send to all]") - + self.send_keys(self.message_textarea, "sms_" + fetch_random_string()) - + self.scroll_to_element(self.send_message) self.wait_to_click(self.send_message) self.wait_for_element(self.message_sent_success_msg) @@ -186,7 +189,7 @@ def send_broadcast_message(self, broadcast_input): self.wait_to_click(self.recipients) self.wait_to_click(self.select_recipient_type) self.wait_to_click(self.user_recipient) - + self.wait_to_click(self.select_value_dropdown) self.send_keys(self.broadcast_message, "Test Broadcast:" + broadcast_input) self.wait_to_click(self.send_broadcast) @@ -298,10 +301,10 @@ def add_keyword_trigger(self, keyword_name_input): self.send_keys(self.keyword_description, keyword_name_input) self.select_by_text(self.send_sender, 'SMS') self.send_keys(self.keyword_message, "Test Message: " + keyword_name_input) - + self.scroll_to_element(self.send_message) self.wait_to_click(self.send_message) - + self.select_by_value(self.page_limit, "50") time.sleep(3) self.wait_for_element((By.XPATH, self.keyword_created.format(keyword_name_input))) @@ -319,7 +322,7 @@ def add_structured_keyword_trigger(self, struct_keyword_name_input): self.scroll_to_element(self.send_message) self.wait_to_click(self.send_message) - + self.select_by_value(self.page_limit, "50") time.sleep(3) self.wait_for_element((By.XPATH, self.keyword_created.format(struct_keyword_name_input))), "Structured keyword not created successfully!" @@ -332,9 +335,9 @@ def chat_page(self): # def sms_connectivity_gateway(self): # self.driver.find_element(By.LINK_TEXT, self.sms_connectivity).click() - # + # # self.driver.find_element(By.XPATH, "//select[@name='hq_api_id']").click() - # + # # self.driver.find_element(By.XPATH, "//select[@name='hq_api_id']/option[text( # )='Airtel (through TCL)']").click() # self.driver.find_element(By.XPATH, self.add_gateway).click() @@ -345,19 +348,19 @@ def chat_page(self): # self.driver.find_element(By.XPATH, self.sender_id).send_keys("gateway_" + fetch_random_string()) # self.driver.find_element(By.XPATH, self.client_name).send_keys("gateway_" + fetch_random_string()) # self.driver.find_element(By.XPATH, self.campaign_name).send_keys("gateway_" + fetch_random_string()) - # + # # assert True == self.driver.find_element(By.XPATH, self.gateway_created).is_displayed() # print("Gateway created successfully!") def general_settings_page(self): self.wait_to_click(self.general_settings) - + if self.is_enabled(self.disable_button): self.wait_to_click(self.enable_button) self.send_keys(self.time_input, "23:59") else: self.wait_to_click(self.disable_button) - + self.scroll_to_element(self.send_message) self.wait_to_click(self.send_message) self.wait_for_element(self.message_sent_success_msg) @@ -387,7 +390,7 @@ def delete_languages(self): self.js_click((By.XPATH, self.delete_lang.format(lang))) time.sleep(3) self.js_click(self.save_lang) - + else: print("Only English is Present and no other languages") @@ -397,7 +400,7 @@ def add_eng_lang(self): self.wait_for_element(self.lang_search_input) self.wait_for_element(self.select_eng_lang) self.click(self.select_eng_lang) - + lang = self.get_text(self.selected_lang_name) print("Language selected is: ", lang) self.js_click(self.save_lang) @@ -501,10 +504,10 @@ def remove_all_keywords(self): for i in range(len(keyword_names))[::-1]: self.scroll_to_element((By.XPATH, self.keyword_delete_btn.format(keyword_names[i]))) self.wait_to_click((By.XPATH, self.keyword_delete_btn.format(keyword_names[i]))) - + self.wait_for_element((By.XPATH, self.delete_confirm_button.format(keyword_names[i]))) self.wait_to_click((By.XPATH, self.delete_confirm_button.format(keyword_names[i]))) - + list = self.find_elements(self.keywords_list) confirm_button_list = self.find_elements((By.XPATH, self.delete_confirm_button.format('KEYWORD_'))) print("Updated List Count: ", len(list)) @@ -537,7 +540,7 @@ def remove_cond_alert(self, cond_alert_name_input): except NoAlertPresentException: raise AssertionError("Celery down") try: - + self.reload_page() time.sleep(4) self.wait_to_clear_and_send_keys(self.search_box, cond_alert_name_input) @@ -565,7 +568,7 @@ def remove_alert_with_same_name(self, alert_name): except NoAlertPresentException: raise AssertionError("Celery down") try: - + self.reload_page() self.wait_to_clear_and_send_keys(self.search_box, alert_name) self.wait_and_sleep_to_click(self.search_box) @@ -654,4 +657,66 @@ def remove_all_cond_alert(self): print("No script created cond alerts present") print("All Cond Alert removed successfully!") except Exception: - print("No Conditional alerts are present") \ No newline at end of file + print("No Conditional alerts are present") + + + def create_cond_alert_for_doesnot_have_value(self, rerun): + cond_alert_no_value_name_input = f"{self.cond_alert_no_value_name_input}{rerun}" + self.wait_to_click(self.cond_alerts) + self.remove_alert_with_same_name(cond_alert_no_value_name_input) + self.wait_to_click(self.add_cond_alert) + self.send_keys(self.cond_alert_name, cond_alert_no_value_name_input) + self.wait_to_click(self.continue_button_basic_tab) + time.sleep(2) + self.wait_to_click(self.case_type) + self.select_by_text(self.case_type, UserData.case_reassign) + time.sleep(3) + self.wait_to_click(self.select_filter) + self.wait_to_click(self.case_property_filter) + time.sleep(2) + self.wait_to_click(self.case_property_textbox) + time.sleep(1) + # self.send_keys(self.case_property_input, UserData.alert_case_property_random_value) + self.wait_for_element(self.select_case_property) + time.sleep(2) + self.select_by_text(self.select_case_property, UserData.alert_case_property_random_value) + self.select_by_text(self.select_match_type, UserData.alert_no_value) + self.wait_to_click(self.continue_button_rule_tab) + self.wait_for_element(self.recipients_select_cond_alert) + self.select_by_value(self.recipients_select_cond_alert, "Owner") + self.select_by_text(self.alert_type, "Email") + self.send_keys(self.email_subject, "Test Alert for no value " + cond_alert_no_value_name_input) + self.send_keys(self.broadcast_message, "Test Alert for no value:" + cond_alert_no_value_name_input) + self.wait_to_click(self.save_button_xpath) + print("Sleeping till the alert processing completes") + time.sleep(360) + self.driver.refresh() + time.sleep(160) + self.wait_to_clear_and_send_keys(self.search_box, cond_alert_no_value_name_input) + time.sleep(10) + self.wait_to_click(self.search_box) + self.wait_for_element((By.XPATH, self.delete_cond_alert.format(cond_alert_no_value_name_input)), 700) + self.driver.refresh() + if self.is_clickable((By.XPATH, self.delete_cond_alert.format(cond_alert_no_value_name_input))): + print("Restart is not required.") + else: + try: + self.js_click((By.XPATH, self.restart_rule_button.format(cond_alert_no_value_name_input))) + self.accept_pop_up() + time.sleep(5) + self.accept_pop_up() + print("Sleeping till the alert processing completes") + time.sleep(360) + self.wait_to_clear_and_send_keys(self.search_box, cond_alert_no_value_name_input) + self.wait_to_click(self.search_box) + self.wait_for_element((By.XPATH, self.delete_cond_alert.format(cond_alert_no_value_name_input)), 700) + self.driver.refresh() + except: + print("Restart not required") + self.wait_for_element(self.search_box) + self.wait_to_clear_and_send_keys(self.search_box, cond_alert_no_value_name_input) + self.wait_to_click(self.search_box) + assert self.is_displayed((By.XPATH, self.cond_alert_created.format(cond_alert_no_value_name_input))), "Conditional Alert not created successfully!" + print("Conditional Alert created successfully!") + subject = "Test Alert for no value" + cond_alert_no_value_name_input + return cond_alert_no_value_name_input, subject \ No newline at end of file diff --git a/HQSmokeTests/testPages/project_settings/repeaters_page.py b/HQSmokeTests/testPages/project_settings/repeaters_page.py index eac74d4f2..2b59c6726 100644 --- a/HQSmokeTests/testPages/project_settings/repeaters_page.py +++ b/HQSmokeTests/testPages/project_settings/repeaters_page.py @@ -38,7 +38,10 @@ def __init__(self, driver): By.XPATH, "//div[contains(@class,'alert-success')][contains(.,'Forwarder Successfully Updated')]") self.delete_success = ( By.XPATH, "//div[contains(@class,'alert-success')][contains(.,'Forwarding stopped!')]") + self.close_message = ( + By.XPATH, "//div[contains(@class,'alert-success')][contains(.,'Forwarding stopped!')]/button[contains(@class,'close')]") self.confirm_delete_button = "//div[./p[contains(.,'{}')]]//following-sibling::div/*[contains(.,'Delete')]" + self.test_repeater_row = (By.XPATH, "//td[starts-with(.,'repeater_')]") def data_forwarding(self): self.wait_for_element(self.data_forwarding_linked_text) @@ -87,3 +90,24 @@ def delete_repeater(self): self.wait_to_click((By.XPATH, self.confirm_delete_button.format(self.repeater_name_input))) assert self.is_present_and_displayed(self.delete_success), "Delete repeater failed" print("Repeater deleted successfully") + + def delete_all_repeaters(self): + self.data_forwarding() + repeater_names = [] + list_repeater = self.find_elements(self.test_repeater_row) + if len(list_repeater) > 0: + print("Test repeaters are present") + for item in list_repeater: + repeater_names.append(item.text) + print("Test Repeater list: ", repeater_names) + for item in repeater_names: + self.wait_to_click((By.XPATH, self.repeater_delete_button.format(item))) + self.wait_for_element((By.XPATH, self.confirm_delete_button.format(item))) + self.wait_to_click((By.XPATH, self.confirm_delete_button.format(item))) + assert self.is_present_and_displayed(self.delete_success), "Delete repeater failed" + print("Repeater deleted successfully", item) + self.wait_to_click(self.close_message) + time.sleep(3) + print("All test repeaters deleted") + else: + print("No test repeaters present") diff --git a/HQSmokeTests/testPages/reports/report_page.py b/HQSmokeTests/testPages/reports/report_page.py index ae72ce1af..fb7113fbe 100644 --- a/HQSmokeTests/testPages/reports/report_page.py +++ b/HQSmokeTests/testPages/reports/report_page.py @@ -21,6 +21,42 @@ """"Contains test page elements and functions related to the Reports module""" +def parse_time(time_str): + # Define regex patterns to match time units + time_units = { + 'days': 1, + 'weeks': 7, + 'months': 30, + 'years': 365 + } + + total_days = 0 + # Match days, weeks, months, and years in the string + for unit, multiplier in time_units.items(): + match = re.search(r'(\d+)\s+' + unit, time_str) + if match: + total_days += int(match.group(1)) * multiplier + + # If 'Never' is found, we return a very large value to consider it as the "oldest" + if 'Never' in time_str: + return float('inf') + + return total_days + + +def sort_times(time_list): + # Sort the list based on the parsed time values (newest first) + return sorted(time_list, key=parse_time, reverse=False) + + +def is_list_sorted_new_to_old(time_list): + # Parse each time string and check if they are in sorted order + parsed_times = [parse_time(time) for time in time_list] + res = all(parsed_times[i] >= parsed_times[i + 1] for i in range(len(parsed_times) - 1)) + print(res) + # Verify if the parsed times are sorted in descending order + return res + class ReportPage(BasePage): @@ -41,6 +77,7 @@ def __init__(self, driver): self.completion_vs_submission_rep = (By.LINK_TEXT, "Form Completion vs. Submission Trends") self.worker_activity_times_rep = (By.LINK_TEXT, "Worker Activity Times") self.project_performance_rep = (By.LINK_TEXT, "Project Performance") + self.CASE_LIST_TITLE = "Case List - CommCare HQ" # Inspect Data Reports self.submit_history_rep = (By.LINK_TEXT, "Submission History") @@ -83,6 +120,7 @@ def __init__(self, driver): self.select_source_id = (By.XPATH, "//select[@id='id_source']") self.select_form_type_value = "form" + self.select_case_type_value = "case" self.select_source_id_form_value = "Case List / Registration Form" self.select_source_id_case_value = "commcare-user" @@ -132,6 +170,8 @@ def __init__(self, driver): self.case_type_select = (By.XPATH, "//select[@id='report_filter_case_type']") self.date_input = (By.XPATH, "//input[@id='filter_range']") self.view_form_link = (By.XPATH, "//tbody/tr[1]/td[1]/a[.='View Form']") + self.view_case_link = (By.XPATH, "//tbody/tr[1]/td[1]/a[.='View Case']") + self.case_name = (By.XPATH, "//td[div[contains(text(),'abc')]]") self.submit_history_table = (By.XPATH, "//table[@id='report_table_submit_history']/tbody/tr") self.location_values = (By.XPATH, "//tr[@class='form-data-question ']/td[2]") @@ -147,10 +187,33 @@ def __init__(self, driver): self.case_owner_column = (By.XPATH, "//tbody//td[3]") # Case List Explorer + self.query_textarea = ".report-filter-xpath-textarea" + self.query_div = (By.XPATH, "//div[@class='report-filter-xpath-textarea']//pre//div[@class='ace_line']") + self.query_cursor = (By.XPATH, "//div[@class='report-filter-xpath-textarea']//pre//div[@class='ace_cursor']") + self.case_list_explorer_query_field = ( + By.XPATH, "//div[@class='report-filter-xpath-textarea']//pre//textarea[@class='ace_text-input']") + self.case_list_explorer_rep = (By.LINK_TEXT, "Case List Explorer") + self.case_list_explorer_TITLE = "Case List Explorer - CommCare HQ" + self.case_type_dropdown = (By.XPATH, "//select[@id='report_filter_case_type']") + self.column_editor = (By.XPATH, "//a[@href='#columns-editor']") + self.add_property_button = (By.XPATH, "//button[@data-bind='click: addProperty']") + self.last_properties_input = ( + By.XPATH, + "(//tbody[contains(@data-bind,'properties')]//td//input[contains(@data-bind,'Properties')])[last()]") + self.last_value_input = ( + By.XPATH, + "(//tbody[contains(@data-bind,'properties')]//td//input[contains(@data-bind,'value: label')])[last()]") + self.last_delete_property = (By.XPATH, "(//tbody[contains(@data-bind,'properties')]//td[4]/i)[last()]") + self.property_label = "//div[@class='atwho-container']//div[@class='atwho-view']//ul/li[1]/span[ .='reassign']//following-sibling::strong[.='name']" + self.properties_input = ( + By.XPATH, "//tbody[contains(@data-bind,'properties')]//td//input[contains(@data-bind,'Properties')]") + self.value_input = ( + By.XPATH, "//tbody[contains(@data-bind,'properties')]//td//input[contains(@data-bind,'value: label')]") + self.delete_property = (By.XPATH, "//tbody[contains(@data-bind,'properties')]//td[4]") self.edit_column = (By.XPATH, "//div[./label[contains(.,'Columns')]]//following-sibling::div//a[@data-parent='#case-list-explorer-columns']") self.properties_table = (By.XPATH, "//tbody[contains(@data-bind,'properties')]") - self.add_property_button = (By.XPATH, "//*[@data-bind='click: addProperty']") + self.add_property_button = (By.XPATH, "//button[@data-bind='click: addProperty']/i") self.property_name_input = (By.XPATH, "(//tbody[contains(@data-bind,'properties')]//td[2]//input)[last()]") self.cle_case_owner_column = (By.XPATH, "//table[contains(@class,'datatable')]//tbody//td[5]") @@ -186,11 +249,22 @@ def __init__(self, driver): self.export_to_excel = (By.XPATH, "//a[@id='export-report-excel']") self.export_success = (By.XPATH, "//span[.='Your requested Excel report will be sent to the email address defined in your account settings.']") + self.download_report_link = (By.XPATH, "//div[contains(@class,'success')]//a[.='Download Report']") # App Status self.app_status_results = (By.XPATH, "//table[@class='table table-striped datatable dataTable no-footer']/tbody/tr") self.app_status_results_cells = (By.XPATH, "//table[@class='table table-striped datatable dataTable no-footer']/tbody/tr/td") - + self.panel_body_text = (By.XPATH, "//div[@id='report-content']//div[contains(@class,'card-body')]") + self.last_submit_column_list = (By.XPATH, "//table[@id='report_table_app_status']//tbody//td[3]") + self.last_submit_column_first = (By.XPATH, "(//table[@id='report_table_app_status']//tbody//td[3])[1]") + self.page_list_dropdown = (By.XPATH, "//select[@name='report_table_app_status_length']") + self.pagination_list = (By.XPATH, "//ul[@class='pagination']/li/a") + self.application_dropdown = (By.XPATH, "//select[@id='report_filter_app']") + self.application_field = (By.XPATH, "//span[contains(@id, 'report_filter_app-container')]") + self.application_input = (By.XPATH, "//input[contains(@aria-controls,'report_filter_app-result')]") + self.APPLICATION_STATUS_TITLE = "Application Status - CommCare HQ" + self.result_table = (By.XPATH, "(//div[@id='report-content']//table//tbody//td[1])[1]") + self.users_list_item = "//ul[@role='listbox']/li[contains(.,'{}')]" def check_if_report_loaded(self): try: @@ -250,7 +324,7 @@ def sms_usage_report(self): self.check_if_report_loaded() def messaging_history_report(self): - self.js_click(self.messaging_history_rep) + self.wait_to_click(self.messaging_history_rep) date_range = self.get_last_7_days_date_range() self.clear(self.date_input) self.send_keys(self.date_input, date_range + Keys.TAB) @@ -408,7 +482,7 @@ def delete_report_case_links(self): self.wait_to_click(self.edit_report_id) self.wait_to_click(self.delete_report_xpath) print("Deleted Saved Report") - + self.reload_page() time.sleep(2) list = self.find_elements(self.report_case_links) @@ -429,7 +503,7 @@ def delete_report_form_links(self): self.wait_to_click(self.edit_report_id) self.wait_to_click(self.delete_report_xpath) print("Deleted Saved Report") - + self.reload_page() time.sleep(2) list = self.find_elements(self.report_form_links) @@ -563,9 +637,9 @@ def validate_messaging_history_for_cond_alert(self, cond_alert): date_range = self.get_todays_date_range() self.clear(self.date_input) self.send_keys(self.date_input, date_range + Keys.TAB) - + self.deselect_all(self.communication_type_select) - + self.select_by_text(self.communication_type_select, UserData.communication_type) self.check_if_report_loaded() self.scroll_to_bottom() @@ -613,18 +687,18 @@ def check_for_case_list_explorer_owner(self, url): owner = UserData.appiumtest_owner_id_prod else: owner = UserData.appiumtest_owner_id + self.wait_for_element(self.case_list_explorer, 300) self.wait_to_click(self.case_list_explorer) - time.sleep(2) - self.wait_for_element(self.edit_column) + time.sleep(20) + self.wait_for_element(self.edit_column, 220) self.wait_to_click(self.edit_column) self.wait_for_element(self.properties_table) self.wait_to_click(self.add_property_button) self.wait_to_click(self.property_name_input) self.send_keys(self.property_name_input, "owner_name") - + ActionChains(self.driver).key_down(Keys.ENTER).send_keys(Keys.TAB).perform() - self.scroll_to_element(self.remove_case_owner) - self.wait_to_click(self.remove_case_owner) + self.remove_default_users() self.wait_to_click(self.case_owner_textarea) self.send_keys(self.case_owner_textarea, UserData.app_login) self.wait_for_element((By.XPATH, self.case_owner_list_item.format(UserData.app_login))) @@ -638,7 +712,7 @@ def check_for_case_list_explorer_owner(self, url): for i in range(len(list_of_owner)): text = list_of_owner[i].text print(text) - assert text == owner or text == UserData.user_group, "Owner does not match" + assert text == owner or text == UserData.user_group, f"Owner {text} does not match for {owner} or {UserData.user_group}" self.check_if_html(text) def check_if_html(self, text): @@ -685,16 +759,19 @@ def export_daily_form_activity_to_excel(self): print(len(count)) for i in range(len(count)): count[0].click() - + if len(count) != 1: ActionChains(self.driver).send_keys(Keys.TAB).perform() - + count = self.find_elements(self.remove_buttons) # self.wait_to_click(self.users_field) self.send_keys(self.users_field, UserData.app_login) self.wait_to_click((By.XPATH, self.user_from_list.format(UserData.app_login))) - + ActionChains(self.driver).send_keys(Keys.TAB).perform() + date_range = self.get_todays_date_range() + self.clear(self.date_input) + self.send_keys(self.date_input, date_range + Keys.TAB) self.wait_to_click(self.apply_id) time.sleep(2) except (TimeoutException, NoSuchElementException): @@ -715,7 +792,7 @@ def export_daily_form_activity_to_excel(self): self.wait_for_element(self.export_success) print("Export to excel successful") print("Sleeping for some time for the email to be sent") - time.sleep(30) + time.sleep(120) return list def compare_web_with_email(self, link, web_data): @@ -757,10 +834,10 @@ def export_app_status_to_excel(self): print(len(count)) for i in range(len(count)): count[0].click() - + if len(count) != 1: ActionChains(self.driver).send_keys(Keys.TAB).perform() - + count = self.find_elements(self.remove_buttons) # self.wait_to_click(self.users_field) @@ -853,7 +930,6 @@ def verify_form_in_submit_history(self, app_name, lat, lon): result_lat = self.format_number(abs(float(text[0])), 5) result_lon = self.format_number(abs(float(text[1])), 5) print(result_lat, result_lon) - print(lat, lon) assert result_lat in lat and result_lon in lon, "Mismatch" def format_number(self, n, digits): @@ -872,3 +948,122 @@ def remove_default_users(self): ActionChains(self.driver).send_keys(Keys.TAB).perform() count = self.find_elements(self.remove_buttons) + ActionChains(self.driver).send_keys(Keys.ESCAPE).perform() + time.sleep(2) + ActionChains(self.driver).send_keys(Keys.TAB).perform() + + def verify_case_list_page(self): + self.wait_to_click(self.case_list_rep) + self.wait_for_element(self.apply_id, 100) + assert self.CASE_LIST_TITLE in self.driver.title, "This is not the Case List page." + text = self.get_text(self.panel_body_text) + print(text) + assert "Why can't I see any data?" in text + assert "Please choose your filters above and click Apply to see report data." in text + + def export_to_excel_config_report(self, report_name): + self.wait_to_click((By.LINK_TEXT, report_name)) + time.sleep(10) + self.wait_for_element(self.export_to_excel) + self.wait_to_click(self.export_to_excel) + self.wait_till_progress_completes("exports") + self.wait_to_click(self.download_report_link, 300) + print("Downloading report...") + time.sleep(3) + newest_file = latest_download_file() + print("Newest file:" + newest_file) + self.assert_downloaded_file(newest_file, report_name) + + def verify_sorted_list(self): + self.select_by_value(self.page_list_dropdown, '100') + time.sleep(10) + list1 = self.find_elements(self.last_submit_column_list) + list1_names = list() + for item in list1: + list1_names.append(item.text) + print(list1_names) + sorted_time_list = sort_times(list1_names) + print(sorted_time_list) + if list1_names == sorted_time_list: + assert True + else: + assert False + # result = is_list_sorted_new_to_old(list1_names) + # print(result) + + def application_status_report_search(self): + self.wait_to_click(self.application_status_rep) + self.wait_for_element(self.apply_id, 100) + assert self.APPLICATION_STATUS_TITLE in self.driver.title, "This is not the Application Status page." + self.remove_default_users() + self.click(self.application_field) + self.send_keys(self.application_input, UserData.reassign_cases_application) + self.wait_to_click((By.XPATH, self.users_list_item.format(UserData.reassign_cases_application))) + time.sleep(2) + self.wait_to_click(self.apply_id) + time.sleep(10) + self.wait_for_element(self.result_table, 300) + assert self.is_visible_and_displayed(self.report_content_id, 120), "Report not loaded" + print("Report loaded successfully!") + + def verify_case_list_explorer_properties(self): + self.wait_to_click(self.case_list_explorer_rep) + self.wait_for_element(self.apply_id, 100) + assert self.case_list_explorer_TITLE in self.driver.title, "This is not the Case List Explorer page." + self.select_by_value(self.case_type_dropdown, UserData.case_reassign) + return UserData.case_reassign + + def add_new_property(self, name): + self.scroll_to_element(self.column_editor) + self.wait_to_click(self.column_editor) + props1 = self.find_elements(self.properties_input) + value1 = self.find_elements(self.value_input) + delete1 = self.find_elements(self.delete_property) + assert len(props1) != 0, "Property fields not present" + assert len(value1) != 0, "Value fields not present" + assert len(delete1) != 0, "Delete fields not present" + self.wait_for_element(self.add_property_button) + self.wait_to_click(self.add_property_button) + time.sleep(2) + assert len(props1) + 1 == len(self.find_elements(self.properties_input)), "Property fields not added" + assert len(value1) + 1 == len(self.find_elements(self.value_input)), "Value fields not added" + assert len(delete1) + 1 == len(self.find_elements(self.delete_property)), "Delete fields not added" + self.send_keys(self.last_properties_input, "name") + time.sleep(2) + if self.is_visible_and_displayed((By.XPATH, self.property_label.format(name))): + assert True + print("Property present") + else: + print("Property absent") + assert False + ActionChains(self.driver).send_keys(Keys.TAB).perform() + + def get_case_id_from_case_list_explorer(self, text): + query = "case_name = '" + text + "'" + self.wait_to_click(self.case_list_explorer_rep) + time.sleep(5) + self.wait_for_element(self.apply_id, 100) + self.remove_default_users() + time.sleep(2) + self.set_ace_editor_text(self.query_textarea, query) + time.sleep(2) + self.select_by_text(self.case_type_dropdown, UserData.case_reassign_change) + time.sleep(2) + self.scroll_to_element(self.apply_id) + self.js_click(self.apply_id) + time.sleep(5) + self.wait_for_element(self.result_table, 300) + assert self.is_visible_and_displayed(self.report_content_id, 120), "Report not loaded" + print("Report loaded successfully!") + form_link = self.get_attribute(self.view_case_link, "href") + print("View Form Link: ", form_link) + # self.switch_to_new_tab() + self.driver.get(form_link) + time.sleep(3) + self.page_source_contains(text) + assert True, "Case name is present in Submit history" + self.page_source_contains(text) + print("Case is updated successfully") + case_id = self.get_text(self.case_id_block) + return case_id + diff --git a/HQSmokeTests/testPages/users/mobile_workers_page.py b/HQSmokeTests/testPages/users/mobile_workers_page.py index b614e7b79..e09cf4dac 100644 --- a/HQSmokeTests/testPages/users/mobile_workers_page.py +++ b/HQSmokeTests/testPages/users/mobile_workers_page.py @@ -4,7 +4,7 @@ import pandas as pd from openpyxl import load_workbook -from selenium.webdriver import Keys +from selenium.webdriver import Keys, ActionChains from common_utilities.selenium.base_page import BasePage from common_utilities.path_settings import PathSettings @@ -158,6 +158,16 @@ def __init__(self, driver): self.location_selection = (By.XPATH, "//li[contains(text(),'updated')]") self.location_update_button = (By.XPATH, "//button[contains(text(),'Update Location Settings')]") + self.remove_assigned_location = (By.XPATH, + "//select[@name='assigned_locations']//following-sibling::span//ul//button") + self.assigned_location_field = (By.XPATH, "(//textarea[@class='select2-search__field'])[1]") + + # Reset Password + self.security_tab = (By.XPATH, "//a[@href='#user-password']") + self.password_field = (By.XPATH, "//input[@name='new_password1']") + self.confirm_password_field = (By.XPATH, "//input[@name='new_password2']") + self.reset_button_xpath = (By.XPATH, '//*[@type="submit"][contains(@value,"Reset")]') + # Download and Upload self.download_worker_btn = (By.LINK_TEXT, "Download Mobile Workers") self.download_users_btn = (By.LINK_TEXT, "Download Users") @@ -176,6 +186,8 @@ def __init__(self, driver): self.role_dropdown = (By.XPATH, "//select[@id='id_role']") self.username_in_list = "//h3[./b[text() ='{}']]" self.table_body = (By.XPATH, "//tbody/tr[1]") + self.loaction_page_alert_info = (By.XPATH, + "//div[contains(@class,'alert-info')]/p[contains(.,'The user shares all assigned locations with one or more other users.')]") def search_user(self, username, flag="YES"): @@ -802,3 +814,32 @@ def verify_profile_change(self, profile): text = self.get_selected_text(self.profile_dropdown) print(text) assert text == profile, "Profile is not the same as set before upload" + + def remove_location(self): + self.wait_to_click(self.location_tab) + self.wait_for_element(self.assigned_location_field) + count = self.find_elements(self.remove_assigned_location) + print(len(count)) + for i in range(len(count)): + count[0].click() + time.sleep(2) + if len(count) != 1: + ActionChains(self.driver).send_keys(Keys.TAB).perform() + time.sleep(2) + count = self.find_elements(self.remove_assigned_location) + ActionChains(self.driver).send_keys(Keys.ESCAPE).perform() + + def verify_location_alert_not_present(self): + assert not self.is_present_and_displayed(self.loaction_page_alert_info, 10), "Location alert banner present" + print("Location alert button not present") + + def reset_mobile_worker_password(self, new): + self.wait_for_element(self.security_tab) + self.wait_to_click(self.security_tab) + self.wait_for_element(self.password_field) + self.send_keys(self.password_field, new) + time.sleep(1) + self.send_keys(self.confirm_password_field, new) + self.wait_to_click(self.reset_button_xpath) + self.wait_for_element(self.user_field_success_msg, 30) + print("Password reset successfully") \ No newline at end of file diff --git a/HQSmokeTests/testPages/users/roles_permissions_page.py b/HQSmokeTests/testPages/users/roles_permissions_page.py index 8d568039d..37de06820 100644 --- a/HQSmokeTests/testPages/users/roles_permissions_page.py +++ b/HQSmokeTests/testPages/users/roles_permissions_page.py @@ -22,6 +22,8 @@ def __init__(self, driver, settings): self.role_name_created = "role_" + fetch_random_string() self.role_non_admin_created = "role_non_" + fetch_random_string() + self.role_no_shared_export_created = "role_no_export_" + fetch_random_string() + self.role_yes_shared_export_created = "role_yes_export_" + fetch_random_string() self.role_rename_created = "role_rename_" + fetch_random_string() self.roles_menu = (By.XPATH, "//a[@data-title='Roles & Permissions']") self.add_new_role = ( @@ -36,12 +38,20 @@ def __init__(self, driver, settings): self.role_name_created) + "']]/following-sibling::td//i[@class='fa fa-trash']") self.edit_mobile_worker_checkbox = (By.XPATH, "//input[@id='edit-commcare-users-checkbox']//following-sibling::label/span") self.report_for_p1p2 = (By.XPATH, "//div[contains(@data-bind,'reportPermission')]//label/span[.='"+UserData.report_for_p1p2+"']") + self.manage_shared_exports = (By.XPATH, "//input[@id='edit-shared-exports-checkbox']") + self.data_checkbox = (By.XPATH, "//input[@id='edit-data-checkbox']") + + self.report_for_p1p2 = (By.XPATH, "//div[contains(@data-bind,'reportPermission')]//label[./span[.='"+UserData.report_for_p1p2+"']]") self.role_renamed = (By.XPATH, "//span[text()='" + str(self.role_rename_created) + "']") self.role_non_admin = (By.XPATH, "//span[text()='" + str(self.role_non_admin_created) + "']") + self.role_no_shared_export = "//span[text()='{}']" self.confirm_role_delete = (By.XPATH, "//div[@class='btn btn-danger']") self.full_org_access_checkbox = (By.XPATH, "//label[contains(.,'Full Organization Access')]//following-sibling::div//input") self.access_all_reports_checkbox = (By.XPATH, "//input[@id='access-all-reports-checkbox']") + self.web_user_permission = "//th[./span[.='{}']]//following-sibling::td/div[contains(@data-bind,'edit_web_users')]/i[contains(@class,'check')]" + self.mobile_worker_permission = "//th[./span[.='{}']]//following-sibling::td/div[contains(@data-bind,'edit_commcare_users')]/i[contains(@class,'check')]" + self.managed_shared_export_permission = "//th[./span[.='{}']]//following-sibling::td/div[contains(@data-bind,'edit_shared_exports')]/i[contains(@class,'check')]" def roles_menu_click(self): self.wait_to_click(self.roles_menu) @@ -54,7 +64,7 @@ def add_role(self): self.scroll_to_element(self.save_button) time.sleep(0.5) self.wait_to_click(self.save_button) - + assert self.is_present_and_displayed(self.role_created), "Role not added successfully!" def edit_role(self): @@ -64,9 +74,9 @@ def edit_role(self): self.scroll_to_element(self.save_button) time.sleep(0.5) self.wait_to_click(self.save_button) - + assert self.is_present_and_displayed(self.role_renamed), "Role not edited successfully!" - + def cleanup_role(self): self.wait_to_click(self.delete_role) @@ -84,7 +94,7 @@ def delete_test_roles(self): "(//th[.//span[contains(text(),'role_')]]//following-sibling::td//button[@class='btn btn-danger'])[" + str( i + 1) + "]").click() self.wait_to_click(self.confirm_role_delete) - + list_profile = self.driver.find_elements(By.XPATH, "//th[.//span[contains(text(),'role_')]]") else: print("There are no test roles") @@ -105,7 +115,7 @@ def delete_test_roles(self): "(//th[.//span[contains(text(),'role_')]]//following-sibling::td//button[@class='btn btn-danger'])[" + str( i + 1) + "]").click() self.wait_to_click(self.confirm_role_delete) - + list_profile = self.driver.find_elements(By.XPATH, "//th[.//span[contains(text(),'role_')]]") else: print("There are no test roles") @@ -116,7 +126,7 @@ def add_non_admin_role(self): self.wait_to_click(self.add_new_role) self.wait_for_element(self.role_name) self.send_keys(self.role_name, self.role_non_admin_created) - + self.wait_to_click(self.edit_mobile_worker_checkbox) self.scroll_to_element(self.access_all_reports_checkbox) is_checked = self.get_attribute(self.access_all_reports_checkbox, 'checked') @@ -139,7 +149,40 @@ def add_non_admin_role(self): self.scroll_to_element(self.save_button) time.sleep(0.5) self.wait_to_click(self.save_button) - + assert self.is_present_and_displayed(self.role_non_admin), "Role not added successfully!" print("Role added successfully") - return self.role_non_admin_created \ No newline at end of file + return self.role_non_admin_created + + + def add_shared_export_role(self, name, flag='NO'): + self.wait_to_click(self.add_new_role) + self.wait_to_clear_and_send_keys(self.role_name, name) + time.sleep(1) + self.click(self.edit_mobile_worker_checkbox) + time.sleep(0.5) + self.click(self.edit_web_user_checkbox) + time.sleep(0.5) + self.click(self.data_checkbox) + time.sleep(0.5) + self.scroll_to_element(self.manage_shared_exports) + if flag == 'YES': + time.sleep(2) + self.click(self.manage_shared_exports) + time.sleep(2) + time.sleep(0.5) + self.scroll_to_element(self.access_all_reports_checkbox) + time.sleep(1) + self.click(self.access_all_reports_checkbox) + time.sleep(0.5) + self.scroll_to_element(self.save_button) + time.sleep(0.5) + self.click(self.save_button) + time.sleep(2) + assert self.is_present_and_displayed((By.XPATH, self.role_no_shared_export.format(name))), "Role not added successfully!" + assert self.is_present_and_displayed((By.XPATH, self.web_user_permission.format(name))), "Web User Permission not present" + assert self.is_present_and_displayed((By.XPATH, self.mobile_worker_permission.format(name))), "Mobile Worker Permission not present" + if flag == "NO": + assert not self.is_present_and_displayed((By.XPATH, self.managed_shared_export_permission.format(name)), 5), "Shared Export Permission is present" + else: + assert self.is_present_and_displayed((By.XPATH, self.managed_shared_export_permission.format(name))), "Shared Export Permission not present" diff --git a/HQSmokeTests/testPages/users/web_user_page.py b/HQSmokeTests/testPages/users/web_user_page.py index c7a14b07b..321b3a837 100644 --- a/HQSmokeTests/testPages/users/web_user_page.py +++ b/HQSmokeTests/testPages/users/web_user_page.py @@ -216,4 +216,16 @@ def edit_user_permission(self, rolename): self.wait_to_click(self.update_location_btn) - + def change_user_role(self, username, role): + self.wait_to_click(self.web_users_menu) + self.wait_for_element(self.search_user) + self.wait_to_clear_and_send_keys(self.search_user, username) + time.sleep(1) + self.wait_to_click(self.search_user_btn) + time.sleep(2) + self.wait_for_element(self.user_link) + self.wait_to_click(self.user_link) + self.wait_for_element(self.select_project_role_id) + self.select_by_text(self.select_project_role_id, role) + self.wait_to_click(self.update_role_btn) + time.sleep(2) diff --git a/HQSmokeTests/testPages/webapps/web_apps_page.py b/HQSmokeTests/testPages/webapps/web_apps_page.py index f7ca35090..f0ccf49cc 100644 --- a/HQSmokeTests/testPages/webapps/web_apps_page.py +++ b/HQSmokeTests/testPages/webapps/web_apps_page.py @@ -20,6 +20,7 @@ def __init__(self, driver): self.case_name_created = "case_" + fetch_random_string() self.text_value = "text_" + fetch_random_string() + self.form_text_value = "cond_alert_" + fetch_random_string() self.random_value = fetch_random_digit() self.login_as_css = (By.CLASS_NAME, "js-restore-as-item") @@ -28,7 +29,7 @@ def __init__(self, driver): self.sync_button = (By.XPATH, "//h3[.='Sync']") self.home_button = (By.XPATH, "//li[contains(@class,'home')]") self.apps_links = (By.XPATH, "//*[@class='fcc fcc-flower appicon-icon']") - self.web_app_link = (By.XPATH, "//*[text()='" + UserData.reassign_cases_application + "']") + self.web_app_link = (By.XPATH, "//div[@class='appicon-title']//*[text()='" + UserData.reassign_cases_application + "']") self.case_list_link = (By.XPATH, "//*[text()='" + UserData.case_list_name + "']") self.update_case_change_link = (By.XPATH, "//*[text()='" + UserData.update_case_change_link + "']") self.case_register_form = (By.XPATH, "//*[text()='" + UserData.case_register_form + "']") @@ -125,3 +126,22 @@ def submit_case_update_form(self, case_name): def click_case_link(self): case_link = self.get_attribute(self.this_case, "href") self.driver.get(case_link) + + def submit_case_change_register_form_no_value(self): + self.scroll_to_element(self.web_app_link) + time.sleep(3) + # self.wait_for_element(self.web_app_link) + self.js_click(self.web_app_link) + self.wait_for_element(self.update_case_change_link) + self.js_click(self.update_case_change_link) + self.wait_for_element(self.case_register_form) + self.js_click(self.case_register_form) + self.wait_to_clear_and_send_keys(self.enter_text_area, self.form_text_value) + self.js_click(self.form_submit_button) + self.wait_for_ajax() + time.sleep(5) + self.wait_for_element(self.success_message) + assert self.is_displayed(self.success_message), "Form not submitted" + print("Form successfully submitted") + print(self.form_text_value) + return self.form_text_value diff --git a/HQSmokeTests/userInputs/user_inputs.py b/HQSmokeTests/userInputs/user_inputs.py index 25ea5dd99..f7de7b647 100644 --- a/HQSmokeTests/userInputs/user_inputs.py +++ b/HQSmokeTests/userInputs/user_inputs.py @@ -11,10 +11,12 @@ class UserData: reassign_cases_application = 'Reassign Cases' case_pregnancy = "pregnancy" case_reassign = "reassign" + case_reassign_change = "reassign_change" model_type_case = "case" model_type_form = "form" new_form_name = "Android Test Form" app_login = "appiumtest" + new_app_login = "apptest" app_password = "Pass@123" two_fa_user = "2fa.commcare.user@gmail.com" web_user = "[Web Users]" @@ -78,7 +80,8 @@ class UserData: """Conditional Alert""" alert_case_property = "name" alert_case_property_value = "conditional alert" - + alert_case_property_random_value = "enter_a_random_value" + alert_no_value = "does not have a value" """Saved report""" report_for_p1p2 = "Report For P1P2" @@ -88,6 +91,7 @@ class UserData: from_email_prod = "commcarehq-noreply-production@dimagi.com" from_email = "commcarehq-noreply-staging@dimagi.com" from_email_india = "commcarehq-noreply-india@dimagi.com" + from_email_eu = "commcarehq-noreply-eu@dimagi.com" """Report email subjects""" daily_form_activity = "Daily Form Activity: Requested export excel data" @@ -105,3 +109,6 @@ class UserData: parent_type = "pregnancy" child_type = "village" child_name = "Saharanpur" + + private_export_yes = "Smoke Shared Form Export" + private_export_no = "Smoke Shared Private Form Export" \ No newline at end of file diff --git a/LocustScripts/update-scripts/commcarehq-referrals-search-for-beds-mw-login_single_case.py b/LocustScripts/update-scripts/commcarehq-referrals-search-for-beds-mw-login_single_case.py index fccd97506..fd2d2859d 100644 --- a/LocustScripts/update-scripts/commcarehq-referrals-search-for-beds-mw-login_single_case.py +++ b/LocustScripts/update-scripts/commcarehq-referrals-search-for-beds-mw-login_single_case.py @@ -43,6 +43,7 @@ def on_start(self): self.FUNC_ENTER_GENDER = APP_CONFIG["FUNC_ENTER_GENDER"] self.FUNC_OUTGOING_REFERRAL_DETAILS_FORM = APP_CONFIG["FUNC_OUTGOING_REFERRAL_DETAILS_FORM"] self.FUNC_OUTGOING_REFERRAL_DETAILS_FORM_SUBMIT = APP_CONFIG["FUNC_OUTGOING_REFERRAL_DETAILS_FORM_SUBMIT"] + self.FUNC_OPEN_BEDS = APP_CONFIG['FUNC_OPEN_BEDS'] self.cases_per_page = 100 @tag('home_screen') @@ -64,6 +65,26 @@ def search_for_beds_menu(self): if data: self.page_count = data["pageCount"] + @tag('open_bed_search') + @task + def open_bed_search(self): + logging.info( + "Searching open beds for - mobile worker:" + self.user.user_detail.username + "; request: navigate_menu" + ) + data = { + "query_data": { + "m2_results.inline": { + "inputs": { + self.FUNC_OPEN_BEDS['input']: self.FUNC_OPEN_BEDS['inputValue'] + }, + "execute": True + } + }, + "selections": ["0"], + } + self.user.hq_user.navigate("Perform a bed search", data=data) + + @tag('select_cases') @task def select_cases(self): diff --git a/LocustScripts/update-scripts/project-config/co-carecoordination-perf/app_config_referrals_platform.json b/LocustScripts/update-scripts/project-config/co-carecoordination-perf/app_config_referrals_platform.json index 3df2045ef..c1a58fe01 100644 --- a/LocustScripts/update-scripts/project-config/co-carecoordination-perf/app_config_referrals_platform.json +++ b/LocustScripts/update-scripts/project-config/co-carecoordination-perf/app_config_referrals_platform.json @@ -3,7 +3,10 @@ "title":"Client Care Search" }, "FUNC_SEARCH_FOR_BEDS_MENU": { - "selections":"1", "title":"Pilot: Submit Referrals" + "selections":"0", "title":"Send Referrals" + }, + "FUNC_OPEN_BEDS": { + "selections":"0", "input":"only_open_beds", "inputValue":"yes" }, "FUNC_OUTGOING_REFERRALS_MENU": { "selections":"4", "title": "Search Outgoing Referrals" diff --git a/MobileTest/QA_7315/20240422-app-cccStaging-release.apk b/MobileTest/QA_7315/20240422-app-cccStaging-release.apk new file mode 100644 index 000000000..206ec51d1 Binary files /dev/null and b/MobileTest/QA_7315/20240422-app-cccStaging-release.apk differ diff --git a/MobileTest/QA_7315/README.md b/MobileTest/QA_7315/README.md new file mode 100644 index 000000000..646bce8d6 --- /dev/null +++ b/MobileTest/QA_7315/README.md @@ -0,0 +1,54 @@ +## Bulk Form Submission Appium Test Script + +This test script is used to validate that the test the above "over total limit" labels in CCC without having to submit 60 Infant Immunization Record forms in the app. + +## Executing Scripts + +### On Local Machine + +#### Setting up test environment + +```sh + +# create and activate a virtualenv using your preferred method. Example: +python -m venv venv +source venv/bin/activate + + +# install requirements +pip install -r .\MobileTest\ccc_bulk_submission\requires.txt + +``` + +[More on setting up the machine and the scripts](https://docs.google.com/document/d/12C-BJzdDCu0tl3WfwnP90jdzT4SGEMz--p10FrYSJ8Y/edit) + + +#### Running Tests + +- Run tests using pytest command like: + +```sh + +# To execute all the test cases +python .\MobileTest\ccc_bulk_submission\main.py + +``` + + +### Trigger Manually on Gitaction + +clone this repository + +To manually trigger the script, + - Go to [Gitactions](https://github.com/dimagi/dimagi-qa/actions/) + - Select the desired workflow, here [HQ Smoke Tests action](https://github.com/dimagi/dimagi-qa/actions/workflows/hq-smoke-tests.yml) + - Run workflow + - Select workflow as ```master``` + - Select the environment as desired + - Run! + +If you are a part of the QA team, you'll receive emails for the result of the run after it's complete. + +clone this repository + +Besides, you should be able to find the zipped results in the **Artifacts** section, of the corresponding run (after it's complete). diff --git a/MobileTest/QA_7315/__init__.py b/MobileTest/QA_7315/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/MobileTest/QA_7315/commcare_2.53.1.apk b/MobileTest/QA_7315/commcare_2.53.1.apk new file mode 100644 index 000000000..f7ff4852c Binary files /dev/null and b/MobileTest/QA_7315/commcare_2.53.1.apk differ diff --git a/MobileTest/QA_7315/commcare_2.54.1.apk b/MobileTest/QA_7315/commcare_2.54.1.apk new file mode 100644 index 000000000..1e918ba3b Binary files /dev/null and b/MobileTest/QA_7315/commcare_2.54.1.apk differ diff --git a/MobileTest/QA_7315/report.html b/MobileTest/QA_7315/report.html new file mode 100644 index 000000000..9a77c1f1e --- /dev/null +++ b/MobileTest/QA_7315/report.html @@ -0,0 +1,1091 @@ + + + + + report.html + + + + +

report.html

+

Report generated on 11-Dec-2024 at 14:54:57 by pytest-html + v4.1.1

+
+

Environment

+
+
+ + + + + +
+
+

Summary

+
+
+

1 test took 00:06:32.

+

(Un)check the boxes to filter the results.

+
+ +
+
+
+
+ + 1 Failed, + + 0 Passed, + + 0 Skipped, + + 0 Expected failures, + + 0 Unexpected passes, + + 1 Errors, + + 0 Reruns +
+
+  /  +
+
+
+
+
+
+
+
+ + + + + + + + + +
ResultTestDurationLinks
+ + + \ No newline at end of file diff --git a/MobileTest/QA_7315/requires.txt b/MobileTest/QA_7315/requires.txt new file mode 100644 index 000000000..a512b12bd --- /dev/null +++ b/MobileTest/QA_7315/requires.txt @@ -0,0 +1,3 @@ +Appium-Python-Client >= 4.0.0 +selenium == 4.20.0 +pytest \ No newline at end of file diff --git a/MobileTest/QA_7315/test_new_apk.py b/MobileTest/QA_7315/test_new_apk.py new file mode 100644 index 000000000..09f3211e6 --- /dev/null +++ b/MobileTest/QA_7315/test_new_apk.py @@ -0,0 +1,198 @@ +# import os +import random +import string +import time +import unittest +from appium import webdriver +from appium.options.android import UiAutomator2Options +from appium.webdriver.common.appiumby import AppiumBy +from selenium.common import NoSuchElementException, TimeoutException +from selenium.webdriver.support import expected_conditions as ec +from selenium.webdriver.support.wait import WebDriverWait + +app_path = 'C:\\Users\\dsi-user\\PycharmProjects\\Anroid\\apps\\commcare_2.54.1.apk' +capabilities = UiAutomator2Options().load_capabilities({ + "platformName": "Android", + "udid": "emulator-5554", + "automationName": "UIAutomator2", + "deviceName": "Pixel_8_New_APK", + "avd": "Pixel_8_New_APK", + "appWaitPackage": "org.commcare.dalvik", + # "appActivity": "org.commcare.activities.CommCareSetupActivity", + "appWaitActivity": "org.commcare.activities.LoginActivity", + # "appWaitActivity": "org.commcare.activities.DispatchActivity", + "autoGrantPermissions": "true", + "app": app_path, + "noReset": "true", + "fullReset": "false", + "dontStopAppOnReset": "false" + } + ) + +appium_server_url = 'http://localhost:4723/wd/hub' +chars = string.ascii_lowercase + string.digits +random_string = ''.join(random.choices(chars, k=6)) +random_number = random.randint(100, 19999) + + +class TestAppium(unittest.TestCase): + def setUp(self) -> None: + self.driver = webdriver.Remote(appium_server_url, + options=capabilities + ) + + self.case_list_name = 'Case List' + self.form_name = 'Registration Form' + self.enter_code = "//android.widget.TextView[@text='Enter Code']" + self.profile_code = "org.commcare.dalvik:id/edit_profile_location" + self.start_install = "org.commcare.dalvik:id/start_install" + self.install = "//android.widget.TextView[@text='Start Install']" + self.username = "org.commcare.dalvik:id/edit_username" + self.password = "org.commcare.dalvik:id/edit_password" + self.login = "org.commcare.dalvik:id/login_button" + self.start_button = "//android.widget.TextView[@text='Start']" + self.sync_button = "//android.widget.TextView[@text='Sync with Server']" + self.case_list = "//android.widget.TextView[@text='Case List']" + self.form = "//android.widget.TextView[@text='Registration Form']" + self.text_field = "//android.widget.EditText" + self.radio_btn_field = "//*[@text='pune']" + self.submit_button = "//android.widget.TextView[@text='FINISH']" + self.next_btn = "org.commcare.dalvik:id/nav_btn_next" + + # self.go_to_menu = (AppiumBy.ID, "org.commcare.dalvik:id/connect_login_button") + # self.password_field = (AppiumBy.ID, "org.commcare.dalvik:id/connect_password_verify_input") + # self.password_verify_btn = (AppiumBy.ID, "org.commcare.dalvik:id/connect_password_verify_button") + # self.my_jobs = (AppiumBy.ANDROID_UIAUTOMATOR, "new UiSelector().text(\"MY JOBS\")") + # # self.payment_verification_job = (AppiumBy.XPATH, "//android.widget.TextView[@text=\"Payment Verifications\"]//following-sibling::android.widget.ImageView[@resource-id=\"org.commcare.dalvik:id/button\"]\n") + # # self.verification_pay_tab = + # self.launch_app =(AppiumBy.ID,"org.commcare.dalvik:id/connect_progress_button") + # self.start_btn = (AppiumBy.XPATH,"//android.widget.TextView[@text='Start']") + # self.case_list = (AppiumBy.XPATH, "//android.widget.TextView[@text='Case List']") + # self.reg_form = (AppiumBy.XPATH, "//android.widget.TextView[@text='Registration Form']") + # self.text_input = (AppiumBy.XPATH, "//android.widget.EditText") + # self.number_input = (AppiumBy.XPATH, "//android.widget.EditText") + # + # self.finish_btn = (AppiumBy.XPATH, "//android.widget.TextView[@text='FINISH']") + # self.back_btn = (AppiumBy.XPATH, "//android.widget.ImageButton[@content-desc='Navigate up']") + # self.sync_btn = (AppiumBy.XPATH, "//android.widget.TextView[@text='Sync with Server']") + self.log_out = "//android.widget.TextView[@text='Log out of CommCare']" + # self.warning = (AppiumBy.ID, "org.commcare.dalvik:id/connect_progress_delivery_warning_text") + + def tearDown(self) -> None: + if self.driver: + self.driver.quit() + + def click_xpath(self, locator): + element = self.driver.find_element(AppiumBy.XPATH, locator) + element.click() + + def click_id(self, locator): + element = self.driver.find_element(AppiumBy.ID, locator) + element.click() + + def send_text_xpath(self, locator, user_input): + element = self.driver.find_element(AppiumBy.XPATH, locator) + element.send_keys(user_input) + + def send_text_id(self, locator, user_input): + element = self.driver.find_element(AppiumBy.ID, locator) + element.send_keys(user_input) + + def click(self, locator): + time.sleep(2) + clickable = ec.visibility_of_element_located(locator) + element = WebDriverWait(self.driver, 30, poll_frequency=1).until(clickable, + message="Couldn't find locator: " + str( + locator + ) + ) + element.click() + + def send_text(self, locator, value): + time.sleep(2) + clickable = ec.visibility_of_element_located(locator) + element = WebDriverWait(self.driver, 30, poll_frequency=1).until(clickable, + message="Couldn't find locator: " + str( + locator + ) + ) + element.send_keys(value) + + # def send_text_xpath(self, locator, user_input): + # element = self.driver.find_element(AppiumBy.XPATH, locator) + # element.send_keys(user_input) + # + # def send_text_id(self, locator, user_input): + # element = self.driver.find_element(AppiumBy.ID, locator) + # element.send_keys(user_input) + + def wait_for_element(self, locator, timeout=20): + clickable = ec.element_to_be_clickable(locator) + WebDriverWait(self.driver, timeout, poll_frequency=5).until(clickable, + message="Couldn't find locator: " + str(locator) + ) + + def is_enabled(self, locator): + try: + element = self.driver.find_element(*locator) + is_enabled = element.is_enabled() + except TimeoutException: + is_enabled = False + return bool(is_enabled) + # + # def is_displayed(self, locator): + # try: + # element = self.driver.find_element(*locator) + # is_displayed = element.is_displayed() + # except (TimeoutException, NoSuchElementException): + # is_displayed = False + # return bool(is_displayed) + + # def is_present(self, locator): + # try: + # element = self.driver.find_element(*locator) + # is_displayed = True + # except NoSuchElementException: + # is_displayed = False + # return bool(is_displayed) + + def test_form_submission(self) -> None: + # time.sleep(10) + # self.driver.find_element(AppiumBy.XPATH, self.enter_code).click() + # time.sleep(10) + # self.driver.find_element(AppiumBy.ID, self.profile_code).send_keys('4gjhlPe') + # time.sleep(5) + # self.driver.find_element(AppiumBy.ID, self.start_install).click() + # time.sleep(3) + # self.driver.find_element(AppiumBy.XPATH, self.install).click() + time.sleep(25) + self.driver.find_element(AppiumBy.ID, self.username).send_keys('kdd') + self.driver.find_element(AppiumBy.ID, self.password).send_keys('123') + self.driver.find_element(AppiumBy.ID, self.login).click() + time.sleep(30) + self.driver.find_element(AppiumBy.XPATH, self.start_button).click() + time.sleep(10) + self.driver.find_element(AppiumBy.XPATH, self.case_list).click() + time.sleep(10) + self.driver.find_element(AppiumBy.XPATH, self.form).click() + time.sleep(10) + self.driver.find_element(AppiumBy.XPATH, self.text_field).send_keys(random_string) + print(random_string) + self.driver.find_element(AppiumBy.ID, self.next_btn).click() + time.sleep(3) + self.driver.find_element(AppiumBy.XPATH, self.radio_btn_field).click() + time.sleep(3) + self.driver.find_element(AppiumBy.ID, self.next_btn).click() + time.sleep(3) + self.driver.find_element(AppiumBy.XPATH, self.text_field).send_keys('23') + self.driver.find_element(AppiumBy.XPATH, self.submit_button).click() + time.sleep(2) + # assert self.driver.find_element(AppiumBy.XPATH, "//android.widget.TextView[@text='1 form sent to server!']" + # ).is_displayed() + self.driver.find_element(AppiumBy.XPATH, self.sync_button).click() + time.sleep(120) + self.driver.find_element(AppiumBy.XPATH, self.log_out).click() + + +if __name__ == '__main__': + unittest.main() diff --git a/MobileTest/QA_7315/test_old_apk.py b/MobileTest/QA_7315/test_old_apk.py new file mode 100644 index 000000000..81e32fa33 --- /dev/null +++ b/MobileTest/QA_7315/test_old_apk.py @@ -0,0 +1,205 @@ +import os +import random +import string +import time +import unittest +from appium import webdriver +from appium.options.android import UiAutomator2Options +from appium.webdriver.common.appiumby import AppiumBy +from selenium.common import NoSuchElementException, TimeoutException +from selenium.webdriver.support import expected_conditions as ec +from selenium.webdriver.support.wait import WebDriverWait + +app_path = 'C:\\Users\\dsi-user\\PycharmProjects\\Anroid\\apps\\commcare_2.53.1.apk' +capabilities = UiAutomator2Options().load_capabilities({ + "platformName": "Android", + "udid": "emulator-5556", + "automationName": "UIAutomator2", + "deviceName": "Pixel_8_Old_APK", + "avd": "Pixel_8_Old_APK", + "appWaitPackage": "org.commcare.dalvik", + "appActivity": "org.commcare.activities.CommCareSetupActivity", + # "appWaitActivity": "org.commcare.activities.LoginActivity", + # "appWaitActivity": "org.commcare.activities.DispatchActivity", + "autoGrantPermissions": "true", + "app": app_path, + "noReset": "true", + "fullReset": "false", + "dontStopAppOnReset": "false" + } + ) + +appium_server_url = 'http://localhost:4723/wd/hub' +chars = string.ascii_lowercase + string.digits +random_string = ''.join(random.choices(chars, k=6)) +random_number = random.randint(100, 19999) + + +class TestAppium(unittest.TestCase): + def setUp(self) -> None: + self.driver = webdriver.Remote(appium_server_url, + options=capabilities + ) + + self.case_list_name = 'Case List' + self.form_name = 'Registration Form' + self.enter_code = "//android.widget.TextView[@text='Enter Code']" + self.profile_code = "org.commcare.dalvik:id/edit_profile_location" + self.start_install = "org.commcare.dalvik:id/start_install" + self.install = "//android.widget.TextView[@text='Start Install']" + self.username = "org.commcare.dalvik:id/edit_username" + self.password = "org.commcare.dalvik:id/edit_password" + self.login = "org.commcare.dalvik:id/login_button" + self.start_button = "//android.widget.TextView[@text='Start']" + self.sync_button = "//android.widget.TextView[@text='Sync with Server']" + self.case_list = "//android.widget.TextView[@text='Case List']" + self.form = "//android.widget.TextView[@text='Registration Form']" + self.text_field = "//android.widget.EditText" + self.radio_btn_field = "//*[@text='mumbai']" + self.submit_button = "//android.widget.TextView[@text='FINISH']" + self.next_btn = "org.commcare.dalvik:id/nav_btn_next" + + self.go_to_menu = (AppiumBy.ID, "org.commcare.dalvik:id/connect_login_button") + self.password_field = (AppiumBy.ID, "org.commcare.dalvik:id/connect_password_verify_input") + self.password_verify_btn = (AppiumBy.ID, "org.commcare.dalvik:id/connect_password_verify_button") + self.my_jobs = (AppiumBy.ANDROID_UIAUTOMATOR, "new UiSelector().text(\"MY JOBS\")") + self.payment_verification_job = (AppiumBy.XPATH, + "//android.widget.TextView[@text=\"Payment Verifications\"]//following-sibling::android.widget.ImageView[@resource-id=\"org.commcare.dalvik:id/button\"]\n") + + # self.launch_app = (AppiumBy.ID, "org.commcare.dalvik:id/connect_progress_button") + # self.start_btn = (AppiumBy.XPATH, "//android.widget.TextView[@text='Start']") + # self.case_list = (AppiumBy.XPATH, "//android.widget.TextView[@text='Case List']") + # self.reg_form = (AppiumBy.XPATH, "//android.widget.TextView[@text='Registration Form']") + # self.text_input = (AppiumBy.XPATH, "//android.widget.EditText") + # self.number_input = (AppiumBy.XPATH, "//android.widget.EditText") + # + # self.finish_btn = (AppiumBy.XPATH, "//android.widget.TextView[@text='FINISH']") + # self.back_btn = (AppiumBy.XPATH, "//android.widget.ImageButton[@content-desc='Navigate up']") + # self.sync_btn = (AppiumBy.XPATH, "//android.widget.TextView[@text='Sync with Server']") + self.log_out = "//android.widget.TextView[@text='Log out of CommCare']" + # self.warning = (AppiumBy.ID, "org.commcare.dalvik:id/connect_progress_delivery_warning_text") + + def tearDown(self) -> None: + if self.driver: + self.driver.quit() + + def click_xpath(self, locator): + element = self.driver.find_element(AppiumBy.XPATH, locator) + element.click() + + def click_id(self, locator): + element = self.driver.find_element(AppiumBy.ID, locator) + element.click() + + def send_text_xpath(self, locator, user_input): + element = self.driver.find_element(AppiumBy.XPATH, locator) + element.send_keys(user_input) + + def send_text_id(self, locator, user_input): + element = self.driver.find_element(AppiumBy.ID, locator) + element.send_keys(user_input) + + def click(self, locator): + time.sleep(2) + clickable = ec.visibility_of_element_located(locator) + element = WebDriverWait(self.driver, 30, poll_frequency=1).until(clickable, + message="Couldn't find locator: " + str( + locator + ) + ) + element.click() + + def send_text(self, locator, value): + time.sleep(2) + clickable = ec.visibility_of_element_located(locator) + element = WebDriverWait(self.driver, 30, poll_frequency=1).until(clickable, + message="Couldn't find locator: " + str( + locator + ) + ) + element.send_keys(value) + + # def send_text_xpath(self, locator, user_input): + # element = self.driver.find_element(AppiumBy.XPATH, locator) + # element.send_keys(user_input) + # + # def send_text_id(self, locator, user_input): + # element = self.driver.find_element(AppiumBy.ID, locator) + # element.send_keys(user_input) + + def wait_for_element(self, locator, timeout=20): + clickable = ec.element_to_be_clickable(locator) + WebDriverWait(self.driver, timeout, poll_frequency=5).until(clickable, + message="Couldn't find locator: " + str(locator) + ) + + def fetch_random_string(self): + return random_string + + def fetch_random_digit(self): + return str(random_number) + + def is_enabled(self, locator): + try: + element = self.driver.find_element(*locator) + is_enabled = element.is_enabled() + except TimeoutException: + is_enabled = False + return bool(is_enabled) + + def is_displayed(self, locator): + try: + element = self.driver.find_element(*locator) + is_displayed = element.is_displayed() + except (TimeoutException, NoSuchElementException): + is_displayed = False + return bool(is_displayed) + + def is_present(self, locator): + try: + element = self.driver.find_element(*locator) + is_displayed = True + except NoSuchElementException: + is_displayed = False + return bool(is_displayed) + + def test_form_submission(self) -> None: + time.sleep(10) + self.driver.find_element(AppiumBy.XPATH, self.enter_code).click() + time.sleep(10) + self.driver.find_element(AppiumBy.ID, self.profile_code).send_keys('4gjhlPe') + time.sleep(5) + self.driver.find_element(AppiumBy.ID, self.start_install).click() + time.sleep(3) + self.driver.find_element(AppiumBy.XPATH, self.install).click() + time.sleep(25) + self.driver.find_element(AppiumBy.ID, self.username).send_keys('04') + self.driver.find_element(AppiumBy.ID, self.password).send_keys('123') + self.driver.find_element(AppiumBy.ID, self.login).click() + time.sleep(70) + self.driver.find_element(AppiumBy.XPATH, self.start_button).click() + time.sleep(10) + self.driver.find_element(AppiumBy.XPATH, self.case_list).click() + time.sleep(3) + self.driver.find_element(AppiumBy.XPATH, self.form).click() + time.sleep(3) + self.driver.find_element(AppiumBy.XPATH, self.text_field).send_keys(random_string) + print(random_string) + self.driver.find_element(AppiumBy.ID, self.next_btn).click() + time.sleep(3) + self.driver.find_element(AppiumBy.XPATH, self.radio_btn_field).click() + time.sleep(3) + self.driver.find_element(AppiumBy.ID, self.next_btn).click() + time.sleep(3) + self.driver.find_element(AppiumBy.XPATH, self.text_field).send_keys('23') + self.driver.find_element(AppiumBy.XPATH, self.submit_button).click() + time.sleep(2) + # assert self.driver.find_element(AppiumBy.XPATH, "//android.widget.TextView[@text='1 form sent to server!']" + # ).is_displayed() + self.driver.find_element(AppiumBy.XPATH, self.sync_button).click() + time.sleep(120) + self.driver.find_element(AppiumBy.XPATH, self.log_out).click() + + +if __name__ == '__main__': + unittest.main() diff --git a/P1P2Tests/requires.txt b/P1P2Tests/requires.txt index 7f9444a4f..556c100a8 100644 --- a/P1P2Tests/requires.txt +++ b/P1P2Tests/requires.txt @@ -11,6 +11,7 @@ matplotlib >= 3.3.4 pytest-rerunfailures pytest-xdist pytest-xdist[psutil] +Appium-Python-Client >= 2.10.0 pyotp >=2.6.0 pytest-order requests diff --git a/P1P2Tests/testCases/conftest.py b/P1P2Tests/testCases/conftest.py index b28df53f6..aea4cc5a9 100644 --- a/P1P2Tests/testCases/conftest.py +++ b/P1P2Tests/testCases/conftest.py @@ -34,7 +34,7 @@ def environment_settings_hq(): for instructions on how to set them. """ settings = {} - for name in ["url", "login_username", "login_password", "mail_username", + for name in ["url", "login_username", "login_password", "bs_user", "bs_key", "mail_username", "mail_password", "imap_password"]: var = f"DIMAGIQA_{name.upper()}" @@ -54,7 +54,7 @@ def settings(environment_settings_hq): if os.environ.get("CI") == "true": settings = environment_settings_hq settings["CI"] = "true" - if any(x not in settings for x in ["url", "login_username", "login_password", + if any(x not in settings for x in ["url", "login_username", "login_password", "bs_user", "bs_key", "mail_username", "mail_password", "imap_password"]): lines = environment_settings_hq.__doc__.splitlines() vars_ = "\n ".join(line.strip() for line in lines if "DIMAGIQA_" in line) diff --git a/P1P2Tests/testCases/test_02_users.py b/P1P2Tests/testCases/test_02_users.py index 4f81a0162..58e2d44f0 100644 --- a/P1P2Tests/testCases/test_02_users.py +++ b/P1P2Tests/testCases/test_02_users.py @@ -3,8 +3,11 @@ import pytest +from HQSmokeTests.testPages.android.android_screen import AndroidScreen +from HQSmokeTests.testPages.applications.application_page import ApplicationPage from HQSmokeTests.testPages.users.group_page import GroupPage from HQSmokeTests.userInputs.user_inputs import UserData +from P1P2Tests.testCases.conftest import rerun_count from common_utilities.generate_random_string import fetch_random_string from HQSmokeTests.testPages.home.home_page import HomePage from HQSmokeTests.testPages.users.mobile_workers_page import MobileWorkerPage @@ -16,6 +19,21 @@ group_id["user_new"] = None + +@pytest.mark.user +@pytest.mark.mobileWorker +@pytest.mark.mobileWorker +@pytest.mark.p1p2EscapeDefect +def test_case_89_verify_user_location_alert(driver, settings): + mw = MobileWorkerPage(driver) + menu = HomePage(driver, settings) + menu.users_menu() + mw.mobile_worker_menu() + mw.select_mobile_worker_created(UserData.app_login) + mw.select_location() + mw.remove_location() + mw.verify_location_alert_not_present() + @pytest.mark.user @pytest.mark.mobileWorker @pytest.mark.user_profiles @@ -93,3 +111,30 @@ def test_aftertest_cleanup_items_in_users_menu(driver, settings): clean2.click_group_menu() clean2.delete_test_groups() print("Deleted the group") + + +@pytest.mark.application +@pytest.mark.appSettings +@pytest.mark.p1p2EscapeDefect +def test_case_91_login_with_new_password(driver, settings, rerun_count): + menu = HomePage(driver, settings) + menu.applications_menu(UserData.village_application) + load = ApplicationPage(driver) + code = load.get_app_code(UserData.village_application) + username = f"username_{rerun_count}{fetch_random_string()}" + worker = MobileWorkerPage(driver) + menu = HomePage(driver, settings) + menu.users_menu() + # worker.delete_bulk_users() + worker.mobile_worker_menu() + worker.create_mobile_worker() + worker.mobile_worker_enter_username(username) + worker.mobile_worker_enter_password(fetch_random_string()) + worker.click_create(username) + mobile = AndroidScreen(settings) + mobile.verify_login_with_old_password(code, username, fetch_random_string()) + worker.mobile_worker_menu() + worker.select_mobile_worker_created(username) + worker.reset_mobile_worker_password("new_"+fetch_random_string()) + mobile.verify_login_with_new_password(username, "new_"+fetch_random_string()) + mobile.close_android_driver() diff --git a/P1P2Tests/testCases/test_03_exports.py b/P1P2Tests/testCases/test_03_exports.py new file mode 100644 index 000000000..b8808300a --- /dev/null +++ b/P1P2Tests/testCases/test_03_exports.py @@ -0,0 +1,49 @@ +import pytest + +from HQSmokeTests.testPages.data.export_data_page import ExportDataPage +from HQSmokeTests.testPages.home.home_page import HomePage +from P1P2Tests.userInputs.user_inputs import UserData + +""""Contains test cases related to the Exports module""" + +@pytest.mark.data +@pytest.mark.exportsFormData +@pytest.mark.p1p2EscapeDefect +def test_case_21_form_exports(driver, settings): + home = HomePage(driver, settings) + home.data_menu() + export = ExportDataPage(driver) + name = export.add_form_exports() + export.form_exports(name) + +@pytest.mark.data +@pytest.mark.exportsCaseData +@pytest.mark.p1p2EscapeDefect +def test_case_21_case_exports(driver, settings): + home = HomePage(driver, settings) + home.data_menu() + export = ExportDataPage(driver) + name = export.add_case_exports() + export.case_exports(name) + + +@pytest.mark.data +@pytest.mark.exportsFormData +@pytest.mark.p1p2EscapeDefect +def test_case_88_repeat_form_exports(driver, settings): + home = HomePage(driver, settings) + home.data_menu() + export = ExportDataPage(driver) + export.add_repeat_form_exports(UserData.basic_test_app[0], UserData.basic_test_app[1], UserData.basic_test_app[2], UserData.repeat_form_export_name) + + + +@pytest.mark.data +@pytest.mark.deleteBulkExports +def test_exports_cleanup(driver, settings): + home = HomePage(driver, settings) + home.data_menu() + export = ExportDataPage(driver) + export.delete_all_bulk_exports() + + diff --git a/P1P2Tests/testCases/test_04_integration_exports.py b/P1P2Tests/testCases/test_04_integration_exports.py index 3d8e9172f..a7852be0a 100644 --- a/P1P2Tests/testCases/test_04_integration_exports.py +++ b/P1P2Tests/testCases/test_04_integration_exports.py @@ -31,3 +31,14 @@ def test_case_26_excel_dashboard_integration_case(driver, settings): link = export.check_feed_link(case) export.verify_duplicate_data_in_dashboard(link, settings['login_username'], settings['login_password']) +@pytest.mark.data +@pytest.mark.powerBiTableauIntegrationCase +@pytest.mark.p1p2EscapeDefect +#SAAS-13243, SAAS-14468 +def test_case_27_powerbi_tableau_integration_case(driver, settings): + username = settings["login_username"] + password = settings["login_password"] + home = HomePage(driver, settings) + home.data_menu() + export = ExportDataPage(driver) + export.power_bi_tableau_integration_case(username, password) \ No newline at end of file diff --git a/P1P2Tests/testCases/test_05_roles.py b/P1P2Tests/testCases/test_05_roles.py index 2c7335cd6..3b01e9c69 100644 --- a/P1P2Tests/testCases/test_05_roles.py +++ b/P1P2Tests/testCases/test_05_roles.py @@ -107,4 +107,4 @@ def test_cleanup_items_in_role_menu(driver, settings): menu.users_menu() clean3.roles_menu_click() clean3.delete_test_roles() - print("Deleted the role") + print("Deleted the role") \ No newline at end of file diff --git a/P1P2Tests/testCases/test_06_data.py b/P1P2Tests/testCases/test_06_data.py new file mode 100644 index 000000000..447d070bc --- /dev/null +++ b/P1P2Tests/testCases/test_06_data.py @@ -0,0 +1,34 @@ +import pytest + +from HQSmokeTests.testPages.data.copy_cases_page import CopyCasesPage +from HQSmokeTests.testPages.data.data_dictionary_page import DataDictionaryPage +from HQSmokeTests.testPages.data.deduplicate_case_page import DeduplicateCasePage +from HQSmokeTests.testPages.data.manage_forms_page import ManageFormsPage +from HQSmokeTests.testPages.data.import_cases_page import ImportCasesPage +from HQSmokeTests.testPages.data.reassign_cases_page import ReassignCasesPage +from HQSmokeTests.testPages.data.auto_case_update_page import AutoCaseUpdatePage +from HQSmokeTests.testPages.data.lookup_table_page import LookUpTablePage +from HQSmokeTests.testPages.home.home_page import HomePage + +""""Contains test cases related to the Data module""" + + +@pytest.mark.data +@pytest.mark.reassignCases +@pytest.mark.p1p2EscapeDefect +def test_case_30_reassign_cases(driver, settings): + home = HomePage(driver, settings) + home.data_menu() + reassign = ReassignCasesPage(driver, settings) + reassign.get_cases(settings['login_username']) + reassign.reassign_case() + +@pytest.mark.data +@pytest.mark.copyCases +@pytest.mark.p1p2EscapeDefect +def test_case_60_copy_cases(driver, settings): + home = HomePage(driver, settings) + home.data_menu() + copy = CopyCasesPage(driver, settings) + copy.get_cases(settings['login_username']) + copy.copy_case() diff --git a/P1P2Tests/testCases/test_07_applications.py b/P1P2Tests/testCases/test_07_applications.py new file mode 100644 index 000000000..06be1c7e7 --- /dev/null +++ b/P1P2Tests/testCases/test_07_applications.py @@ -0,0 +1,45 @@ +import pytest + +from HQSmokeTests.testPages.applications.app_preview import AppPreviewPage +from HQSmokeTests.testPages.applications.application_page import ApplicationPage +from HQSmokeTests.testPages.android.android_screen import AndroidScreen +from HQSmokeTests.testPages.home.home_page import HomePage +from HQSmokeTests.testPages.reports.report_page import ReportPage +from P1P2Tests.userInputs.user_inputs import UserData + +""""Contains test cases related to the Application module""" + +@pytest.mark.application +@pytest.mark.appSettings +@pytest.mark.p1p2EscapeDefect +def test_case_84_verify_form_settings(driver, settings): + menu = HomePage(driver, settings) + menu.applications_menu(UserData.reassign_cases_application) + load = ApplicationPage(driver) + load.verify_form_settings_page(UserData.form_name) + load.verify_form_settings_page(UserData.followup_form_name) + +@pytest.mark.application +@pytest.mark.appSettings +@pytest.mark.p1p2EscapeDefect +def test_case_85_verify_app_version_page(driver, settings): + menu = HomePage(driver, settings) + menu.applications_menu(UserData.reassign_cases_application) + load = ApplicationPage(driver) + load.verify_app_version_page() + +@pytest.mark.application +@pytest.mark.appSettings +@pytest.mark.p1p2EscapeDefect +def test_case_90_verify_app_installation(driver, settings): + menu = HomePage(driver, settings) + menu.applications_menu(UserData.village_application) + load = ApplicationPage(driver) + code = load.get_app_code(UserData.village_application) + mobile = AndroidScreen(settings) + mobile.verify_app_install(code) + mobile.close_android_driver() + + + + diff --git a/P1P2Tests/testCases/test_08_reports.py b/P1P2Tests/testCases/test_08_reports.py index 4ac08166e..a73b47803 100644 --- a/P1P2Tests/testCases/test_08_reports.py +++ b/P1P2Tests/testCases/test_08_reports.py @@ -3,6 +3,7 @@ from HQSmokeTests.testPages.home.home_page import HomePage from HQSmokeTests.testPages.reports.report_page import ReportPage from HQSmokeTests.testPages.webapps.web_apps_page import WebAppsPage +from P1P2Tests.userInputs.user_inputs import UserData """"Contains test cases related to the Data module""" @@ -22,3 +23,57 @@ def test_case_17_create_form_report(driver, settings): load.configure_add_report() load.delete_report() +@pytest.mark.reportBuilderForm +@pytest.mark.reportBuilderCase +@pytest.mark.editReport +@pytest.mark.p1p2EscapeDefect +def test_case_17_create_case_report(driver, settings): + report = HomePage(driver, settings) + driver.refresh() + report.reports_menu() + load = ReportPage(driver) + load.create_report_builder_case_report() + load.delete_report() + +@pytest.mark.report +@pytest.mark.caseListPage +@pytest.mark.p1p2EscapeDefect +def test_case_82_check_case_list(driver, settings): + home = HomePage(driver, settings) + home.reports_menu() + report = ReportPage(driver) + report.verify_case_list_page() + +@pytest.mark.report +@pytest.mark.caseListPage +@pytest.mark.p1p2EscapeDefect +def test_case_86_export_to_excel_config_report(driver, settings): + home = HomePage(driver, settings) + home.reports_menu() + report = ReportPage(driver) + report.export_to_excel_config_report(UserData.report_for_p1p2) + +@pytest.mark.report +@pytest.mark.applicationStatusPage +@pytest.mark.p1p2EscapeDefect +@pytest.mark.skip +def test_case_87_application_status_report(driver, settings): + home = HomePage(driver, settings) + home.reports_menu() + report = ReportPage(driver) + report.application_status_report_search() + report.verify_sorted_list() + + +@pytest.mark.report +@pytest.mark.caseListExplorer +@pytest.mark.p1p2EscapeDefect +def test_case_92_verify_case_list_explorer_properties(driver, settings): + home = HomePage(driver, settings) + home.reports_menu() + report = ReportPage(driver) + name = report.verify_case_list_explorer_properties() + report.add_new_property(name) + + + diff --git a/P1P2Tests/testCases/test_09_messaging.py b/P1P2Tests/testCases/test_09_messaging.py new file mode 100644 index 000000000..0835b544b --- /dev/null +++ b/P1P2Tests/testCases/test_09_messaging.py @@ -0,0 +1,49 @@ +import pytest + +from HQSmokeTests.testPages.home.home_page import HomePage +from HQSmokeTests.testPages.messaging.messaging_page import MessagingPage +from HQSmokeTests.testPages.reports.report_page import ReportPage +from common_utilities.generate_random_string import fetch_random_string + +""""Contains test cases related to the Messaging module""" + + + +@pytest.mark.messaging +@pytest.mark.broadcasts +@pytest.mark.p1p2EscapeDefect +def test_case_43_broadcast(driver, settings, rerun_count): + menu = HomePage(driver, settings) + msg = MessagingPage(driver) + broadcast_input = f"broadcast_{fetch_random_string()}{rerun_count}" + menu.messaging_menu() + msg.send_broadcast_message(broadcast_input) + + +@pytest.mark.messaging +@pytest.mark.conditionalAlerts +@pytest.mark.report +@pytest.mark.reportMessaging +@pytest.mark.p1p2EscapeDefect +def test_case_44_create_cond_alert(driver, settings, rerun_count): + menu = HomePage(driver, settings) + msg = MessagingPage(driver) + cond_alert_name_input = f"cond_alert_{fetch_random_string()}{rerun_count}" + menu.messaging_menu() + cond_alert = msg.create_cond_alert(cond_alert_name_input) + menu.reports_menu() + history = ReportPage(driver) + history.validate_messaging_history_for_cond_alert(cond_alert) + menu.messaging_menu() + msg.remove_cond_alert(cond_alert_name_input) + + +@pytest.mark.projectSettings +@pytest.mark.currentSubscription +@pytest.mark.p1p2EscapeDefect +def test_case_52_settings_pages(driver, settings): + msg = MessagingPage(driver) + home = HomePage(driver, settings) + home.project_settings_page() + msg.current_subscription_page() + diff --git a/P1P2Tests/testCases/test_10_p1_p2_defects.py b/P1P2Tests/testCases/test_10_p1_p2_defects.py index c58f96e6b..77d4bd518 100644 --- a/P1P2Tests/testCases/test_10_p1_p2_defects.py +++ b/P1P2Tests/testCases/test_10_p1_p2_defects.py @@ -1,15 +1,19 @@ import pytest +from HQSmokeTests.testPages.android.android_screen import AndroidScreen from HQSmokeTests.testPages.applications.app_preview import AppPreviewPage from HQSmokeTests.testPages.applications.application_page import ApplicationPage from HQSmokeTests.testPages.data.export_data_page import ExportDataPage from HQSmokeTests.testPages.data.import_cases_page import ImportCasesPage from HQSmokeTests.testPages.email.email_verification import EmailVerification from HQSmokeTests.testPages.home.home_page import HomePage +from HQSmokeTests.testPages.messaging.messaging_page import MessagingPage from HQSmokeTests.testPages.project_settings.repeaters_page import RepeatersPage from HQSmokeTests.testPages.reports.report_page import ReportPage +from HQSmokeTests.testPages.webapps.web_apps_page import WebAppsPage from HQSmokeTests.userInputs.user_inputs import UserData +from common_utilities.generate_random_string import fetch_random_string values = dict() values['flag'] = False @@ -35,6 +39,7 @@ def test_case_71_case_owner_list_explorer(driver, settings): @pytest.mark.report @pytest.mark.p1p2EscapeDefect +@pytest.mark.xfail def test_case_75_daily_form_activity(driver, settings): home = HomePage(driver, settings) home.reports_menu() @@ -61,11 +66,12 @@ def test_case_76_application_status(driver, settings): @pytest.mark.application @pytest.mark.appBuilder @pytest.mark.p1p2EscapeDefect -def test_case_77_create_new_app(driver, settings): +def test_case_77_create_new_app(driver, settings, rerun_count): if "india" in settings['url']: pytest.skip("Skipping for this month as limit exhausted") + app_p1p2_name = f"App P1P2 {rerun_count}{fetch_random_string()}" load = ApplicationPage(driver) - app_name = load.create_application_with_verifications() + app_name = load.create_application_with_verifications(app_p1p2_name) app = AppPreviewPage(driver) lat, lon = app.submit_form_with_loc() home = HomePage(driver, settings) @@ -132,4 +138,46 @@ def test_case_81_parent_child_case_imports(driver, settings): home.data_menu() export.verify_case_import(assignment) +@pytest.mark.projectSettings +@pytest.mark.createRepeater +@pytest.mark.editRepeater +@pytest.mark.p1p2EscapeDefect +def test_case_83_data_forwarding_add_edit(driver, settings): + home = HomePage(driver, settings) + home.project_settings_page() + repeater = RepeatersPage(driver) + repeater.delete_all_repeaters() + repeater.add_repeater() + repeater.edit_repeater() + repeater.delete_repeater() + +@pytest.mark.data +@pytest.mark.p1p2EscapeDefect +@pytest.mark.xfail +def test_case_93_cond_alert_on_form_submit(driver, settings, rerun_count): + menu = HomePage(driver, settings) + msg = MessagingPage(driver) + menu.messaging_menu() + msg.remove_all_cond_alert() + menu.messaging_menu() + cond_alert, subject = msg.create_cond_alert_for_doesnot_have_value(rerun_count) + menu.web_apps_menu() + webapps = WebAppsPage(driver) + webapps.verify_apps_presence() + case_name = webapps.submit_case_change_register_form_no_value() + menu = HomePage(driver, settings) + menu.applications_menu(UserData.reassign_cases_application) + load = ApplicationPage(driver) + code = load.get_app_code(UserData.reassign_cases_application) + mobile = AndroidScreen(settings) + mobile.verify_app_install(code) + mobile.close_android_driver() + menu.reports_menu() + report = ReportPage(driver) + case_id = report.get_case_id_from_case_list_explorer(case_name) + export = ExportDataPage(driver) + menu.data_menu() + export.check_for_case_id(case_id) + email = EmailVerification(settings) + email.verify_email_sent(subject, settings['url'], sleep="YES") diff --git a/P1P2Tests/userInputs/user_inputs.py b/P1P2Tests/userInputs/user_inputs.py index d6ff74492..6e9d96313 100644 --- a/P1P2Tests/userInputs/user_inputs.py +++ b/P1P2Tests/userInputs/user_inputs.py @@ -29,6 +29,10 @@ class UserData: user_group = "automation_user" web_user = "[Web Users]" + + basic_test_app = ["Basic Tests", "Formplayer Specific Tests", "[Formplayer] Repeats"] + repeat_form_export_name = "Smoke Repeat Form Export" + # Phone Number area_code = "91" @@ -36,6 +40,7 @@ class UserData: app_type = "Applications" case_list_name = 'Case List' form_name = 'Registration Form' + followup_form_name = "Followup Form" login_as = 'henry' update_case_change_link = "Case Change" case_register_form = "Case Register" diff --git a/QA_Requests/Vaccine/README.md b/QA_Requests/Vaccine/README.md index 83f20ad36..74b1fdd48 100644 --- a/QA_Requests/Vaccine/README.md +++ b/QA_Requests/Vaccine/README.md @@ -21,5 +21,5 @@ pip install -r requires.txt - Run tests ```sh -python main.py +python test_new_apk.py ``` diff --git a/common_utilities/selenium/base_page.py b/common_utilities/selenium/base_page.py index 177bf4c2c..d873b4a3a 100644 --- a/common_utilities/selenium/base_page.py +++ b/common_utilities/selenium/base_page.py @@ -98,7 +98,7 @@ def wait_to_get_value(self, locator, timeout=10): return element_text @retry_on_exception((StaleElementReferenceException, TimeoutException)) - def wait_for_element(self, locator, timeout=10): + def wait_for_element(self, locator, timeout=30): clickable = ec.presence_of_element_located(locator) WebDriverWait(self.driver, timeout, poll_frequency=1).until(clickable, message="Couldn't find locator: " + str(locator) @@ -648,3 +648,23 @@ def back(self): except Exception as js_e: print(f"[ERROR] JavaScript fallback also failed: {js_e}") raise + + def set_ace_editor_text(self, locator, text): + script = """ + var text = arguments[0]; + var container = document.querySelector(arguments[1]); + if (!container) return; + var editorEl = container.querySelector('.ace_editor'); + if (!editorEl || !window.ace) return; + var editor = ace.edit(editorEl); + editor.focus(); + editor.setValue(text, 1); + editor.clearSelection(); + """ + self.driver.execute_script(script, text, locator) + + def wait_for_page_title(self, title, timeout=20): + WebDriverWait(self.driver, timeout).until( + ec.title_is(title) + ) + print(f"✅ Page loaded: {title}") \ No newline at end of file