diff --git a/ocs_ci/ocs/ui/page_objects/object_buckets_tab.py b/ocs_ci/ocs/ui/page_objects/buckets_tab.py similarity index 56% rename from ocs_ci/ocs/ui/page_objects/object_buckets_tab.py rename to ocs_ci/ocs/ui/page_objects/buckets_tab.py index bba74105fd7b..3eb36f888c37 100644 --- a/ocs_ci/ocs/ui/page_objects/object_buckets_tab.py +++ b/ocs_ci/ocs/ui/page_objects/buckets_tab.py @@ -4,14 +4,16 @@ from selenium.webdriver.common.by import By from ocs_ci.ocs.ocp import get_ocp_url from ocs_ci.ocs import exceptions +from ocs_ci.ocs.ui.page_objects.confirm_dialog import ConfirmDialog from ocs_ci.ocs.ui.page_objects.object_storage import ObjectStorage, logger +from ocs_ci.utility import version -class ObjectBucketsTab(ObjectStorage): +class BucketsTab(ObjectStorage, ConfirmDialog): def __init__(self): super().__init__() - def delete_object_bucket_ui(self, delete_via, expect_fail, resource_name): + def delete_bucket_ui(self, delete_via, expect_fail, resource_name): """ Delete an Object Bucket via the UI @@ -19,7 +21,7 @@ def delete_object_bucket_ui(self, delete_via, expect_fail, resource_name): expect_fail (str): verify if OB removal fails with proper PopUp message resource_name (str): Object Bucket Claim's name. The resource with its suffix will be deleted """ - self.navigate_object_buckets_page() + self.navigate_buckets_page() self.delete_resource(delete_via, resource_name) if expect_fail: @@ -28,9 +30,9 @@ def _check_three_dots_disabled(text): logger.info(text) # locator of three_dots btn aligned with the specific resource name locator = ( - f"//td[@id='name']//a[contains(text(), '{resource_name}')]" - "/../../..//button[@aria-label='Actions'] | " - f"//tr[contains(., '{resource_name}')]//button[@data-test='kebab-button']", + f"//tr[contains(., '{resource_name}')]//button[@data-test='kebab-button'] | " + f"//td[@data-label='Name' and normalize-space()='{resource_name}']" + "/following-sibling::td//button[@aria-label='Kebab toggle']", By.XPATH, ) # when three_dots element is active attribute 'disabled' does not exist @@ -52,23 +54,27 @@ def _check_three_dots_disabled(text): sleep=1, ) - # PopUp is not reachable via Selenium driver. It does not appear in DOM - URL = f"{get_ocp_url()}/locales/resource.json?lng=en&ns=plugin__odf-console" + # this popup is not available on ODF 4.18 and above + if self.ocp_version_semantic < version.VERSION_4_18: + # PopUp is not reachable via Selenium driver. It does not appear in DOM + URL = f"{get_ocp_url()}/locales/resource.json?lng=en&ns=plugin__odf-console" - cookies = self.driver.get_cookies() - session = requests.Session() - for cookie in cookies: - session.cookies.set(cookie["name"], cookie["value"]) + cookies = self.driver.get_cookies() + session = requests.Session() + for cookie in cookies: + session.cookies.set(cookie["name"], cookie["value"]) - popup_str = "The corresponding ObjectBucketClaim must be deleted first." - logger.info(f"Send req to {URL}. Get PopUp with {popup_str}") + popup_str = ( + "The corresponding ObjectBucketClaim must be deleted first." + ) + logger.info(f"Send req to {URL}. Get PopUp with {popup_str}") - resp = session.get(url=URL, verify=False) - json_resp = resp.json() + resp = session.get(url=URL, verify=False) + json_resp = resp.json() - assert ( - popup_str == json_resp[popup_str] - ), f"No expected Popup. See full response: \n {json.dumps(json_resp)}" + assert ( + popup_str == json_resp[popup_str] + ), f"No expected Popup. See full response: \n {json.dumps(json_resp)}" _check_three_dots_disabled("check three dots inactive automatically") self.driver.refresh() diff --git a/ocs_ci/ocs/ui/page_objects/confirm_dialog.py b/ocs_ci/ocs/ui/page_objects/confirm_dialog.py new file mode 100644 index 000000000000..2ecc03722fbc --- /dev/null +++ b/ocs_ci/ocs/ui/page_objects/confirm_dialog.py @@ -0,0 +1,47 @@ +from ocs_ci.ocs.ui.base_ui import BaseUI +from ocs_ci.ocs.ui.helpers_ui import format_locator + + +class ConfirmDialog(BaseUI): + """ + Page object for Confirm Dialog + """ + + def dialog_confirm_delete(self, resource_name): + """ + Action to confirm delete resource + """ + # placeholder for the confirm dialog remains even when text input contains any text + # remove the text if exists, for more complex scenarios + self.dialog_type_resource_name(resource_name) + self.dialog_confirm() + + def dialog_confirm(self): + """ + Clicks on Delete button + """ + self.do_click(self.generic_locators["confirm_delete_resource"]) + + def dialog_cancel(self): + """ + Clicks on Cancel button + """ + self.do_click(self.generic_locators["cancel_delete_resource"]) + + def dialog_type_resource_name(self, resource_name): + """ + Type the resource name in the dialog + """ + self.clear_input_gradually( + format_locator(self.generic_locators["confirm_dilog_input"], resource_name) + ) + self.do_send_keys( + format_locator(self.generic_locators["confirm_dilog_input"], resource_name), + resource_name, + ) + + def dialog_close(self): + """ + Close the dialog + """ + self.do_click(self.generic_locators["close_dialog"]) diff --git a/ocs_ci/ocs/ui/page_objects/object_storage.py b/ocs_ci/ocs/ui/page_objects/object_storage.py index ee64fb7c5f67..203f0d0dd921 100644 --- a/ocs_ci/ocs/ui/page_objects/object_storage.py +++ b/ocs_ci/ocs/ui/page_objects/object_storage.py @@ -54,20 +54,18 @@ def nav_namespace_store_tab(self): return NameSpaceStoreTab() - def nav_object_buckets_tab(self): + def nav_buckets_tab(self): """ Navigate to Object Buckets tab. Accessible from Object Storage page Returns: ObjectBucketTab: ObjectBucketTab page object """ - self.do_click( - locator=self.page_nav["object_buckets_tab"], enable_screenshot=False - ) + self.do_click(locator=self.page_nav["buckets_tab"], enable_screenshot=False) - from ocs_ci.ocs.ui.page_objects.object_buckets_tab import ObjectBucketsTab + from ocs_ci.ocs.ui.page_objects.buckets_tab import BucketsTab - return ObjectBucketsTab() + return BucketsTab() def nav_object_buckets_claims_tab(self): """ diff --git a/ocs_ci/ocs/ui/page_objects/page_navigator.py b/ocs_ci/ocs/ui/page_objects/page_navigator.py index 9bde5675a6d8..51219b4981d7 100644 --- a/ocs_ci/ocs/ui/page_objects/page_navigator.py +++ b/ocs_ci/ocs/ui/page_objects/page_navigator.py @@ -292,13 +292,13 @@ def navigate_volumesnapshotcontents_page(self): enable_screenshot=False, ) - def navigate_object_buckets_page(self): + def navigate_buckets_page(self): """ Navigate to Object Buckets Page """ - return self.nav_object_storage().nav_object_buckets_tab() + return self.nav_object_storage().nav_buckets_tab() def navigate_object_bucket_claims_page(self): """ diff --git a/ocs_ci/ocs/ui/page_objects/resource_list.py b/ocs_ci/ocs/ui/page_objects/resource_list.py index 38c49794db95..cb4e2b4ab11b 100644 --- a/ocs_ci/ocs/ui/page_objects/resource_list.py +++ b/ocs_ci/ocs/ui/page_objects/resource_list.py @@ -1,6 +1,8 @@ from ocs_ci.ocs.ui.helpers_ui import format_locator +from ocs_ci.ocs.ui.page_objects.buckets_tab import BucketsTab from ocs_ci.ocs.ui.page_objects.searchbar import SearchBar from ocs_ci.ocs.ui.base_ui import logger +from ocs_ci.utility import version class ResourceList(SearchBar): @@ -23,7 +25,9 @@ def nav_to_resource_via_name(self, resource_name: str = None): self.do_clear(self.generic_locators["searchbar_input"]) self.search(resource_name) self.do_click( - format_locator(self.generic_locators["resource_link"], resource_name), + format_locator( + self.generic_locators["resource_link"], resource_name, resource_name + ), enable_screenshot=True, ) @@ -78,4 +82,13 @@ def delete_resource(self, delete_via, resource): logger.info(f"Confirm {resource} Deletion") # same PopUp both for OBC and OB - self.do_click(self.generic_locators["confirm_action"], enable_screenshot=True) + # check if we are on the Bucket page, it has different UI starting from 4.18 + if ( + isinstance(self, BucketsTab) + and self.ocp_version_semantic >= version.VERSION_4_18 + ): + self.dialog_confirm_delete(resource) + else: + self.do_click( + self.generic_locators["confirm_action"], enable_screenshot=True + ) diff --git a/ocs_ci/ocs/ui/page_objects/resource_page.py b/ocs_ci/ocs/ui/page_objects/resource_page.py index 6d486a3328f8..af0992ee7ccb 100644 --- a/ocs_ci/ocs/ui/page_objects/resource_page.py +++ b/ocs_ci/ocs/ui/page_objects/resource_page.py @@ -126,7 +126,7 @@ def nav_resource_list_via_breadcrumbs(self): from ocs_ci.ocs.ui.page_objects.object_bucket_claims_tab import ( ObjectBucketClaimsTab, ) - from ocs_ci.ocs.ui.page_objects.object_buckets_tab import ObjectBucketsTab + from ocs_ci.ocs.ui.page_objects.buckets_tab import BucketsTab if self.is_namespace_store_open(): resource_list_page = NameSpaceStoreTab @@ -135,7 +135,7 @@ def nav_resource_list_via_breadcrumbs(self): elif self.is_obc_open(): resource_list_page = ObjectBucketClaimsTab elif self.is_ob_open(): - resource_list_page = ObjectBucketsTab + resource_list_page = BucketsTab else: raise IncorrectUiOptionRequested( "Wrong page is open after resource created", func=take_screenshot diff --git a/ocs_ci/ocs/ui/views.py b/ocs_ci/ocs/ui/views.py index c43c86b4c6da..87aab0c4cc20 100644 --- a/ocs_ci/ocs/ui/views.py +++ b/ocs_ci/ocs/ui/views.py @@ -298,7 +298,7 @@ By.XPATH, ), "actions": ( - '//button[@aria-label="Actions"] | //div[@data-test-id="details-actions"]//button | ' + '//button[@aria-label="Actions"]| //div[@data-test-id="details-actions"]//button[normalize-space()="Actions"]| ' '//span[@class="pf-c-dropdown__toggle-text" and text()="Actions"]/..', By.XPATH, ), @@ -308,11 +308,19 @@ "//tr[contains(., '{}')]//button[@data-test='kebab-button']", By.XPATH, ), - "resource_link": ("//td[@id='name']//a[contains(text(),'{}')]", By.XPATH), + "resource_link": ( + "//td[@id='name']//a[contains(text(),'{}')] | " + "//td[@data-label='Name']//a[contains(text(),'{}')]", + By.XPATH, + ), "confirm_action": ( 'button[id="confirm-action"],button[data-test="delete-action"]', By.CSS_SELECTOR, ), + "confirm_dilog_input": ("//input[@placeholder='{}']", By.XPATH), + "confirm_delete_resource": ("//button[contains(text(), 'Delete')]", By.XPATH), + "cancel_delete_resource": ("//button[contains(text(), 'Cancel')]", By.XPATH), + "close_dialog": ("button[aria-label='Close']", By.XPATH), "submit_form": ('button[type="submit"]', By.CSS_SELECTOR), "ocs_operator": ('//h1[text()="OpenShift Container Storage"]', By.XPATH), "kebab_button": ('button[data-test-id="kebab-button"', By.CSS_SELECTOR), @@ -689,8 +697,10 @@ "volumesnapshots_page": ("VolumeSnapshots", By.LINK_TEXT), "volumesnapshotclasses_page": ("VolumeSnapshotClasses", By.LINK_TEXT), "volumesnapshotcontents_page": ("VolumeSnapshotContents", By.LINK_TEXT), - "object_buckets_tab": ( - "//a[normalize-space()='Object Buckets'] | //span[normalize-space()='Object Buckets']/..", + "buckets_tab": ( + "//a[normalize-space()='Object Buckets'] " + "| //span[normalize-space()='Object Buckets']/.. " + "| //span[normalize-space()='Buckets']/..", By.XPATH, ), "object_storage": ("//a[normalize-space()='Object Storage']", By.XPATH), diff --git a/tests/functional/object/mcg/ui/test_mcg_ui.py b/tests/functional/object/mcg/ui/test_mcg_ui.py index 336c3bcb138c..98895ef1ea97 100644 --- a/tests/functional/object/mcg/ui/test_mcg_ui.py +++ b/tests/functional/object/mcg/ui/test_mcg_ui.py @@ -29,7 +29,7 @@ from ocs_ci.ocs.ui.page_objects.object_bucket_claims_tab import ( ObjectBucketClaimsTab, ) -from ocs_ci.ocs.ui.page_objects.object_buckets_tab import ObjectBucketsTab +from ocs_ci.ocs.ui.page_objects.buckets_tab import BucketsTab from ocs_ci.ocs.ui.page_objects.page_navigator import PageNavigator logger = logging.getLogger(__name__) @@ -393,7 +393,7 @@ def test_obc_creation_and_deletion( # covers BZ 2097772 if verify_ob_removal: - ObjectBucketsTab().delete_object_bucket_ui( + BucketsTab().delete_bucket_ui( delete_via="three_dots", expect_fail=True, resource_name=obc_name )