mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Significant changes to use ReactJS extensively.
1. Replace the current layout library wcDocker with ReactJS based rc-dock. #6479 2. Have close buttons on individual panel tabs instead of common. #2821 3. Changes in the context menu on panel tabs - Add close, close all and close others menu items. #5394 4. Allow closing all the tabs, including SQL and Properties. #4733 5. Changes in docking behaviour of different tabs based on user requests and remove lock layout menu. 6. Fix an issue where the scroll position of panels was not remembered on Firefox. #2986 7. Reset layout now will not require page refresh and is done spontaneously. 8. Use the zustand store for storing preferences instead of plain JS objects. This will help reflecting preferences immediately. 9. The above fix incorrect format (no indent) of SQL stored functions/procedures. #6720 10. New version check is moved to an async request now instead of app start to improve startup performance. 11. Remove jQuery and Bootstrap completely. 12. Replace jasmine and karma test runner with jest. Migrate all the JS test cases to jest. This will save time in writing and debugging JS tests. 13. Other important code improvements and cleanup.
This commit is contained in:
@@ -72,6 +72,7 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
|
||||
BrowserToolBarLocators.open_query_tool_button_css),
|
||||
(By.CSS_SELECTOR, BrowserToolBarLocators.query_tool_panel_css)),
|
||||
'Query tool did not open on clicking Query Tool button.')
|
||||
|
||||
self.page.close_query_tool(prompt=False)
|
||||
|
||||
def test_view_data_tool_button(self):
|
||||
@@ -97,7 +98,7 @@ class BrowserToolBarFeatureTest(BaseFeatureTest):
|
||||
self.assertTrue(self.page.retry_click(
|
||||
(By.CSS_SELECTOR,
|
||||
BrowserToolBarLocators.filter_data_button_css),
|
||||
(By.XPATH, BrowserToolBarLocators.filter_box_css)),
|
||||
(By.CSS_SELECTOR, BrowserToolBarLocators.filter_box_css)),
|
||||
'Filter dialogue did not open on clicking filter button.')
|
||||
self.page.click_modal('Close')
|
||||
self.page.click_modal('Close', docker=True)
|
||||
self.page.close_query_tool(prompt=False)
|
||||
|
||||
@@ -184,8 +184,8 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
|
||||
"test_backup", input_keys=True, loose_focus=True)
|
||||
|
||||
# Click on the take Backup button
|
||||
take_bckup = self.page.find_by_xpath(
|
||||
NavMenuLocators.backup_btn_xpath)
|
||||
take_bckup = self.page.find_by_css_selector(
|
||||
NavMenuLocators.backup_btn)
|
||||
click = True
|
||||
retry = 3
|
||||
while click and retry > 0:
|
||||
@@ -193,8 +193,8 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
|
||||
take_bckup.click()
|
||||
if self.page.wait_for_element_to_disappear(
|
||||
lambda driver: driver.find_element(
|
||||
By.XPATH,
|
||||
"//*[@id='0']/div[contains(text(),'Backup')]")):
|
||||
By.CSS_SELECTOR,
|
||||
".dock-fbox div[title^='Backup']")):
|
||||
click = False
|
||||
except Exception:
|
||||
retry -= 1
|
||||
|
||||
@@ -79,7 +79,7 @@ class PGUtilitiesMaintenanceFeatureTest(BaseFeatureTest):
|
||||
|
||||
def runTest(self):
|
||||
self._open_maintenance_dialogue()
|
||||
self.page.click_modal('OK')
|
||||
self.page.click_modal('OK', docker=True)
|
||||
self.page.wait_for_element_to_disappear(
|
||||
lambda driver: driver.find_element(
|
||||
By.XPATH, NavMenuLocators.maintenance_operation), 10)
|
||||
|
||||
@@ -169,7 +169,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
|
||||
self.page.click_element(editor_input)
|
||||
self.page.execute_query(self.select_query % self.invalid_table_name)
|
||||
|
||||
self.page.click_tab(self.query_history_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Query History")
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear(
|
||||
container_id="id-history")
|
||||
selected_history_entry = self.page.find_by_css_selector(
|
||||
@@ -211,7 +211,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
|
||||
self.assertIn(self.select_query % self.invalid_table_name,
|
||||
invalid_history_entry.text)
|
||||
|
||||
self.page.click_tab(self.query_editor_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Query")
|
||||
self.page.clear_query_tool()
|
||||
self.page.click_element(editor_input)
|
||||
|
||||
@@ -223,7 +223,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
|
||||
QueryToolLocators.btn_execute_query_css).click()
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
|
||||
self.page.click_tab(self.query_history_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Query History")
|
||||
|
||||
query_list = self.page.wait_for_elements(
|
||||
lambda driver: driver.find_elements(
|
||||
@@ -237,10 +237,10 @@ class QueryToolJourneyTest(BaseFeatureTest):
|
||||
self._test_toggle_generated_queries()
|
||||
|
||||
def _test_history_query_sources(self):
|
||||
self.page.click_tab(self.query_editor_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Query")
|
||||
self._execute_sources_test_queries()
|
||||
|
||||
self.page.click_tab(self.query_history_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Query History")
|
||||
|
||||
history_entries_icons = [
|
||||
'CommitIcon',
|
||||
@@ -275,7 +275,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
|
||||
self.assertTrue(self.page.check_if_element_exist_by_xpath(xpath))
|
||||
|
||||
def _test_updatable_resultset(self):
|
||||
self.page.click_tab(self.query_editor_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Query")
|
||||
|
||||
# Select all data
|
||||
# (contains the primary key -> all columns should be editable)
|
||||
@@ -309,7 +309,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
|
||||
def _test_is_editable_columns_icons(self):
|
||||
if self.driver_version < 2.8:
|
||||
return
|
||||
self.page.click_tab(self.query_editor_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Query")
|
||||
|
||||
self.page.clear_query_tool()
|
||||
query = "SELECT pk_column FROM %s" % self.test_editable_table_name
|
||||
@@ -404,7 +404,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
|
||||
retry -= 1
|
||||
|
||||
def _insert_data_into_test_editable_table(self):
|
||||
self.page.click_tab(self.query_editor_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Query")
|
||||
self.page.clear_query_tool()
|
||||
self.page.execute_query(
|
||||
"INSERT INTO %s VALUES (1, 1), (2, 2);"
|
||||
@@ -412,7 +412,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
|
||||
)
|
||||
|
||||
def __clear_query_history(self):
|
||||
self.page.click_tab(self.query_history_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Query History")
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear(
|
||||
container_id="id-history")
|
||||
self.page.click_element(
|
||||
|
||||
@@ -257,7 +257,7 @@ SELECT generate_series(1, 1000) as id order by id desc"""
|
||||
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
|
||||
self.page.click_tab(self.data_output_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Data Output")
|
||||
|
||||
canvas = self.wait.until(EC.presence_of_element_located(
|
||||
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css))
|
||||
@@ -292,7 +292,7 @@ SELECT generate_series(1, 1000) as id order by id desc"""
|
||||
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
|
||||
self.page.click_tab(self.data_output_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Data Output")
|
||||
|
||||
self.wait.until(EC.presence_of_element_located(
|
||||
(By.XPATH, QueryToolLocators.output_cell_xpath.format(2, 2)))
|
||||
@@ -329,7 +329,7 @@ CREATE TABLE public.{}();""".format(table_name)
|
||||
self.page.click_execute_query_button()
|
||||
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
self.page.click_tab('id-messages', rc_dock=True)
|
||||
self.page.click_tab('Messages')
|
||||
|
||||
self.assertTrue(self.page.check_if_element_exist_by_xpath(
|
||||
QueryToolLocators.sql_editor_message.format('CREATE TABLE')),
|
||||
@@ -343,7 +343,7 @@ CREATE TABLE public.{}();""".format(table_name)
|
||||
-- 4. Check if table is *NOT* created.
|
||||
ROLLBACK;"""
|
||||
self.page.execute_query(query)
|
||||
self.page.click_tab('id-messages', rc_dock=True)
|
||||
self.page.click_tab('Messages')
|
||||
self.assertTrue(self.page.check_if_element_exist_by_xpath(
|
||||
QueryToolLocators.sql_editor_message.format('ROLLBACK')),
|
||||
"ROLLBACK message does not displayed")
|
||||
@@ -357,7 +357,7 @@ SELECT relname FROM pg_catalog.pg_class
|
||||
WHERE relkind IN ('r','s','t') and relnamespace = 2200::oid;"""
|
||||
|
||||
self.page.execute_query(query)
|
||||
self.page.click_tab(self.data_output_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Data Output")
|
||||
canvas = self.wait.until(EC.presence_of_element_located(
|
||||
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
|
||||
|
||||
@@ -411,7 +411,7 @@ CREATE TABLE public.{}();""".format(table_name)
|
||||
|
||||
self.page.execute_query(query)
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
self.page.click_tab('id-messages', rc_dock=True)
|
||||
self.page.click_tab('Messages')
|
||||
self.assertTrue(self.page.check_if_element_exist_by_xpath(
|
||||
QueryToolLocators.sql_editor_message.format('CREATE TABLE')),
|
||||
self.table_creation_fail_error)
|
||||
@@ -426,7 +426,7 @@ ROLLBACK;"""
|
||||
|
||||
self.page.execute_query(query)
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
self.page.click_tab('id-messages', rc_dock=True)
|
||||
self.page.click_tab('Messages')
|
||||
self.assertTrue(self.page.check_if_element_exist_by_xpath(
|
||||
QueryToolLocators.sql_editor_message.format('ROLLBACK')),
|
||||
"ROLLBACK message does not displayed")
|
||||
@@ -441,7 +441,7 @@ SELECT relname FROM pg_catalog.pg_class
|
||||
WHERE relkind IN ('r','s','t') and relnamespace = 2200::oid;"""
|
||||
|
||||
self.page.execute_query(query)
|
||||
self.page.click_tab(self.data_output_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Data Output")
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
|
||||
canvas = self.wait.until(EC.presence_of_element_located(
|
||||
@@ -490,7 +490,7 @@ END;"""
|
||||
CREATE TABLE public.{}();""".format(table_name)
|
||||
self.page.execute_query(query)
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
self.page.click_tab('id-messages', rc_dock=True)
|
||||
self.page.click_tab('Messages')
|
||||
self.assertTrue(self.page.check_if_element_exist_by_xpath(
|
||||
QueryToolLocators.sql_editor_message.format('CREATE TABLE')),
|
||||
self.table_creation_fail_error)
|
||||
@@ -505,7 +505,7 @@ CREATE TABLE public.{}();""".format(table_name)
|
||||
SELECT 1/0;"""
|
||||
self.page.execute_query(query)
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
self.page.click_tab('id-messages', rc_dock=True)
|
||||
self.page.click_tab('Messages')
|
||||
self.assertTrue(self.page.check_if_element_exist_by_xpath(
|
||||
QueryToolLocators.sql_editor_message.format('division by zero')),
|
||||
"division by zero message does not displayed")
|
||||
@@ -520,7 +520,7 @@ SELECT 1/0;"""
|
||||
END;"""
|
||||
self.page.execute_query(query)
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
self.page.click_tab('id-messages', rc_dock=True)
|
||||
self.page.click_tab('Messages')
|
||||
self.assertTrue(self.page.check_if_element_exist_by_xpath(
|
||||
QueryToolLocators.sql_editor_message.
|
||||
format('Query returned successfully')),
|
||||
@@ -537,7 +537,7 @@ SELECT relname FROM pg_catalog.pg_class
|
||||
WHERE relkind IN ('r','s','t') and relnamespace = 2200::oid;"""
|
||||
self.page.execute_query(query)
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
self.page.click_tab(self.data_output_tab_id, rc_dock=True)
|
||||
self.page.click_tab("Data Output")
|
||||
canvas = self.wait.until(EC.presence_of_element_located(
|
||||
(By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
|
||||
|
||||
@@ -580,7 +580,7 @@ SELECT 1, pg_sleep(300)"""
|
||||
self.page.find_by_css_selector(
|
||||
QueryToolLocators.btn_cancel_query).click()
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
self.page.click_tab('id-messages', rc_dock=True)
|
||||
self.page.click_tab('Messages')
|
||||
self.assertTrue(
|
||||
self.page.check_if_element_exist_by_xpath(
|
||||
QueryToolLocators.sql_editor_message
|
||||
@@ -593,7 +593,7 @@ SELECT 1, pg_sleep(300)"""
|
||||
def _query_tool_notify_statements(self):
|
||||
print("\n\tListen on an event... ", file=sys.stderr, end="")
|
||||
self.page.execute_query("LISTEN foo;")
|
||||
self.page.click_tab('id-messages', rc_dock=True)
|
||||
self.page.click_tab('Messages')
|
||||
|
||||
self.assertTrue(self.page.check_if_element_exist_by_xpath(
|
||||
QueryToolLocators.sql_editor_message.format('LISTEN')),
|
||||
@@ -603,7 +603,7 @@ SELECT 1, pg_sleep(300)"""
|
||||
|
||||
print("\tNotify event without data... ", file=sys.stderr, end="")
|
||||
self.page.execute_query("NOTIFY foo;")
|
||||
self.page.click_tab('id-notifications', rc_dock=True)
|
||||
self.page.click_tab('Notifications')
|
||||
self.wait.until(EC.text_to_be_present_in_element(
|
||||
(By.CSS_SELECTOR, "td[data-label='channel']"), "foo")
|
||||
)
|
||||
@@ -612,7 +612,7 @@ SELECT 1, pg_sleep(300)"""
|
||||
print("\tNotify event with data... ", file=sys.stderr, end="")
|
||||
self.page.clear_query_tool()
|
||||
self.page.execute_query("SELECT pg_notify('foo', 'Hello')")
|
||||
self.page.click_tab('id-notifications', rc_dock=True)
|
||||
self.page.click_tab('Notifications')
|
||||
self.wait.until(WaitForAnyElementWithText(
|
||||
(By.CSS_SELECTOR, "td[data-label='payload']"), "Hello"))
|
||||
print("OK.", file=sys.stderr)
|
||||
|
||||
@@ -171,9 +171,9 @@ CREATE TABLE public.nonintpkey
|
||||
self._copy_paste_row(config_data_local)
|
||||
|
||||
self._update_row(config_data_local)
|
||||
self.page.click_tab("id-messages", rc_dock=True)
|
||||
self.page.click_tab("Messages")
|
||||
self._verify_messsages("")
|
||||
self.page.click_tab("id-dataoutput", rc_dock=True)
|
||||
self.page.click_tab("Data Output")
|
||||
updated_row_data = {
|
||||
i: config_data_local['update'][i] if i in config_data_local[
|
||||
'update'] else val
|
||||
@@ -182,7 +182,7 @@ CREATE TABLE public.nonintpkey
|
||||
self._verify_row_data(row=1,
|
||||
config_check_data=updated_row_data)
|
||||
|
||||
self.page.close_data_grid()
|
||||
self.page.close_query_tool(prompt=False)
|
||||
|
||||
def _compare_cell_value(self, xpath, value):
|
||||
# Initialize an instance of WebDriverWait with timeout of 5 seconds
|
||||
|
||||
@@ -78,7 +78,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
|
||||
# Query tool view/edit data
|
||||
self.page.open_view_data(self.test_db)
|
||||
self._check_xss_view_data()
|
||||
self.page.close_data_grid()
|
||||
self.page.close_query_tool(prompt=False)
|
||||
|
||||
# Explain module
|
||||
self.page.open_query_tool()
|
||||
@@ -110,7 +110,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
|
||||
)
|
||||
# Fetch the inner html & check for escaped characters
|
||||
source_code = self.page.find_by_xpath(
|
||||
"//*[@id='tree']"
|
||||
"//*[@id='id-object-explorer']"
|
||||
).get_attribute('innerHTML')
|
||||
|
||||
self._check_escaped_characters(
|
||||
@@ -156,10 +156,10 @@ class CheckForXssFeatureTest(BaseFeatureTest):
|
||||
try:
|
||||
self.page.click_tab("Dependents")
|
||||
source_code = \
|
||||
self.page.find_by_xpath(
|
||||
"//*[@id='5']/table/tbody/tr/td/div/div/div[2]/div"
|
||||
"/div[2]/div[1]/div/div/div/div/"
|
||||
"div/div[2]").get_attribute('innerHTML')
|
||||
self.page.find_by_css_selector(
|
||||
"#id-dependents div[role='row']:nth-child(1) "
|
||||
"div[role='cell']:nth-child(2)"
|
||||
).get_attribute('innerHTML')
|
||||
retry = 0
|
||||
except WebDriverException as e:
|
||||
print("Exception in dependent tab {0}".format(retry),
|
||||
@@ -208,7 +208,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
|
||||
self.page.find_by_css_selector(
|
||||
QueryToolLocators.btn_execute_query_css).click()
|
||||
|
||||
self.page.click_tab('id-history', rc_dock=True)
|
||||
self.page.click_tab('Query History')
|
||||
|
||||
# Check for history entry
|
||||
history_ele = self.page\
|
||||
@@ -240,7 +240,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
|
||||
"Query tool (History Details-Message)"
|
||||
)
|
||||
|
||||
self.page.click_tab('id-query', rc_dock=True)
|
||||
self.page.click_tab('Query')
|
||||
|
||||
def _check_xss_view_data(self):
|
||||
print(
|
||||
@@ -272,7 +272,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
|
||||
self.page.find_by_css_selector(
|
||||
QueryToolLocators.btn_explain).click()
|
||||
self.page.wait_for_query_tool_loading_indicator_to_disappear()
|
||||
self.page.click_tab('id-explain', rc_dock=True)
|
||||
self.page.click_tab('Explain')
|
||||
|
||||
for idx in range(3):
|
||||
# Re-try logic
|
||||
|
||||
@@ -123,7 +123,7 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
|
||||
|
||||
# Only this tab is vulnerable rest are Code Mirror
|
||||
# control which are already tested in Query tool test case
|
||||
self.page.click_tab('id-debugger-messages', rc_dock=True)
|
||||
self.page.click_tab('Messages')
|
||||
source_code = self.page.find_by_xpath(
|
||||
"//div[@id='id-debugger-messages'] //div[@id='debugger-msg']"
|
||||
).get_attribute('innerHTML')
|
||||
@@ -139,10 +139,9 @@ class CheckDebuggerForXssFeatureTest(BaseFeatureTest):
|
||||
|
||||
def _close_debugger(self):
|
||||
self.page.driver.switch_to.default_content()
|
||||
self.page.click_element(
|
||||
self.page.find_by_xpath(
|
||||
"//*[@id='dockerContainer']/div/div[3]/div/div[2]/div[1]")
|
||||
)
|
||||
self.page.find_by_css_selector("div[data-dockid='id-main'] "
|
||||
".dock-tab.dock-tab-active "
|
||||
"button[data-label='Close']").click()
|
||||
|
||||
def _check_escaped_characters(self, source_code, string_to_find, source):
|
||||
# For XSS we need to search against element's html code
|
||||
|
||||
@@ -80,7 +80,8 @@ class CheckRoleMembershipControlFeatureTest(BaseFeatureTest):
|
||||
|
||||
# Fetch the source code for our custom control
|
||||
source_code = self.page.find_by_xpath(
|
||||
"//span[contains(@class,'icon-')]/following-sibling::span"
|
||||
"//div[contains(@role, 'cell')]//span[contains(@class,'icon-')]"
|
||||
"/following-sibling::span"
|
||||
).get_attribute('innerHTML')
|
||||
|
||||
self._check_escaped_characters(
|
||||
|
||||
Reference in New Issue
Block a user