diff --git a/web/pgadmin/feature_tests/browser_tool_bar_test.py b/web/pgadmin/feature_tests/browser_tool_bar_test.py index 9e1ff74cb..28fcb4068 100644 --- a/web/pgadmin/feature_tests/browser_tool_bar_test.py +++ b/web/pgadmin/feature_tests/browser_tool_bar_test.py @@ -47,7 +47,7 @@ class BrowserToolBarFeatureTest(BaseFeatureTest): file=sys.stderr, end="") self.test_view_data_tool_button() print("OK.", file=sys.stderr) - + # # Check for filtered rows button print("\nFiltered Rows ToolBar Button ", file=sys.stderr, end="") @@ -60,9 +60,9 @@ class BrowserToolBarFeatureTest(BaseFeatureTest): self.test_table_name) def test_query_tool_button(self): - self.page.toggle_open_tree_item(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.test_db) + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) self.page.retry_click( (By.CSS_SELECTOR, BrowserToolBarLocators.open_query_tool_button_css), @@ -70,9 +70,12 @@ class BrowserToolBarFeatureTest(BaseFeatureTest): def test_view_data_tool_button(self): self.page.select_tree_item(self.test_db) - self.page.toggle_open_tree_item('Schemas') - self.page.toggle_open_tree_item('public') - self.page.toggle_open_tables_node() + self.page.toggle_open_schema_node( + self.server['name'], self.server['db_password'], + self.test_db, 'public') + self.page.toggle_open_tables_node( + self.server['name'], self.server['db_password'], + self.test_db, 'public') self.page.select_tree_item(self.test_table_name) self.page.retry_click( diff --git a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py index 9bb458710..9ac8be6f4 100644 --- a/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py +++ b/web/pgadmin/feature_tests/copy_selected_query_results_feature_test.py @@ -39,9 +39,9 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest): self.server, self.test_db, self.test_table_name) def runTest(self): - self.page.toggle_open_tree_item(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.test_db) + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) self.page.open_query_tool() self.page.fill_codemirror_area_with( @@ -70,7 +70,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest): QueryToolLocators.copy_button_css) copy_button.click() - self.assertEqual('"Some-Name"\t"6"\t"some info"', + self.assertEqual('"Some-Name"\t6\t"some info"', pyperclip.paste()) def _copies_rows_with_header(self): @@ -87,9 +87,9 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest): copy_button.click() self.assertEqual("""\"some_column"\t"value"\t"details" -\"Some-Name"\t"6"\t"some info" -\"Some-Other-Name"\t"22"\t"some other info" -\"Yet-Another-Name"\t"14"\t"cool info\"""", pyperclip.paste()) +\"Some-Name"\t6\t"some info" +\"Some-Other-Name"\t22\t"some other info" +\"Yet-Another-Name"\t14\t"cool info\"""", pyperclip.paste()) def _copies_columns(self): pyperclip.copy("old clipboard contents") @@ -116,7 +116,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest): ActionChains(self.page.driver).key_down( Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform() - self.assertEqual('"Some-Name"\t"6"\t"some info"', + self.assertEqual('"Some-Name"\t6\t"some info"', pyperclip.paste()) def _copies_column_using_keyboard_shortcut(self): @@ -154,8 +154,8 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest): self.page.driver ).key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform() - self.assertEqual("""\"Some-Other-Name"\t"22" -"Yet-Another-Name"\t"14\"""", pyperclip.paste()) + self.assertEqual( + '"Some-Other-Name"\t22\n"Yet-Another-Name"\t14', pyperclip.paste()) def _shift_resizes_rectangular_selection(self): pyperclip.copy("old clipboard contents") @@ -180,8 +180,8 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest): Keys.CONTROL ).send_keys('c').key_up(Keys.CONTROL).perform() - self.assertEqual("""\"Some-Other-Name"\t"22"\t"some other info" -"Yet-Another-Name"\t"14"\t"cool info\"""", pyperclip.paste()) + self.assertEqual("""\"Some-Other-Name"\t22\t"some other info" +"Yet-Another-Name"\t14\t"cool info\"""", pyperclip.paste()) def _shift_resizes_column_selection(self): pyperclip.copy("old clipboard contents") @@ -198,9 +198,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest): Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform() self.assertEqual( - """\"Some-Name"\t"6" -"Some-Other-Name"\t"22" -"Yet-Another-Name"\t"14\"""", + '"Some-Name"\t6\n"Some-Other-Name"\t22\n"Yet-Another-Name"\t14', pyperclip.paste()) def _mouseup_outside_grid_still_makes_a_selection(self): diff --git a/web/pgadmin/feature_tests/file_manager_test.py b/web/pgadmin/feature_tests/file_manager_test.py index dd2a7855f..c76f20386 100644 --- a/web/pgadmin/feature_tests/file_manager_test.py +++ b/web/pgadmin/feature_tests/file_manager_test.py @@ -60,9 +60,9 @@ class CheckFileManagerFeatureTest(BaseFeatureTest): print("OK.", file=sys.stderr) def _navigate_to_query_tool(self): - self.page.toggle_open_tree_item(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.test_db) + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) self.page.open_query_tool() def _create_new_file(self): diff --git a/web/pgadmin/feature_tests/pg_datatype_validation_test.py b/web/pgadmin/feature_tests/pg_datatype_validation_test.py index 2de897cc5..eb93be7cf 100644 --- a/web/pgadmin/feature_tests/pg_datatype_validation_test.py +++ b/web/pgadmin/feature_tests/pg_datatype_validation_test.py @@ -149,9 +149,9 @@ class PGDataypeFeatureTest(BaseFeatureTest): self.page.remove_server(self.server) def _schema_node_expandable(self): - self.page.toggle_open_tree_item(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.test_db) + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) def _check_datatype(self): # Slick grid does not render all the column if viewport is not enough diff --git a/web/pgadmin/feature_tests/pg_utilities_backup_restore_test.py b/web/pgadmin/feature_tests/pg_utilities_backup_restore_test.py index 6b99fdb7d..8659dd0e0 100644 --- a/web/pgadmin/feature_tests/pg_utilities_backup_restore_test.py +++ b/web/pgadmin/feature_tests/pg_utilities_backup_restore_test.py @@ -64,9 +64,9 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest): test_gui_helper.close_bgprocess_popup(self) def runTest(self): - self.page.toggle_open_server(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.database_name) + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.database_name) # Backup self.page.retry_click( @@ -115,11 +115,11 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest): self.assertEquals(status, "Successfully completed.") - self.page.find_by_css_selector( - NavMenuLocators.status_alertifier_more_btn_css).click() - - self.wait.until(EC.visibility_of_element_located( - (By.XPATH, NavMenuLocators.process_watcher_alertfier))) + self.page.retry_click( + (By.CSS_SELECTOR, + NavMenuLocators.status_alertifier_more_btn_css), + (By.XPATH, + NavMenuLocators.process_watcher_alertfier)) backup_file = None # Check for XSS in Backup details @@ -143,9 +143,7 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest): backup_file = command[int(command.find('--file')) + 8:int(command.find('--host')) - 2] - close_btn = self.page.find_by_xpath( - NavMenuLocators.process_watcher_close_button_xpath) - close_btn.click() + test_gui_helper.close_process_watcher(self) # Restore tools_menu = self.driver.find_element_by_link_text( @@ -186,11 +184,11 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest): self.assertEquals(status, "Successfully completed.") - self.page.find_by_css_selector( - NavMenuLocators.status_alertifier_more_btn_css).click() - - self.wait.until(EC.visibility_of_element_located( - (By.XPATH, NavMenuLocators.process_watcher_alertfier))) + self.page.retry_click( + (By.CSS_SELECTOR, + NavMenuLocators.status_alertifier_more_btn_css), + (By.XPATH, + NavMenuLocators.process_watcher_alertfier)) # Check for XSS in Restore details if self.is_xss_check: @@ -206,9 +204,7 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest): self.assertIn("pg_restore", str(command)) - close_watcher = self.page.find_by_xpath( - NavMenuLocators.process_watcher_close_button_xpath) - close_watcher.click() + test_gui_helper.close_process_watcher(self) if backup_file is not None: if os.path.isfile(backup_file): diff --git a/web/pgadmin/feature_tests/pg_utilities_maintenance_test.py b/web/pgadmin/feature_tests/pg_utilities_maintenance_test.py index 5eb521be7..b50c2b6fa 100644 --- a/web/pgadmin/feature_tests/pg_utilities_maintenance_test.py +++ b/web/pgadmin/feature_tests/pg_utilities_maintenance_test.py @@ -90,20 +90,22 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest): self.verify_command() def _open_maintenance_dialogue(self): - self.page.toggle_open_server(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.database_name) + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.database_name) if self.test_level == 'table': - self.page.toggle_open_tree_item('Schemas') - self.page.toggle_open_tree_item('public') - self.page.toggle_open_tables_node() + self.page.toggle_open_schema_node(self.server['name'], + self.server['db_password'], + self.database_name, 'public') + self.page.toggle_open_tables_node(self.server['name'], + self.server['db_password'], + self.database_name, 'public') self.page.select_tree_item(self.table_name) self.page.retry_click( (By.LINK_TEXT, NavMenuLocators.tools_menu_link_text), (By.CSS_SELECTOR, NavMenuLocators.maintenance_obj_css)) - maintenance_obj = self.wait.until(EC.visibility_of_element_located( (By.CSS_SELECTOR, NavMenuLocators.maintenance_obj_css))) maintenance_obj.click() @@ -118,11 +120,12 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest): test_gui_helper.close_bgprocess_popup(self) self.assertEquals(status, "Successfully completed.") - self.page.find_by_css_selector( - NavMenuLocators.status_alertifier_more_btn_css).click() - self.wait.until(EC.visibility_of_element_located( - (By.XPATH, NavMenuLocators.process_watcher_alertfier))) + self.page.retry_click( + (By.CSS_SELECTOR, + NavMenuLocators.status_alertifier_more_btn_css), + (By.XPATH, + NavMenuLocators.process_watcher_alertfier)) command = self.page.find_by_css_selector( NavMenuLocators. @@ -148,13 +151,12 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest): "\nVACUUM VERBOSE" " public." + self.table_name + ";") - self.page.find_by_xpath( - NavMenuLocators.process_watcher_close_button_xpath).click() + test_gui_helper.close_process_watcher(self) def after(self): test_gui_helper.close_bgprocess_popup(self) self.page.remove_server(self.server) - test_utils.delete_table(self.server, self.test_db, + test_utils.delete_table(self.server, self.database_name, self.table_name) connection = test_utils.get_db_connection( self.server['db'], diff --git a/web/pgadmin/feature_tests/query_tool_auto_complete_tests.py b/web/pgadmin/feature_tests/query_tool_auto_complete_tests.py index 1f6e248ce..fe6d68e4d 100644 --- a/web/pgadmin/feature_tests/query_tool_auto_complete_tests.py +++ b/web/pgadmin/feature_tests/query_tool_auto_complete_tests.py @@ -56,9 +56,9 @@ class QueryToolAutoCompleteFeatureTest(BaseFeatureTest): test_utils.create_table(self.server, self.test_db, self.second_table_name) - self.page.toggle_open_tree_item(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.test_db) + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) self.page.open_query_tool() self.page.wait_for_spinner_to_disappear() diff --git a/web/pgadmin/feature_tests/query_tool_journey_test.py b/web/pgadmin/feature_tests/query_tool_journey_test.py index 937cd97a8..88d30a1c1 100644 --- a/web/pgadmin/feature_tests/query_tool_journey_test.py +++ b/web/pgadmin/feature_tests/query_tool_journey_test.py @@ -103,7 +103,7 @@ class QueryToolJourneyTest(BaseFeatureTest): QueryToolLocators.copy_button_css) copy_row.click() - self.assertEqual('"Some-Name"\t"6"\t"some info"', + self.assertEqual('"Some-Name"\t6\t"some info"', pyperclip.paste()) def _test_copies_columns(self): @@ -380,9 +380,9 @@ class QueryToolJourneyTest(BaseFeatureTest): self.page.click_modal('Yes') def _navigate_to_query_tool(self): - self.page.toggle_open_tree_item(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.test_db) + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) self.page.open_query_tool() self.page.wait_for_spinner_to_disappear() diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py index ca9ee5091..413811dc2 100644 --- a/web/pgadmin/feature_tests/query_tool_tests.py +++ b/web/pgadmin/feature_tests/query_tool_tests.py @@ -35,9 +35,9 @@ class QueryToolFeatureTest(BaseFeatureTest): def before(self): self.page.wait_for_spinner_to_disappear() self.page.add_server(self.server) - self.page.toggle_open_tree_item(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.test_db) + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) self.page.open_query_tool() self.page.wait_for_spinner_to_disappear() self._reset_options() @@ -254,7 +254,7 @@ SELECT generate_series(1, {}) as id1, 'dummy' as id2""".format( ) # Table height takes some time to update, for which their is no # particular way - time.sleep(1) + time.sleep(2) if canvas_ele.size['height'] == scrolling_height: break else: diff --git a/web/pgadmin/feature_tests/table_ddl_feature_test.py b/web/pgadmin/feature_tests/table_ddl_feature_test.py index 12a293728..26f231ef9 100644 --- a/web/pgadmin/feature_tests/table_ddl_feature_test.py +++ b/web/pgadmin/feature_tests/table_ddl_feature_test.py @@ -32,12 +32,12 @@ class TableDdlFeatureTest(BaseFeatureTest): test_utils.create_table(self.server, self.test_db, self.test_table_name) - self.page.toggle_open_server(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.test_db) - self.page.toggle_open_tree_item('Schemas') - self.page.toggle_open_tree_item('public') - self.page.toggle_open_tree_item('Tables') + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) + self.page.toggle_open_tables_node( + self.server['name'], self.server['db_password'], + self.test_db, 'public') self.page.select_tree_item(self.test_table_name) self.page.click_tab("SQL") diff --git a/web/pgadmin/feature_tests/view_data_dml_queries.py b/web/pgadmin/feature_tests/view_data_dml_queries.py index 09dd6d046..6ea8d506c 100644 --- a/web/pgadmin/feature_tests/view_data_dml_queries.py +++ b/web/pgadmin/feature_tests/view_data_dml_queries.py @@ -122,12 +122,12 @@ CREATE TABLE public.nonintpkey self.page.wait_for_spinner_to_disappear() self.page.add_server(self.server) - self.page.toggle_open_tree_item(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.test_db) - self.page.toggle_open_tree_item('Schemas') - self.page.toggle_open_tree_item('public') - self.page.toggle_open_tree_item('Tables') + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) + self.page.toggle_open_tables_node(self.server['name'], + self.server['db_password'], + self.test_db, 'public') self._load_config_data('table_insert_update_cases') # iterate on both tables @@ -349,13 +349,13 @@ CREATE TABLE public.nonintpkey element = result_row.find_element_by_class_name("r" + str(idx)) self.page.driver.execute_script( "arguments[0].scrollIntoView(false)", element) - - self.assertEquals(element.text, config_check_data[str(idx)][1]) + time.sleep(0.4) self.assertEquals(element.text, config_check_data[str(idx)][1]) # scroll browser back to the left # to reset position so other assertions can succeed for idx in reversed(list(config_check_data.keys())): + time.sleep(0.4) element = result_row.find_element_by_class_name("r" + str(idx)) self.page.driver.execute_script( "arguments[0].scrollIntoView(false)", element) diff --git a/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py b/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py index 335d2c8db..aed1f36f1 100644 --- a/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py +++ b/web/pgadmin/feature_tests/xss_checks_panels_and_query_tool_test.py @@ -94,12 +94,12 @@ class CheckForXssFeatureTest(BaseFeatureTest): self.server, self.test_db, self.test_table_name) def _tables_node_expandable(self): - self.page.toggle_open_server(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item(self.test_db) - self.page.toggle_open_tree_item('Schemas') - self.page.toggle_open_tree_item('public') - self.page.toggle_open_tree_item('Tables') + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) + self.page.toggle_open_tables_node(self.server['name'], + self.server['db_password'], + self.test_db, 'public') self.page.select_tree_item(self.test_table_name) def _check_xss_in_browser_tree(self): diff --git a/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py b/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py index 70ae11d13..b42d3f12d 100644 --- a/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py +++ b/web/pgadmin/feature_tests/xss_checks_pgadmin_debugger_test.py @@ -39,10 +39,10 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest): self.function_name = "a_test_function" + \ str(random.randint(10000, 65535)) test_utils.create_debug_function( - self.server, "postgres", self.function_name + self.server, self.test_db, self.function_name ) - if test_utils.does_function_exist(self.server, 'postgres', + if test_utils.does_function_exist(self.server, self.test_db, self.function_name) != 'True': raise Exception("The required function is not found") @@ -54,15 +54,16 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest): def after(self): self.page.remove_server(self.server) - test_utils.drop_debug_function(self.server, "postgres", + test_utils.drop_debug_function(self.server, self.test_db, self.function_name) def _function_node_expandable(self): - self.page.toggle_open_server(self.server['name']) - self.page.toggle_open_tree_item('Databases') - self.page.toggle_open_tree_item('postgres') - self.page.toggle_open_tree_item('Schemas') - self.page.toggle_open_tree_item('public') + self.page.expand_database_node( + self.server['name'], + self.server['db_password'], self.test_db) + self.page.toggle_open_schema_node(self.server['name'], + self.server['db_password'], + self.test_db, 'public') self.page.toggle_open_function_node() self.page.select_tree_item(self.function_name + "()") diff --git a/web/pgadmin/feature_tests/xss_checks_roles_control_test.py b/web/pgadmin/feature_tests/xss_checks_roles_control_test.py index bf0013597..ab4c4241e 100644 --- a/web/pgadmin/feature_tests/xss_checks_roles_control_test.py +++ b/web/pgadmin/feature_tests/xss_checks_roles_control_test.py @@ -58,7 +58,8 @@ class CheckRoleMembershipControlFeatureTest(BaseFeatureTest): "

test

") def _role_node_expandable(self, role): - self.page.toggle_open_server(self.server['name']) + self.page.expand_server_node( + self.server['name'], self.server['db_password']) self.page.toggle_open_tree_item('Login/Group Roles') self.page.select_tree_item(role) @@ -93,6 +94,6 @@ class CheckRoleMembershipControlFeatureTest(BaseFeatureTest): """This will click and open membership tab of role""" self.page.retry_click( - (By.XPATH, - "//a[normalize-space(text())='Membership']"), + (By.LINK_TEXT, + "Membership"), (By.XPATH, "//input[@placeholder='Select members']")) diff --git a/web/regression/feature_utils/locators.py b/web/regression/feature_utils/locators.py index f37afddd5..847e457d3 100644 --- a/web/regression/feature_utils/locators.py +++ b/web/regression/feature_utils/locators.py @@ -87,7 +87,7 @@ class NavMenuLocators: ".bg-process-details .bg-detailed-desc" process_watcher_close_button_xpath = \ - "//div[contains(@class,'wcFloatingFocus')]//" \ + "//div[contains(@class,'wcFloating')]//" \ "div[contains(@class,'fa-close')]" restore_file_name_xpath = "//div[contains(text(),'Restore')]" \ @@ -227,3 +227,20 @@ class QueryToolLocators: read_only_column_icon_xpath = "//div[contains(@class," \ " 'editable-column-header-icon')]" \ "/i[contains(@class, 'fa-lock')]" + + +class ConnectToServerDiv: + # This will contain xpaths for element relating to Connect to server div + + password_field = "//input[@id='password']" + + ok_button = \ + "//div [@class='alertify ajs-modeless ajs-movable ajs-zoom']" \ + "//button[text()='OK']" + + error_message = \ + "//form[@id='frmPassword']/div/div//div[@class='alert-text']" + + cancel_button = \ + "//div [@class='alertify ajs-modeless ajs-movable ajs-zoom']" \ + "//button[text()='Cancel']" diff --git a/web/regression/feature_utils/pgadmin_page.py b/web/regression/feature_utils/pgadmin_page.py index 24d3bc9b5..ac1e25fcd 100644 --- a/web/regression/feature_utils/pgadmin_page.py +++ b/web/regression/feature_utils/pgadmin_page.py @@ -21,7 +21,7 @@ from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from regression.feature_utils.locators import QueryToolLocators, \ - NavMenuLocators + NavMenuLocators, ConnectToServerDiv from regression.feature_utils.tree_area_locators import TreeAreaLocators @@ -223,7 +223,7 @@ class PgadminPage: self.click_element(server_to_remove) object_menu_item = self.find_by_partial_link_text("Object") self.click_element(object_menu_item) - delete_menu_item = self.find_by_partial_link_text("Delete/Drop") + delete_menu_item = self.find_by_partial_link_text("Remove Server") self.click_element(delete_menu_item) self.click_modal('OK') @@ -245,14 +245,6 @@ class PgadminPage: if attempts == 0: raise Exception(e) - def get_expansion_status_of_node(self, xpath_node): - """get the expansion status for a node through xpath""" - node_is_expanded = False - element = self.find_by_xpath(xpath_node) - if element.get_attribute("aria-expanded") == 'true': - node_is_expanded = True - return node_is_expanded - def toggle_open_servers_group(self): """This will open Servers group to display underlying nodes""" is_expanded = False @@ -280,50 +272,238 @@ class PgadminPage: file=sys.stderr) return is_expanded - def toggle_open_tree_item(self, tree_item_text): - # 'sleep' here helps in cases where underlying nodes are auto opened. - # Otherwise, encountered situations where False value is returned - # even if the underlying node to be clicked was Opened. - time.sleep(.6) - item_with_text = self.find_by_xpath( - TreeAreaLocators.specified_tree_node.format(tree_item_text)) + def expand_server_node(self, server_name, server_password): + """will expand a particular server node""" + server_node_expansion_status = False + if self.toggle_open_servers_group(): + if self.wait_for_elements_to_appear( + self.driver, + TreeAreaLocators.server_group_sub_nodes): + subnodes_of_servers = self.find_by_xpath_list( + TreeAreaLocators.server_group_sub_nodes) + subnodes_of_servers_expansion_status = \ + self.find_by_xpath_list( + TreeAreaLocators. + server_group_sub_nodes_exp_status) + index_of_server_node = self.get_index_of_element( + subnodes_of_servers, server_name) - self.driver.execute_script("arguments[0].scrollIntoView()", - item_with_text) + if not self.check_server_is_connected( + index_of_server_node): + if self.click_and_connect_server( + subnodes_of_servers[index_of_server_node], + server_password): + server_node_expansion_status = True + else: + print( + "(expand_server_node)The server node is " + "not expanded", + file=sys.stderr) + else: + if not self.get_expansion_status_of_node_element( + subnodes_of_servers_expansion_status[ + index_of_server_node]): + webdriver.ActionChains(self.driver).double_click( + subnodes_of_servers[ + index_of_server_node]).perform() + if self.wait_for_elements_to_appear( + self.driver, TreeAreaLocators. + sub_nodes_of_a_server_node(server_name), + 30): + server_node_expansion_status = True + else: + server_node_expansion_status = True + else: + print( + "(expand_server_node) The Servers node is" + " not expanded", + file=sys.stderr) + return server_node_expansion_status - if item_with_text.find_element_by_xpath( - ".//ancestor::*[@class='aciTreeLine']").get_attribute( - "aria-expanded") == 'false': - item = item_with_text.find_element_by_xpath( - ".//parent::*[@class='aciTreeItem']") - ActionChains(self.driver).double_click(item).perform() - retry = 3 - while retry > 0: - try: - WebDriverWait(self.driver, 5).until((lambda item_with_text: ( - item_with_text.find_element_by_xpath( - ".//ancestor::*[@class='aciTreeLine']"). - get_attribute("aria-expanded") == 'true'))) - break - except TimeoutException: - retry -= 1 - pass + def expand_databases_node(self, server_name, server_password): + """will expand databases node under server node""" + databases_node_expanded = False + if self.expand_server_node(server_name, server_password): + if self.wait_for_elements_to_appear( + self.driver, + TreeAreaLocators.sub_nodes_of_a_server_node(server_name)): + subnodes_of_server_node = self.find_by_xpath_list( + TreeAreaLocators.sub_nodes_of_a_server_node(server_name)) + subnode_of_server_node_exp_status = self.find_by_xpath_list( + TreeAreaLocators.sub_nodes_of_a_server_node_exp_status( + server_name)) + index_of_databases_node = self.get_index_of_element( + subnodes_of_server_node, + "Databases") + time.sleep(2) + expansion_status = self.get_expansion_status_of_node_element( + subnode_of_server_node_exp_status[index_of_databases_node]) + if not expansion_status: + retry = 5 + while retry > 0: + webdriver.ActionChains(self.driver).double_click( + subnodes_of_server_node[ + index_of_databases_node].find_element_by_xpath( + ".//*[@class='aciTreeItem']") + ).perform() + if self.wait_for_elements_to_appear( + self.driver, TreeAreaLocators. + sub_nodes_of_databases_node(server_name), 3): + databases_node_expanded = True + break + else: + retry -= 1 + else: + databases_node_expanded = True + else: + print("The server/previous nodes not expanded", + file=sys.stderr) + return databases_node_expanded - def toggle_open_tables_node(self): - """The function will be used for opening Tables node only""" + def expand_database_node(self, server_name, server_password, + name_of_database): + """will expand database node under databases node""" + db_node_expanded_status = False + if self.expand_databases_node(server_name, server_password): + sub_nodes_of_databases_node = self.find_by_xpath_list( + TreeAreaLocators.sub_nodes_of_databases_node(server_name)) + index_of_required_db_node = self.get_index_of_element( + sub_nodes_of_databases_node, + name_of_database) + expansion_status = self.get_expansion_status_of_node_element( + self.find_by_xpath_list( + TreeAreaLocators. + sub_nodes_of_databases_node_exp_status( + server_name))[ + index_of_required_db_node]) + if not expansion_status: + self.driver.execute_script("arguments[0].scrollIntoView()", + sub_nodes_of_databases_node[ + index_of_required_db_node]) + webdriver.ActionChains(self.driver).double_click( + sub_nodes_of_databases_node[ + index_of_required_db_node]).perform() + if self.wait_for_elements_to_appear( + self.driver, TreeAreaLocators. + sub_nodes_of_database_node( + name_of_database)): + db_node_expanded_status = True + else: + db_node_expanded_status = True + else: + print("The databases/previous nodes not expanded", + file=sys.stderr) + return db_node_expanded_status - # get the element which contains 'aria-expanded' info - tables_expansion_ele = self.find_by_xpath("//div[div[div[div[div[div" - "[div[div[span[span[" - "(@class='aciTreeText') and " - "text()='Tables']]]]]]]]]]") + def toggle_open_schemas_node(self, server_name, server_password, + name_of_database): + """will expand schemas node under a db node""" + expansion_status = False + if self.expand_database_node(server_name, server_password, + name_of_database): + sub_nodes_db_node = self.find_by_xpath_list( + TreeAreaLocators.sub_nodes_of_database_node( + name_of_database)) + index_of_schemas_node = self.get_index_of_element( + sub_nodes_db_node, "Schemas") + expansion_status = self.get_expansion_status_of_node_element( + self.find_by_xpath_list( + TreeAreaLocators.sub_nodes_of_database_node_exp_status( + name_of_database))[ + index_of_schemas_node]) + if not expansion_status: + self.driver.execute_script( + "arguments[0].scrollIntoView()", + sub_nodes_db_node[index_of_schemas_node]) + webdriver.ActionChains(self.driver).double_click( + sub_nodes_db_node[index_of_schemas_node]).perform() + if self.wait_for_elements_to_appear( + self.driver, TreeAreaLocators. + sub_nodes_of_schemas_node(name_of_database)): + expansion_status = True + else: + expansion_status = True + else: + print( + "(expand_schemas_node) database/previous nodes " + "are not expanded", + file=sys.stderr) + return expansion_status - if tables_expansion_ele.get_attribute('aria-expanded') == 'false': - # button element of the Tables node to open it - item_button = self.find_by_xpath( - "//div[span[span[(@class='aciTreeText') and text()" - "='Tables']]]/span[@class='aciTreeButton']") - ActionChains(self.driver).click(item_button).perform() + def toggle_open_schema_node( + self, server_name, server_password, + name_of_database, name_of_schema_node): + """will expand schema node under schemas node""" + expansion_status = False + if self.toggle_open_schemas_node( + server_name, server_password, name_of_database): + sub_nodes_schemas_node = self.find_by_xpath_list( + TreeAreaLocators.sub_nodes_of_schemas_node( + name_of_database)) + index_of_schema_node = self.get_index_of_element( + sub_nodes_schemas_node, + name_of_schema_node) + expansion_status = self.get_expansion_status_of_node_element( + self.find_by_xpath_list( + TreeAreaLocators.sub_nodes_of_schemas_node_exp_status( + name_of_database))[ + index_of_schema_node]) + if not expansion_status: + self.driver.execute_script( + "arguments[0].scrollIntoView()", + sub_nodes_schemas_node[index_of_schema_node]) + webdriver.ActionChains(self.driver).double_click( + sub_nodes_schemas_node[index_of_schema_node]).perform() + if self.wait_for_elements_to_appear( + self.driver, TreeAreaLocators. + sub_nodes_of_schema_node(name_of_database)): + expansion_status = True + else: + expansion_status = True + else: + print( + "(expand_schema_node) schema/previous nodes are" + " not expanded", + file=sys.stderr) + return expansion_status + + def toggle_open_tables_node( + self, server_name, server_password, + name_of_database, name_of_schema_node): + """will expand tables node under schema node""" + node_expanded_successfully = False + if self.toggle_open_schema_node( + server_name, server_password, name_of_database, + name_of_schema_node): + sub_nodes_of_schema_node = self.find_by_xpath_list( + TreeAreaLocators.sub_nodes_of_schema_node( + name_of_database)) + sub_nodes_of_schema_node_exp_status = self.find_by_xpath_list( + TreeAreaLocators.sub_nodes_of_schema_node_exp_status( + name_of_database)) + index_of_tables_node = self.get_index_of_element( + sub_nodes_of_schema_node, "Tables") + expansion_status = self.get_expansion_status_of_node_element( + sub_nodes_of_schema_node_exp_status[index_of_tables_node]) + if not expansion_status: + self.driver.execute_script("arguments[0].scrollIntoView()", + sub_nodes_of_schema_node[ + index_of_tables_node]) + webdriver.ActionChains(self.driver).double_click( + sub_nodes_of_schema_node[ + index_of_tables_node]).perform() + if self.wait_for_elements_to_appear( + self.driver, TreeAreaLocators. + sub_nodes_of_tables_node): + node_expanded_successfully = True + else: + node_expanded_successfully = True + else: + print( + "(expand_tables_node) schema/previous nodes " + "are not expanded", + file=sys.stderr) + return node_expanded_successfully def toggle_open_function_node(self): """The function will be used for opening Functions node only""" @@ -379,6 +559,124 @@ class PgadminPage: else: node_expanded = True + def check_server_is_connected(self, index_of_server): + """This will check connected status of a server, as connection + status is contained either in span or div element so checking it""" + server_connected = False + try: + connection_status_elements = self.find_by_xpath_list( + TreeAreaLocators.server_group_sub_nodes_connected_status) + span_elements = connection_status_elements[ + index_of_server].find_elements_by_tag_name("span") + div_elements = connection_status_elements[ + index_of_server].find_elements_by_tag_name("div") + + span_value_of_class_att = "" + div_value_of_class_att = "" + + if len(span_elements) > 0: + span_value_of_class_att = \ + span_elements[0].get_attribute('class') + if len(div_elements) > 0: + div_value_of_class_att = \ + div_elements[0].get_attribute('class') + if (("aciTreeIcon icon-pg" in span_value_of_class_att or + "aciTreeIcon icon-pg" in div_value_of_class_att or + "aciTreeIcon icon-ppas" in + span_value_of_class_att or + "aciTreeIcon icon-ppas" in div_value_of_class_att) and + ("aciTreeIcon icon-server-not-connected" not in + span_value_of_class_att or + "aciTreeIcon icon-server-not-connected" not in + div_value_of_class_att)): + server_connected = True + except Exception as e: + print("There is some exception thrown in the function " + "check_server_is_connected and is: " + str(e), + file=sys.stderr) + return server_connected + + def click_and_connect_server(self, server_element, password): + """will connect a server node, will provide the password in the + respective window""" + server_connection_status = False + try: + webdriver.ActionChains(self.driver).double_click( + server_element).perform() + if self.wait_for_element_to_appear(self.driver, + ConnectToServerDiv.ok_button): + self.fill_input_by_xpath( + ConnectToServerDiv.password_field, password) + self.find_by_xpath(ConnectToServerDiv.ok_button).click() + self.wait_until_element_not_visible( + ConnectToServerDiv.ok_button) + if self.wait_for_element_to_be_visible( + self.driver, ConnectToServerDiv.error_message, 2): + print( + "While entering password in click_and_connect_server " + "function, error is occurred : " + str( + self.find_by_xpath( + ConnectToServerDiv.error_message).text), + file=sys.stderr) + else: + server_connection_status = True + except Exception as e: + print( + "There is some exception thrown click_and_connect_server " + "and is: " + str( + e), file=sys.stderr) + return server_connection_status + + def get_expansion_status_of_node(self, xpath_node): + """get the expansion status for a node through xpath""" + node_is_expanded = False + element = self.find_by_xpath(xpath_node) + if element.get_attribute("aria-expanded") == 'true': + node_is_expanded = True + return node_is_expanded + + def get_expansion_status_of_node_element(self, element): + """get the expansion status for an element""" + node_is_expanded = False + try: + if element.get_attribute("aria-expanded") == 'true': + node_is_expanded = True + except Exception as e: + print( + "There is some exception thrown in the function " + "get_expansion_status_of_node_element and is: " + str( + e), file=sys.stderr) + return node_is_expanded + + def toggle_open_tree_item(self, tree_item_text): + # 'sleep' here helps in cases where underlying nodes are auto opened. + # Otherwise, encountered situations where False value is returned + # even if the underlying node to be clicked was Opened. + time.sleep(.6) + item_with_text = self.find_by_xpath( + TreeAreaLocators.specified_tree_node.format(tree_item_text)) + + self.driver.execute_script("arguments[0].scrollIntoView()", + item_with_text) + + if item_with_text.find_element_by_xpath( + ".//ancestor::*[@class='aciTreeLine']").get_attribute( + "aria-expanded") == 'false': + item = item_with_text.find_element_by_xpath( + ".//parent::*[@class='aciTreeItem']") + ActionChains(self.driver).double_click(item).perform() + retry = 3 + while retry > 0: + try: + WebDriverWait(self.driver, 5).until((lambda item_with_text: ( + item_with_text.find_element_by_xpath( + ".//ancestor::*[@class='aciTreeLine']"). + get_attribute("aria-expanded") == 'true'))) + break + except TimeoutException: + retry -= 1 + pass + def toggle_open_server(self, tree_item_text): def check_for_password_dialog_or_tree_open(driver): try: @@ -692,6 +990,19 @@ class PgadminPage: return self._wait_for("element to exist", element_if_it_exists) + def wait_for_elements_to_appear(self, driver, locator, time_value=20): + """This will wait until list of elements or an element is visible, + The time out value is userdefined""" + elements_located_status = False + try: + if WebDriverWait(driver, time_value).until( + EC.visibility_of_any_elements_located(( + By.XPATH, locator))): + elements_located_status = True + except Exception as e: + pass + return elements_located_status + def find_by_xpath_list(self, xpath): """This will find out list of elements through a single xpath""" return self.wait_for_elements( @@ -749,11 +1060,11 @@ class PgadminPage: click_status = False attempt = 0 - while click_status is not True and attempt < 5: + while click_status is not True and attempt < 10: try: element = self.driver.find_element(*click_locator) element.click() - WebDriverWait(self.driver, 5).until( + WebDriverWait(self.driver, 2).until( EC.visibility_of_element_located(verify_locator)) click_status = True except Exception: diff --git a/web/regression/feature_utils/tree_area_locators.py b/web/regression/feature_utils/tree_area_locators.py index 524058f09..0b98e7547 100644 --- a/web/regression/feature_utils/tree_area_locators.py +++ b/web/regression/feature_utils/tree_area_locators.py @@ -26,6 +26,98 @@ class TreeAreaLocators(): "following-sibling::ul/li/div/div/div/span[2]/" \ "span[@class='aciTreeText']" + server_group_sub_nodes_exp_status = \ + "//div[div[span[span[contains(text(),'Servers')]]]]" \ + "/following-sibling::ul/li/div" + + server_group_sub_nodes_connected_status = \ + "//div[div[span[span[contains(text(), 'Servers')]]]]/" \ + "following-sibling::ul/li/div/div/div/span[2]" + specified_tree_node = \ "//div[@id='tree']//span[@class='aciTreeItem']/" \ "span[(@class='aciTreeText') and text()='{}']" + + specified_tree_node_exp_status = \ + "//div[@id='tree']//span[@class='aciTreeItem']/" \ + "span[(@class='aciTreeText') and text()='{}']" \ + "//ancestor::*[@class='aciTreeLine']" + + sub_nodes_of_tables_node = \ + "//div[div[div[div[div[div[div[div[span[span[" \ + "contains(text(),'Tables')]]]]]]]]]]/" \ + "following-sibling::ul/li/div//div/span[2]/span[2]" + + @staticmethod + def sub_nodes_of_a_server_node(server_name): + xpath = "//div[div[div[span[span[contains(text(),'%s')]]]]]/" \ + "following-sibling::ul/li/div[@class='aciTreeLine']" % \ + server_name + return xpath + + @staticmethod + def sub_nodes_of_a_server_node_exp_status(server_name): + xpath = "//div[div[div[span[span[contains(text(),'%s')]]]]]/" \ + "following-sibling::ul/li/div" % server_name + return xpath + + @staticmethod + def databases_node_of_a_server_node(server_name): + xpath = "//div[div[div[span[span[contains(text(),'%s')]]]]]/" \ + "following-sibling::ul/li/div/div/div/div/span[2]/span[2 " \ + "and text()='Databases ']" % server_name + return xpath + + @staticmethod + def sub_nodes_of_databases_node(server_name): + xpath = "//div[div[div[span[span[contains(text(),'%s')]]]]]/" \ + "following-sibling::ul/li[1]/div/following-sibling::ul/li/" \ + "div/div/div/div/div/span[2]/span[@class='aciTreeText']" % \ + server_name + return xpath + + @staticmethod + def sub_nodes_of_databases_node_exp_status(server_name): + xpath = "//div[div[div[span[span[contains(text(), '%s')]]]]]/" \ + "following-sibling::ul/li[1]/div/following-sibling::ul/li/" \ + "div" % server_name + return xpath + + @staticmethod + def sub_nodes_of_database_node(database_name): + xpath = "//div[div[div[div[div[span[span[contains(text()," \ + "'%s')]]]]]]]/following-sibling::ul/li/div/div/div/div/div/" \ + "div/span[2]/span[2]" % database_name + return xpath + + @staticmethod + def sub_nodes_of_database_node_exp_status(database_name): + xpath = "//div[div[div[div[div[span[span[contains(text(), " \ + "'%s')]]]]]]]/following-sibling::ul/li/div" % database_name + return xpath + + @staticmethod + def sub_nodes_of_schemas_node(database_name): + xpath = "//div[div[div[div[div[span[span[text()='%s']]]]]]]/" \ + "following-sibling::ul/li[7]/ul/li/div//div/span/" \ + "span[@class='aciTreeText']" % database_name + return xpath + + @staticmethod + def sub_nodes_of_schemas_node_exp_status(database_name): + xpath = "//div[div[div[div[div[span[span[text()='%s']]]]]]]/" \ + "following-sibling::ul/li[7]/ul/li/div" % database_name + return xpath + + @staticmethod + def sub_nodes_of_schema_node(database_name): + xpath = "//div[div[div[div[div[span[span[text()='%s']]]]]]]/" \ + "following-sibling::ul/li[7]/ul/li/ul/li/div//div/" \ + "span[2]/span[2]" % database_name + return xpath + + @staticmethod + def sub_nodes_of_schema_node_exp_status(database_name): + xpath = "//div[div[div[div[div[span[span[text()='%s']]]]]]]/" \ + "following-sibling::ul/li[7]/ul/li/ul/li/div" % database_name + return xpath diff --git a/web/regression/python_test_utils/test_gui_helper.py b/web/regression/python_test_utils/test_gui_helper.py index c31787cc7..7515ee158 100644 --- a/web/regression/python_test_utils/test_gui_helper.py +++ b/web/regression/python_test_utils/test_gui_helper.py @@ -6,6 +6,7 @@ # This software is released under the PostgreSQL Licence # ########################################################################## +from regression.feature_utils.locators import NavMenuLocators def close_bgprocess_popup(tester): @@ -41,3 +42,16 @@ def close_bgprocess_popup(tester): except Exception: tester.driver.find_element_by_css_selector( ".btn.btn-sm-sq.btn-primary.pg-bg-close > i").click() + + +def close_process_watcher(tester): + attempt = 5 + while attempt > 0: + close_btn = tester.page.find_by_xpath( + NavMenuLocators.process_watcher_close_button_xpath) + close_btn.click() + if not tester.page.check_if_element_exist_by_xpath( + NavMenuLocators.process_watcher_close_button_xpath, 1): + break + else: + attempt -= 1