diff --git a/HQSmokeTests/testPages/android/android_screen.py b/HQSmokeTests/testPages/android/android_screen.py
index cc4730a4d..4ded2439b 100644
--- a/HQSmokeTests/testPages/android/android_screen.py
+++ b/HQSmokeTests/testPages/android/android_screen.py
@@ -1,6 +1,7 @@
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
+from selenium.webdriver.support import expected_conditions as ec
from HQSmokeTests.userInputs.user_inputs import UserData
from appium.options.android import UiAutomator2Options
@@ -69,6 +70,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)
@@ -86,6 +88,11 @@ 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 install_app_and_submit_form(self, code, random_text):
self.driver.find_element(AppiumBy.XPATH, self.enter_code).click()
self.driver.find_element(AppiumBy.ID, self.profile_code).send_keys(code)
@@ -93,7 +100,7 @@ def install_app_and_submit_form(self, code, random_text):
time.sleep(3)
self.driver.find_element(AppiumBy.XPATH, self.install).click()
time.sleep(15)
- self.driver.find_element(AppiumBy.ID, self.username).send_keys(UserData.app_login)
+ self.driver.find_element(AppiumBy.ID, self.username).send_keys(UserData.new_app_login)
self.driver.find_element(AppiumBy.ID, self.password).send_keys(UserData.app_password)
self.driver.find_element(AppiumBy.ID, self.login).click()
time.sleep(50)
@@ -111,5 +118,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/application_page.py b/HQSmokeTests/testPages/applications/application_page.py
index a5ebbb30b..9152f407d 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']")
@@ -110,6 +115,8 @@ def __init__(self, driver):
self.override_btn = (By.XPATH, "//button[contains(.,'Overwrite their work')]")
self.enter_app_code_link = (By.LINK_TEXT, "Enter App Code")
+
+
# language tab
self.language_option = "//select[contains(@data-bind,'langcode')]/option[.='{}']"
self.add_language_button = (By.XPATH, "//button[contains(@data-bind,'addLanguage')]")
@@ -428,3 +435,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 a70ed2972..44c926372 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]")
@@ -38,7 +37,9 @@ def __init__(self, driver, settings):
self.copied_user_from_list = "//li[starts-with(text(), '{}')]"
self.success_message = (By.XPATH, "//*[@data-bind='html: message' and contains(.,'Cases copied')]")
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)
@@ -47,14 +48,30 @@ def sort_for_latest_on_top(self):
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(5)
- 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(5)
@@ -66,20 +83,24 @@ def copy_case(self):
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(5)
- self.wait_for_element(self.success_message, 30)
+ 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)
+ self.driver.refresh()
time.sleep(5)
- self.wait_for_element(self.apply, 70)
- self.select_by_text(self.user_search_dropdown, assigned_username)
+ 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(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
diff --git a/HQSmokeTests/testPages/data/export_data_page.py b/HQSmokeTests/testPages/data/export_data_page.py
index 74d3ea035..9716f9cff 100644
--- a/HQSmokeTests/testPages/data/export_data_page.py
+++ b/HQSmokeTests/testPages/data/export_data_page.py
@@ -69,6 +69,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')
@@ -169,6 +170,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)
@@ -840,3 +849,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..be5ac5b48 100644
--- a/HQSmokeTests/testPages/email/email_verification.py
+++ b/HQSmokeTests/testPages/email/email_verification.py
@@ -28,8 +28,8 @@ def get_hyperlink_from_latest_email(self, subject, url):
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")
+ mailbox.fetch(AND(subject=subject, from_=from_email, date=datetime.date.today()))]
+ 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'))
@@ -49,7 +49,7 @@ def get_email_body_from_latest_email(self, subject, url):
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 +61,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 = []
@@ -88,7 +88,7 @@ def get_email_body_from_latest_email_proj_perf(self, subject, url):
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 +128,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 +182,20 @@ 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):
+ if 'www' in url:
+ from_email = UserData.from_email_prod
+ elif 'india' in url:
+ from_email = UserData.from_email_india
+ else:
+ from_email = UserData.from_email
+
+ with MailBox(self.imap_host).login(self.imap_user, self.imap_pass, 'INBOX') as mailbox:
+ for msg in mailbox.fetch(
+ AND(from_=from_email, date=datetime.date.today())
+ ):
+ if msg.subject == subject:
+ print("Email is received")
+ assert True
diff --git a/HQSmokeTests/testPages/home/home_page.py b/HQSmokeTests/testPages/home/home_page.py
index c44c4a9a7..544fa67ae 100644
--- a/HQSmokeTests/testPages/home/home_page.py
+++ b/HQSmokeTests/testPages/home/home_page.py
@@ -138,3 +138,4 @@ def project_settings_page(self, value=None):
self.js_click(self.project_settings_menu)
assert self.PROJECT_SETTINGS == self.driver.title, "This is not the Project Settings page."
print("Project Settings page loaded successfully!")
+
diff --git a/HQSmokeTests/testPages/messaging/messaging_page.py b/HQSmokeTests/testPages/messaging/messaging_page.py
index 972a2c9e9..e1e80d2db 100644
--- a/HQSmokeTests/testPages/messaging/messaging_page.py
+++ b/HQSmokeTests/testPages/messaging/messaging_page.py
@@ -18,6 +18,7 @@ def __init__(self, driver):
super().__init__(driver)
self.cond_alert_name_input = "cond_alert_" + fetch_random_string()
+ self.cond_alert_no_value_name_input = "cond_alert_no_value_" + fetch_random_string()
self.keyword_name_input = "KEYWORD_" + fetch_random_string().upper()
self.struct_keyword_name_input = "STRUCTURED_KEYWORD_" + fetch_random_string().upper()
self.broadcast_input = "broadcast_" + fetch_random_string()
@@ -38,6 +39,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+"']")
@@ -61,17 +63,15 @@ 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 = (
By.XPATH, "//button[@data-bind='click: handleRuleNavContinue, enable: ruleTabValid']")
- self.cond_alert_created = (By.XPATH, "//a[text()='" + str(self.cond_alert_name_input) + "']")
- self.restart_rule_button = (By.XPATH, "//td[./a[text()='" + str(
- self.cond_alert_name_input) + "']]//following-sibling::td/div/button[contains(@data-bind,'restart')]")
- self.restart_rule_button_none = (By.XPATH, "//td[./a[text()='" + str(
- self.cond_alert_name_input) + "']]//following-sibling::td/div[@style='display: none;']/button[contains(@data-bind,'restart')]")
- self.deactive_button_visible = (By.XPATH, "//td[./a[text()='" + str(
- self.cond_alert_name_input) + "']]//following-sibling::td/button[contains(@data-bind,'toggleStatus')]/span[contains(@data-bind,'visible: active')]")
+ self.cond_alert_created = "//a[text()='{}']"
+ self.restart_rule_button = "//td[./a[text()='{}']]//following-sibling::td/div/button[contains(@data-bind,'restart')]"
+ self.restart_rule_button_none = "//td[./a[text()='{}']]//following-sibling::td/div[@style='display: none;']/button[contains(@data-bind,'restart')]"
+ self.deactive_button_visible = "//td[./a[text()='{}']]//following-sibling::td/button[contains(@data-bind,'toggleStatus')]/span[contains(@data-bind,'visible: active')]"
self.empty_table_alert = (
By.XPATH, "//div[contains(@data-bind, 'emptyTable()')][contains(.,'There are no alerts to display')]")
self.select_recipient_type = (By.XPATH, "//ul[@id='select2-id_schedule-recipient_types-results']/li[.='Users']")
@@ -79,8 +79,7 @@ def __init__(self, driver):
self.user_recipients_results = (
By.XPATH, "//ul[@id='select2-id_schedule-user_recipients-results']/li[.='" + UserData.app_login + "']")
self.save_button_xpath = (By.XPATH, "//button[@type='submit'and text()='Save']")
- self.delete_cond_alert = (By.XPATH, "//a[text()='" + str(
- self.cond_alert_name_input) + "']//preceding::button[@class='btn btn-danger'][1]")
+ self.delete_cond_alert = "//a[text()='{}']//preceding::button[@class='btn btn-danger'][1]"
self.search_box = (By.XPATH, "//form[@class='input-group']/input[@class='form-control']")
self.search_btn = (
By.XPATH, "//form[@class='input-group']//button[@data-bind='click: clickAction, visible: !immediate']")
@@ -243,13 +242,13 @@ def create_cond_alert(self):
self.wait_to_clear_and_send_keys(self.search_box, self.cond_alert_name_input)
time.sleep(10)
self.wait_to_click(self.search_box)
- self.wait_for_element(self.delete_cond_alert, 700)
+ self.wait_for_element((By.XPATH, self.delete_cond_alert.format(self.cond_alert_name_input)), 700)
self.driver.refresh()
- if self.is_clickable(self.delete_cond_alert):
+ if self.is_clickable((By.XPATH, self.delete_cond_alert.format(self.cond_alert_name_input))):
print("Restart is not required.")
else:
try:
- self.js_click(self.restart_rule_button)
+ self.js_click((By.XPATH, self.restart_rule_button.format(self.cond_alert_name_input)))
self.accept_pop_up()
time.sleep(5)
self.accept_pop_up()
@@ -257,14 +256,14 @@ def create_cond_alert(self):
time.sleep(360)
self.wait_to_clear_and_send_keys(self.search_box, self.cond_alert_name_input)
self.wait_to_click(self.search_box)
- self.wait_for_element(self.delete_cond_alert, 700)
+ self.wait_for_element((By.XPATH, self.delete_cond_alert.format(self.cond_alert_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, self.cond_alert_name_input)
self.wait_to_click(self.search_box)
- assert self.is_displayed(self.cond_alert_created), "Conditional Alert not created successfully!"
+ assert self.is_displayed((By.XPATH, self.cond_alert_created.format(self.cond_alert_name_input))), "Conditional Alert not created successfully!"
print("Conditional Alert created successfully!")
return self.cond_alert_name_input
@@ -498,9 +497,9 @@ def remove_cond_alert(self):
self.driver.refresh()
self.wait_to_clear_and_send_keys(self.search_box, self.cond_alert_name_input)
self.wait_and_sleep_to_click(self.search_box)
- self.wait_for_element(self.delete_cond_alert, 300)
+ self.wait_for_element((By.XPATH, self.delete_cond_alert.format(self.cond_alert_name_input)), 300)
time.sleep(5)
- self.wait_to_click(self.delete_cond_alert)
+ self.wait_to_click((By.XPATH, self.delete_cond_alert.format(self.cond_alert_name_input)))
try:
obj = self.driver.switch_to.alert
obj.accept()
@@ -511,7 +510,7 @@ def remove_cond_alert(self):
self.driver.refresh()
self.wait_to_clear_and_send_keys(self.search_box, self.cond_alert_name_input)
self.wait_and_sleep_to_click(self.search_box)
- isPresent = self.is_displayed(self.cond_alert_created)
+ isPresent = self.is_displayed((By.XPATH, self.cond_alert_created.format(self.cond_alert_name_input)))
except NoSuchElementException:
isPresent = False
assert not isPresent
@@ -524,7 +523,7 @@ def remove_alert_with_same_name(self, alert_name):
if self.is_present_and_displayed(self.empty_table_alert):
print("No alert created with the same name")
else:
- self.wait_to_click(self.delete_cond_alert)
+ self.wait_to_click((By.XPATH, self.delete_cond_alert.format(self.cond_alert_name_input)))
try:
obj = self.driver.switch_to.alert
obj.accept()
@@ -535,7 +534,7 @@ def remove_alert_with_same_name(self, alert_name):
self.driver.refresh()
self.wait_to_clear_and_send_keys(self.search_box, self.cond_alert_name_input)
self.wait_and_sleep_to_click(self.search_box)
- isPresent = self.is_displayed(self.cond_alert_created)
+ isPresent = self.is_displayed((By.XPATH, self.cond_alert_created.format(self.cond_alert_name_input)))
except NoSuchElementException:
isPresent = False
assert not isPresent
@@ -581,7 +580,6 @@ def current_subscription_page(self):
self.subscription_elements_id), "Subscription Page did not load successfully"
print("Current Subscription page loaded successfully!")
-
def remove_all_cond_alert(self):
self.wait_to_click(self.cond_alerts)
self.wait_for_element(self.value_per_page)
@@ -606,3 +604,63 @@ def remove_all_cond_alert(self):
else:
print("No script created cond alerts present")
print("All Cond Alert removed successfully!")
+
+ def create_cond_alert_for_doesnot_have_value(self):
+ self.wait_to_click(self.cond_alerts)
+ self.remove_alert_with_same_name(self.cond_alert_no_value_name_input)
+ self.wait_to_click(self.add_cond_alert)
+ self.send_keys(self.cond_alert_name, self.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" + self.cond_alert_no_value_name_input)
+ self.send_keys(self.broadcast_message, "Test Alert for no value:" + self.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, self.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(self.cond_alert_no_value_name_input)), 700)
+ self.driver.refresh()
+ if self.is_clickable((By.XPATH, self.delete_cond_alert.format(self.cond_alert_no_value_name_input))):
+ print("Restart is not required.")
+ else:
+ try:
+ self.js_click((By.XPATH, self.restart_rule_button.format(self.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, self.cond_alert_no_value_name_input)
+ self.wait_to_click(self.search_box)
+ self.wait_for_element((By.XPATH, self.delete_cond_alert.format(self.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, self.cond_alert_no_value_name_input)
+ self.wait_to_click(self.search_box)
+ assert self.is_displayed((By.XPATH, self.cond_alert_created.format(self.cond_alert_no_value_name_input))), "Conditional Alert not created successfully!"
+ print("Conditional Alert created successfully!")
+ subject = "Test Alert for no value" + self.cond_alert_no_value_name_input
+ return self.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 5df0cc165..20e20bfa9 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 21ed7cc42..ee4804c28 100644
--- a/HQSmokeTests/testPages/reports/report_page.py
+++ b/HQSmokeTests/testPages/reports/report_page.py
@@ -2,7 +2,6 @@
import time
import html
from datetime import datetime, timedelta
-import re
import pandas as pd
from selenium.webdriver import ActionChains
@@ -21,6 +20,45 @@
""""Contains test page elements and functions related to the Reports module"""
+import re
+
+
+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 +79,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, "Submit History")
@@ -83,6 +122,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"
@@ -95,7 +135,7 @@ def __init__(self, driver):
"(//a[text()='" + self.report_name_saved + "']//following::button[@class='btn btn-danger add-spinner-on-click'])[1]")
self.delete_saved_report_link = "(//a[text()='{}']//following::button[@class='btn btn-danger add-spinner-on-click'])[1]"
self.all_saved_reports = (
- By.XPATH, "//td[a[contains(.,'Saved')]]//following-sibling::td/button[contains(@data-bind,'delete')]")
+ By.XPATH, "//td[a[contains(.,'Saved')]]//following-sibling::td/button[contains(@data-bind,'delete')]")
# Scheduled Reports
self.scheduled_reports_menu_xpath = (By.XPATH, "//a[@href='#scheduled-reports']")
@@ -127,6 +167,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]")
@@ -136,16 +178,36 @@ def __init__(self, driver):
self.case_list_table = (By.XPATH, "//table[@id='report_table_case_list']/tbody/tr")
self.case_id_block = (By.XPATH, "//th[@title='_id']/following-sibling::td")
self.remove_case_owner = (
- By.XPATH, "//label[.='Case Owner(s)']//following-sibling::div//button[@aria-label='Remove item']")
+ By.XPATH, "//label[.='Case Owner(s)']//following-sibling::div//button[@aria-label='Remove item']")
self.case_owner_textarea = (By.XPATH, "//label[.='Case Owner(s)']//following-sibling::div//textarea")
self.case_owner_list_item = "//ul[@role='listbox']/li[contains(.,'{}')]"
self.case_owner_column = (By.XPATH, "//tbody//td[3]")
# Case List Explorer
+ self.query_div = (By.XPATH, "//div[@class='ace_content']//div[@class='ace_line']")
+ self.case_list_explorer_query_field = (
+ By.XPATH, "//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.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]")
@@ -162,7 +224,7 @@ def __init__(self, driver):
self.configurable_report = (By.LINK_TEXT, "Configurable Reports")
self.add_report_button = (By.XPATH, "//div[@id='hq-content']//*[contains(.,'Add Report')]")
self.edit_report_dropdown = (
- By.XPATH, "//span[contains(@class,'placeholder')][.='Edit a report or data source']")
+ By.XPATH, "//span[contains(@class,'placeholder')][.='Edit a report or data source']")
self.report_search_input = (By.XPATH, "//input[@role='searchbox']")
self.select_report = "//li[contains(.,'{}')]/i"
self.report_dropdown = (By.XPATH, "//select[@id='select2-navigation']")
@@ -173,19 +235,34 @@ def __init__(self, driver):
self.daily_form_activity_results = (By.XPATH, "//table[@id='report_table_daily_form_stats']/tbody/tr")
self.daily_form_activity_results_cells = (By.XPATH, "//table[@id='report_table_daily_form_stats']/tbody/tr/td")
self.users_field = (By.XPATH, "(//textarea[@class='select2-search__field'])[1]")
- self.remove_active_worker = (By.XPATH,"//span[.='[Active Mobile Workers]']//preceding-sibling::button[@class='select2-selection__choice__remove']")
- self.remove_deactive_worker = (By.XPATH, "//span[.='[Deactivated Mobile Workers]']//preceding-sibling::button[@class='select2-selection__choice__remove']")
+ self.remove_active_worker = (By.XPATH,
+ "//span[.='[Active Mobile Workers]']//preceding-sibling::button[@class='select2-selection__choice__remove']")
+ self.remove_deactive_worker = (By.XPATH,
+ "//span[.='[Deactivated Mobile Workers]']//preceding-sibling::button[@class='select2-selection__choice__remove']")
self.remove_buttons = (By.XPATH, "//ul//button")
self.user_remove_btn = (By.XPATH, "(//button[@class='select2-selection__choice__remove'])[last()]")
self.user_from_list = "//li[contains(.,'{}')]"
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.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[@class='panel-body-datatable']")
+ 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:
@@ -280,13 +357,13 @@ def delete_report(self):
def create_report_builder_case_report(self):
self.wait_to_click(self.create_new_rep_id)
self.send_keys(self.report_name_textbox_id, self.report_name_case)
- self.click(self.select_app)
+ self.select_by_value(self.form_or_cases, self.select_case_type_value)
+ self.select_by_text(self.application, UserData.village_application)
self.select_by_text(self.select_source_id, self.select_source_id_case_value)
self.wait_to_click(self.next_button_id)
self.wait_to_click(self.save_and_view_button_id)
self.check_if_report_loaded()
-
def create_report_builder_form_report(self):
self.wait_to_click(self.create_new_rep_id)
self.send_keys(self.report_name_textbox_id, self.report_name_form)
@@ -417,7 +494,6 @@ def delete_report_form_links(self):
else:
print("Report deleted successfully!")
-
def get_last_7_days_date_range(self):
# Get today's date
presentday = datetime.now() # or presentday = datetime.today()
@@ -433,7 +509,8 @@ def get_todays_date_range(self):
def verify_table_not_empty(self, locator):
clickable = ec.presence_of_all_elements_located(locator)
element = WebDriverWait(self.driver, 30).until(clickable, message="Couldn't find locator: "
- + str(locator))
+ + str(locator)
+ )
count = len(element)
if count > 0:
print(count, " rows are present in the web table")
@@ -498,7 +575,7 @@ def verify_app_data_submit_history(self, case_name):
self.wait_for_element(self.users_box, 300)
self.wait_to_click(self.users_box)
self.send_keys(self.search_user, UserData.app_login)
- self.wait_to_click((By.XPATH, self.app_user_select.format(UserData.app_login)))
+ self.wait_to_click((By.XPATH, self.app_user_select.format(UserData.new_app_login)))
self.select_by_text(self.application_select, UserData.reassign_cases_application)
self.select_by_text(self.module_select, UserData.case_list_name)
self.select_by_text(self.form_select, UserData.new_form_name)
@@ -524,7 +601,8 @@ def verify_updated_data_in_case_list(self, case_name, value):
time.sleep(3)
self.page_source_contains(case_name)
assert self.is_present_and_displayed(
- (By.XPATH, "//div[@id='properties']//td[contains(text(),'" + value + "')]")), "Case property not updated."
+ (By.XPATH, "//div[@id='properties']//td[contains(text(),'" + value + "')]")
+ ), "Case property not updated."
print("Case is updated successfully")
case_id = self.get_text(self.case_id_block)
return case_id
@@ -660,7 +738,7 @@ def export_daily_form_activity_to_excel(self):
ActionChains(self.driver).send_keys(Keys.TAB).perform()
time.sleep(2)
count = self.find_elements(self.remove_buttons)
- # self.wait_to_click(self.users_field)
+ # 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)))
time.sleep(2)
@@ -782,17 +860,15 @@ def compare_app_status_web_with_email(self, link, web_data):
assert len(web_data) == len(list), "Data in Both Excel and Searched results do not match"
print("Both Excel and Searched results have same amount of data")
for i in range(len(list)):
- if i == 1 or i == 2 or i == 3:
- print("Not comparing", html.unescape(str(list[i])), " with ", str(web_data[i]))
- else:
- print("Comparing ", html.unescape(str(list[i])), " with ", str(web_data[i]))
- assert html.unescape(str(list[i])) == str(web_data[i]), "Comparison failed for " + list[
- i] + " and " + web_data[i]
+ if i == 1 or i == 2 or i == 3:
+ print("Not comparing", html.unescape(str(list[i])), " with ", str(web_data[i]))
+ else:
+ print("Comparing ", html.unescape(str(list[i])), " with ", str(web_data[i]))
+ assert html.unescape(str(list[i])) == str(web_data[i]), "Comparison failed for " + list[
+ i] + " and " + web_data[i]
except Exception:
print("No Data to compare or there is Data mismatch")
-
-
def verify_form_in_submit_history(self, app_name, lat, lon):
print("Sleeping for sometime for the case to get registered.")
time.sleep(140)
@@ -827,3 +903,132 @@ def format_number(self, n, digits):
formatter = '{:.' + '{}'.format(digits) + 'f}'
x = round(n, digits)
return formatter.format(x)
+
+ 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 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 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)
+ self.wait_for_element(self.apply_id, 100)
+ self.remove_default_users()
+ self.js_click(self.query_div)
+ time.sleep(2)
+ self.send_keys(self.case_list_explorer_query_field, 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 ed7d160b0..39099ad57 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
@@ -161,6 +161,15 @@ def __init__(self, driver):
self.location_combobox = (By.XPATH, "//span[@class='select2-selection select2-selection--multiple']")
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")
@@ -178,6 +187,9 @@ def __init__(self, driver):
self.no_user_found = (By.XPATH, "//text()[contains(.,'No users found')]")
self.role_dropdown = (By.XPATH, "//select[@id='id_role']")
+ 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):
self.wait_to_clear_and_send_keys(self.search_mw, username)
@@ -695,3 +707,33 @@ 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 ba3a9543f..7d2c536d0 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 = (
@@ -35,13 +37,20 @@ def __init__(self, driver, settings):
self.delete_role = (By.XPATH, "//th[.//span[.='" + str(
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']")
+ 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)
@@ -142,4 +151,37 @@ def add_non_admin_role(self):
self.click(self.save_button)
time.sleep(2)
assert self.is_present_and_displayed(self.role_non_admin), "Role not 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 3a603c7bc..64d1b5991 100644
--- a/HQSmokeTests/testPages/users/web_user_page.py
+++ b/HQSmokeTests/testPages/users/web_user_page.py
@@ -202,4 +202,16 @@ def edit_user_permission(self, rolename):
self.wait_to_click(self.update_location_btn)
time.sleep(2)
-
+ 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 bf6fd768d..2b2ce490b 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 + "']")
@@ -121,3 +122,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 d6ff74492..b8eb1ff44 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]"
@@ -77,7 +79,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"
@@ -104,3 +107,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 | +
---|