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