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
+
+
+
+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.
+
+
+
+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 generated on 11-Dec-2024 at 14:54:57 by pytest-html + v4.1.1
+1 test took 00:06:32.
+(Un)check the boxes to filter the results.
+Result | +Test | +Duration | +Links | +
---|