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 691f35d88..0e1d19ecc 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
@@ -54,16 +54,17 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
         self._copies_columns()
         self._copies_row_using_keyboard_shortcut()
         self._copies_column_using_keyboard_shortcut()
-        self._copies_rectangular_selection()
-        self._shift_resizes_rectangular_selection()
+        # The below calls is commented since the new data grid does not
+        # support range selection. This can be enabled once the
+        # range selection is implemented.
+        # self._copies_rectangular_selection()
+        # self._shift_resizes_rectangular_selection()
+
         self._shift_resizes_column_selection()
-        self._mouseup_outside_grid_still_makes_a_selection()
+        self._mouseup_outside_grid_does_not_make_a_selection()
         self._copies_rows_with_header()
 
     def paste_values_to_scratch_pad(self):
-        self.page.driver.switch_to.default_content()
-        self.page.driver.switch_to.frame(
-            self.page.driver.find_element(By.TAG_NAME, "iframe"))
         scratch_pad_ele = self.page.find_by_css_selector(
             QueryToolLocators.scratch_pad_css)
         self.page.paste_values(scratch_pad_ele)
@@ -73,7 +74,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
 
     def _copies_rows(self):
         first_row = self.page.find_by_xpath(
-            QueryToolLocators.output_row_xpath.format(1))
+            QueryToolLocators.output_cell_xpath.format(2, 1))
         first_row.click()
 
         copy_button = self.page.find_by_css_selector(
@@ -85,8 +86,10 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
                          clipboard_text)
 
     def _copies_rows_with_header(self):
-        self.page.find_by_css_selector('#btn-copy-row-dropdown').click()
-        self.page.find_by_css_selector('a#btn-copy-with-header').click()
+        self.page.find_by_css_selector(QueryToolLocators.copy_options_css)\
+            .click()
+        self.page.find_by_css_selector(QueryToolLocators.copy_headers_btn_css)\
+            .click()
 
         select_all = self.page.find_by_xpath(
             QueryToolLocators.select_all_column)
@@ -122,7 +125,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
 
     def _copies_row_using_keyboard_shortcut(self):
         first_row = self.page.find_by_xpath(
-            QueryToolLocators.output_row_xpath.format(1))
+            QueryToolLocators.output_cell_xpath.format(2, 1))
         first_row.click()
 
         ActionChains(self.page.driver).key_down(
@@ -216,7 +219,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
             '"Some-Name"\t6\n"Some-Other-Name"\t22\n"Yet-Another-Name"\t14',
             clipboard_text)
 
-    def _mouseup_outside_grid_still_makes_a_selection(self):
+    def _mouseup_outside_grid_does_not_make_a_selection(self):
         bottom_right_cell = self.page.find_by_xpath(
             QueryToolLocators.output_column_data_xpath.format('cool info')
         )
@@ -233,7 +236,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest):
 
         clipboard_text = self.paste_values_to_scratch_pad()
 
-        self.assertIn('"cool info"', clipboard_text)
+        self.assertNotIn('"cool info"', clipboard_text)
 
     def after(self):
         self.page.close_query_tool()
diff --git a/web/pgadmin/feature_tests/query_tool_journey_test.py b/web/pgadmin/feature_tests/query_tool_journey_test.py
index a541f4171..0cb2c1c0d 100644
--- a/web/pgadmin/feature_tests/query_tool_journey_test.py
+++ b/web/pgadmin/feature_tests/query_tool_journey_test.py
@@ -35,7 +35,9 @@ class QueryToolJourneyTest(BaseFeatureTest):
 
     select_query = "SELECT * FROM %s"
     query_history_tab_name = "Query History"
+    query_history_tab_id = "id-history"
     query_editor_tab_name = "Query Editor"
+    query_editor_tab_id = "id-query"
 
     def before(self):
         self.test_table_name = "test_table" + str(random.randint(1000, 3000))
@@ -98,8 +100,10 @@ class QueryToolJourneyTest(BaseFeatureTest):
         self.page.driver.switch_to.frame(
             self.page.driver.find_element_by_tag_name("iframe"))
 
-        select_row = self.page.find_by_xpath(
-            QueryToolLocators.output_row_xpath.format('1'))
+        # row index starts with 2
+        select_row = self.page.find_by_css_selector(
+            QueryToolLocators.output_row_col.format('2', '1'))
+
         select_row.click()
 
         copy_row = self.page.find_by_css_selector(
@@ -133,10 +137,6 @@ class QueryToolJourneyTest(BaseFeatureTest):
             QueryToolLocators.copy_button_css)
         copy_btn.click()
 
-        self.page.driver.switch_to.default_content()
-        self.page.driver.switch_to.frame(
-            self.page.driver.find_element_by_tag_name("iframe"))
-
         scratch_pad_ele = self.page.find_by_css_selector(
             QueryToolLocators.scratch_pad_css)
         self.page.paste_values(scratch_pad_ele)
@@ -149,16 +149,19 @@ class QueryToolJourneyTest(BaseFeatureTest):
         scratch_pad_ele.clear()
 
     def _test_history_tab(self):
-        self.page.clear_query_tool()
+        self.page.driver.switch_to.default_content()
         self.page.driver.switch_to.frame(
             self.page.driver.find_element_by_tag_name("iframe"))
+        self.page.clear_query_tool()
 
         editor_input = self.page.find_by_css_selector(
             QueryToolLocators.query_editor_panel)
         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_name)
+        self.page.click_tab(self.query_history_tab_id, rc_dock=True)
+        self.page.wait_for_query_tool_loading_indicator_to_disappear(
+            container_id="id-history")
         selected_history_entry = self.page.find_by_css_selector(
             QueryToolLocators.query_history_selected)
         self.assertIn(self.select_query % self.invalid_table_name,
@@ -168,7 +171,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
             QueryToolLocators.query_history_detail)
 
         self.assertIn(
-            "Error Message relation \"%s\" does not exist"
+            "ERROR:  relation \"%s\" does not exist"
             % self.invalid_table_name,
             failed_history_detail_pane.text
         )
@@ -198,10 +201,8 @@ class QueryToolJourneyTest(BaseFeatureTest):
         self.assertIn(self.select_query % self.invalid_table_name,
                       invalid_history_entry.text)
 
-        self.page.click_tab(self.query_editor_tab_name)
+        self.page.click_tab(self.query_editor_tab_id, rc_dock=True)
         self.page.clear_query_tool()
-        self.page.driver.switch_to.frame(
-            self.page.driver.find_element_by_tag_name("iframe"))
         self.page.click_element(editor_input)
 
         # Check if 15 more query executed then the history should contain 17
@@ -212,7 +213,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_name)
+        self.page.click_tab(self.query_history_tab_id, rc_dock=True)
 
         query_list = self.page.wait_for_elements(
             lambda driver: driver.find_elements(
@@ -226,20 +227,18 @@ class QueryToolJourneyTest(BaseFeatureTest):
         self._test_toggle_generated_queries()
 
     def _test_history_query_sources(self):
-        self.page.driver.switch_to.frame(
-            self.page.driver.find_element_by_tag_name("iframe"))
-        self.page.click_tab(self.query_editor_tab_name)
+        self.page.click_tab(self.query_editor_tab_id, rc_dock=True)
         self._execute_sources_test_queries()
 
-        self.page.click_tab(self.query_history_tab_name)
+        self.page.click_tab(self.query_history_tab_id, rc_dock=True)
 
         history_entries_icons = [
-            QueryToolLocators.commit_icon,
-            QueryToolLocators.save_data_icon,
-            QueryToolLocators.save_data_icon,
-            QueryToolLocators.execute_icon,
-            QueryToolLocators.explain_analyze_icon,
-            QueryToolLocators.explain_icon
+            'CommitIcon',
+            'SaveDataIcon',
+            'SaveDataIcon',
+            'ExecuteIcon',
+            'ExplainAnalyzeIcon',
+            'ExplainIcon',
         ]
 
         history_entries_queries = [
@@ -256,7 +255,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
                                               history_entries_icons)
 
     def _test_toggle_generated_queries(self):
-        xpath = '//li[contains(@class, "pgadmin-query-history-entry")]'
+        xpath = "//li[@data-label='history-entry'][@data-pgadmin='true']"
         self.assertTrue(self.page.check_if_element_exist_by_xpath(xpath))
         self.page.set_switch_box_status(
             QueryToolLocators.show_query_internally_btn, 'No')
@@ -266,9 +265,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
         self.assertTrue(self.page.check_if_element_exist_by_xpath(xpath))
 
     def _test_updatable_resultset(self):
-        if self.driver_version < 2.8:
-            return
-        self.page.click_tab(self.query_editor_tab_name)
+        self.page.click_tab(self.query_editor_tab_id, rc_dock=True)
 
         # Select all data
         # (contains the primary key -> all columns should be editable)
@@ -295,19 +292,18 @@ class QueryToolJourneyTest(BaseFeatureTest):
         self._check_query_results_editable(query,
                                            [True, True, False, False, False])
 
+        # discard edits
+        self.page.execute_query('SELECT 1')
+        self.page.click_modal('Yes', True)
+
     def _test_is_editable_columns_icons(self):
         if self.driver_version < 2.8:
             return
-        self.page.click_tab(self.query_editor_tab_name)
+        self.page.click_tab(self.query_editor_tab_id, rc_dock=True)
 
         self.page.clear_query_tool()
         query = "SELECT pk_column FROM %s" % self.test_editable_table_name
         self.page.execute_query(query)
-        # Discard changes made by previous test to data grid
-        self.page.driver.switch_to.default_content()
-        self.page.click_modal('Yes', True)
-        self.page.driver.switch_to.frame(
-            self.page.driver.find_element_by_tag_name("iframe"))
 
         icon_exists = self.page.check_if_element_exist_by_xpath(
             QueryToolLocators.editable_column_icon_xpath
@@ -344,33 +340,38 @@ class QueryToolJourneyTest(BaseFeatureTest):
         query_options.click()
         self.page.uncheck_execute_option("auto_commit")
 
-        self._update_numeric_cell(2, 10)
+        self._update_numeric_cell(10)
         time.sleep(0.5)
 
         self._commit_transaction()
+        self.page.wait_for_spinner_to_disappear()
 
         # Turn on autocommit
-        retry = 3
-        while retry > 0:
-            query_options = self.page.find_by_css_selector(
-                QueryToolLocators.btn_query_dropdown)
-            query_options.click()
-            expanded = query_options.get_attribute("aria-expanded")
-            if expanded == "false":
-                print("query option not yet expanded clicking commit again",
-                      file=sys.stderr)
-                self._commit_transaction()
-                time.sleep(0.5)
-                query_options.click()
-                break
-            else:
-                retry -= 1
+        # self.page.check_execute_option("auto_commit")
+        # query_options = self.page.find_by_css_selector(
+        #     QueryToolLocators.btn_query_dropdown)
+        # query_options.click()
+        # retry = 3
+        # while retry > 0:
+        #     query_options = self.page.find_by_css_selector(
+        #         QueryToolLocators.btn_query_dropdown)
+        #     query_options.click()
+        #     expanded = query_options.get_attribute("aria-expanded")
+        #     if expanded == "false":
+        #         print("query option not yet expanded clicking commit again",
+        #               file=sys.stderr)
+        #         self._commit_transaction()
+        #         time.sleep(0.5)
+        #         query_options.click()
+        #         break
+        #     else:
+        #         retry -= 1
         self.page.check_execute_option("auto_commit")
 
     def _check_history_queries_and_icons(self, history_queries, history_icons):
         # Select first query history entry
         self.page.find_by_css_selector(
-            QueryToolLocators.query_history_specific_entry.format(1)).click()
+            QueryToolLocators.query_history_specific_entry.format(2)).click()
         for icon, query in zip(history_icons, history_queries):
             # Check query
             query_history_selected_item = self.page.find_by_css_selector(
@@ -382,27 +383,20 @@ class QueryToolJourneyTest(BaseFeatureTest):
             # Check source icon
             query_history_selected_icon = self.page.find_by_css_selector(
                 QueryToolLocators.query_history_selected_icon)
-            icon_classes = query_history_selected_icon.get_attribute('class')
-            icon_classes = icon_classes.split(" ")
             self.assertTrue(
-                icon in icon_classes or 'icon-save_data_changes' in
-                icon_classes or 'icon-commit' in icon_classes or
-                'fa-play' in icon_classes)
+                icon == query_history_selected_icon.get_attribute(
+                    'data-label'))
             # Move to next entry
             ActionChains(self.page.driver) \
                 .send_keys(Keys.ARROW_DOWN) \
                 .perform()
 
-    def _update_numeric_cell(self, cell_index, value):
+    def _update_numeric_cell(self, value):
         """
             Updates a numeric cell in the first row of the resultset
         """
-        cell_xpath = "//div[contains(@style, 'top:0px')]//" \
-                     "div[contains(@class,'l{0} r{1}')]". \
-            format(cell_index, cell_index)
-
-        self.page.check_if_element_exist_by_xpath(cell_xpath)
-        cell_el = self.page.find_by_xpath(cell_xpath)
+        cell_el = self.page.find_by_css_selector(
+            QueryToolLocators.output_row_col.format(2, 3))
         ActionChains(self.driver).double_click(cell_el).perform()
         ActionChains(self.driver).send_keys(value). \
             send_keys(Keys.ENTER).perform()
@@ -410,7 +404,7 @@ class QueryToolJourneyTest(BaseFeatureTest):
             QueryToolLocators.btn_save_data).click()
 
     def _insert_data_into_test_editable_table(self):
-        self.page.click_tab(self.query_editor_tab_name)
+        self.page.click_tab(self.query_editor_tab_id, rc_dock=True)
         self.page.clear_query_tool()
         self.page.execute_query(
             "INSERT INTO %s VALUES (1, 1), (2, 2);"
@@ -418,18 +412,13 @@ class QueryToolJourneyTest(BaseFeatureTest):
         )
 
     def __clear_query_history(self):
+        self.page.click_tab(self.query_history_tab_id, rc_dock=True)
+        self.page.wait_for_query_tool_loading_indicator_to_disappear(
+            container_id="id-history")
         self.page.click_element(
             self.page.find_by_css_selector(
-                QueryToolLocators.btn_clear_dropdown)
-        )
-        ActionChains(self.driver) \
-            .move_to_element(
-            self.page.find_by_css_selector(
-                QueryToolLocators.btn_clear_history)).perform()
-        self.page.click_element(
-            self.page.find_by_css_selector(QueryToolLocators.btn_clear_history)
+                QueryToolLocators.btn_history_remove_all)
         )
-        self.driver.switch_to.default_content()
         self.page.click_modal('Yes', True)
 
     def _navigate_to_query_tool(self):
@@ -460,12 +449,10 @@ class QueryToolJourneyTest(BaseFeatureTest):
                                       discard_changes_modal=False):
         self.page.execute_query(query)
         if discard_changes_modal:
-            self.driver.switch_to.default_content()
             self.page.click_modal('Yes', True)
-            self.page.driver.switch_to.frame(
-                self.page.driver.find_element_by_tag_name("iframe"))
 
-        enumerated_should_be_editable = enumerate(cols_should_be_editable, 1)
+        # first column is rownum
+        enumerated_should_be_editable = enumerate(cols_should_be_editable, 2)
 
         import time
         time.sleep(0.5)
@@ -475,9 +462,8 @@ class QueryToolJourneyTest(BaseFeatureTest):
 
     def _check_cell_editable(self, cell_index):
         """Checks if a cell in the first row of the resultset is editable"""
-        cell_el = self.page.find_by_xpath(
-            "//div[contains(@style, 'top:0px')]//div[contains(@class, "
-            "'l{0} r{1}')]".format(cell_index, cell_index))
+        cell_el = self.page.find_by_css_selector(
+            QueryToolLocators.output_row_col.format(2, cell_index))
 
         # Get existing value
         cell_value = int(cell_el.text)
@@ -489,9 +475,9 @@ class QueryToolJourneyTest(BaseFeatureTest):
 
         # Check if the value was updated
         # Finding element again to avoid stale element reference exception
-        cell_el = self.page.find_by_xpath(
-            "//div[contains(@style, 'top:0px')]//div[contains(@class, "
-            "'l{0} r{1}')]".format(cell_index, cell_index))
+        cell_el = self.page.\
+            find_by_css_selector(QueryToolLocators.
+                                 output_row_col.format(2, cell_index))
         return int(cell_el.text) == new_value
 
     def _check_can_add_row(self):
diff --git a/web/pgadmin/feature_tests/query_tool_tests.py b/web/pgadmin/feature_tests/query_tool_tests.py
index 74e46878d..3915a29e7 100644
--- a/web/pgadmin/feature_tests/query_tool_tests.py
+++ b/web/pgadmin/feature_tests/query_tool_tests.py
@@ -30,7 +30,7 @@ class QueryToolFeatureTest(BaseFeatureTest):
     scenarios = [
         ("Query tool feature test", dict())
     ]
-    data_output_tab_name = 'Data Output'
+    data_output_tab_id = 'id-dataoutput'
     table_creation_fail_error = '"CREATE TABLE message does not displayed"'
 
     def before(self):
@@ -45,10 +45,10 @@ class QueryToolFeatureTest(BaseFeatureTest):
         self.wait = WebDriverWait(self.page.driver, 10)
 
     def runTest(self):
+        skip_warning = "Skipped."
         # on demand result set on scrolling.
         print("\nOn demand query result... ",
               file=sys.stderr, end="")
-        skip_warning = "Skipped."
         self._on_demand_result()
         self.page.clear_query_tool()
 
@@ -128,8 +128,7 @@ class QueryToolFeatureTest(BaseFeatureTest):
                    QueryToolLocators.btn_explain_buffers,
                    QueryToolLocators.btn_explain_timing):
             btn = self.page.find_by_css_selector(op)
-            check = btn.find_element(By.TAG_NAME, 'i')
-            if 'visibility-hidden' not in check.get_attribute('class'):
+            if btn.get_attribute('data-checked') == 'true':
                 btn.click()
 
         query_op = self.page.find_by_css_selector(
@@ -234,17 +233,16 @@ SELECT generate_series(1, {}) as id1, 'dummy' as id2""".format(
                 self.page.find_by_css_selector(
                     QueryToolLocators.output_column_header_css.format('id1'))
             column_1.click()
-            canvas_ele = self.page.find_by_css_selector('.grid-canvas')
-            scrolling_height = canvas_ele.size['height']
+            grid = self.page.find_by_css_selector('.rdg')
+            scrolling_height = grid.size['height']
             self.driver.execute_script(
-                "pgAdmin.SqlEditor.jquery('.slick-viewport')"
-                ".scrollTop(pgAdmin.SqlEditor.jquery('.grid-canvas')"
-                ".height());"
+                "document.querySelector('.rdg').scrollTop="
+                "document.querySelector('.rdg').scrollHeight"
             )
             # Table height takes some time to update, for which their is no
             # particular way
             time.sleep(2)
-            if canvas_ele.size['height'] == scrolling_height and \
+            if grid.size['height'] == scrolling_height and \
                 self.page.check_if_element_exist_by_xpath(
                     QueryToolLocators.output_column_data_xpath.format(
                         row_id_to_find)):
@@ -279,12 +277,16 @@ 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_name)
+        self.page.click_tab(self.data_output_tab_id, rc_dock=True)
 
         canvas = self.wait.until(EC.presence_of_element_located(
             (By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css))
         )
 
+        self.wait.until(EC.presence_of_element_located(
+            (By.CSS_SELECTOR,
+             QueryToolLocators.query_output_cells)))
+
         # Search for 'Output' word in result (verbose option)
         canvas.find_element(By.XPATH, "//*[contains(string(), 'Output')]")
 
@@ -313,14 +315,14 @@ 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_name)
+        self.page.click_tab(self.data_output_tab_id, rc_dock=True)
 
         self.wait.until(EC.presence_of_element_located(
-            (By.XPATH, QueryToolLocators.output_cell_xpath.format(1, 1)))
+            (By.XPATH, QueryToolLocators.output_cell_xpath.format(2, 2)))
         )
 
         result = self.page.find_by_xpath(
-            QueryToolLocators.output_cell_xpath.format(1, 1))
+            QueryToolLocators.output_cell_xpath.format(2, 2))
 
         # Search for 'Shared Read Blocks' word in result (buffers option)
         self.assertIn('Shared Read Blocks', result.text)
@@ -350,7 +352,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('Messages')
+        self.page.click_tab('id-messages', rc_dock=True)
 
         self.assertTrue(self.page.check_if_element_exist_by_xpath(
             QueryToolLocators.sql_editor_message.format('CREATE TABLE')),
@@ -364,7 +366,7 @@ CREATE TABLE public.{}();""".format(table_name)
 -- 4. Check if table is *NOT* created.
 ROLLBACK;"""
         self.page.execute_query(query)
-        self.page.click_tab('Messages')
+        self.page.click_tab('id-messages', rc_dock=True)
         self.assertTrue(self.page.check_if_element_exist_by_xpath(
             QueryToolLocators.sql_editor_message.format('ROLLBACK')),
             "ROLLBACK message does not displayed")
@@ -378,7 +380,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_name)
+        self.page.click_tab(self.data_output_tab_id, rc_dock=True)
         canvas = self.wait.until(EC.presence_of_element_located(
             (By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
 
@@ -432,7 +434,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('Messages')
+        self.page.click_tab('id-messages', rc_dock=True)
         self.assertTrue(self.page.check_if_element_exist_by_xpath(
             QueryToolLocators.sql_editor_message.format('CREATE TABLE')),
             self.table_creation_fail_error)
@@ -447,7 +449,7 @@ ROLLBACK;"""
 
         self.page.execute_query(query)
         self.page.wait_for_query_tool_loading_indicator_to_disappear()
-        self.page.click_tab('Messages')
+        self.page.click_tab('id-messages', rc_dock=True)
         self.assertTrue(self.page.check_if_element_exist_by_xpath(
             QueryToolLocators.sql_editor_message.format('ROLLBACK')),
             "ROLLBACK message does not displayed")
@@ -462,7 +464,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_name)
+        self.page.click_tab(self.data_output_tab_id, rc_dock=True)
         self.page.wait_for_query_tool_loading_indicator_to_disappear()
 
         canvas = self.wait.until(EC.presence_of_element_located(
@@ -511,7 +513,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('Messages')
+        self.page.click_tab('id-messages', rc_dock=True)
         self.assertTrue(self.page.check_if_element_exist_by_xpath(
             QueryToolLocators.sql_editor_message.format('CREATE TABLE')),
             self.table_creation_fail_error)
@@ -526,7 +528,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('Messages')
+        self.page.click_tab('id-messages', rc_dock=True)
         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")
@@ -541,7 +543,7 @@ SELECT 1/0;"""
 END;"""
         self.page.execute_query(query)
         self.page.wait_for_query_tool_loading_indicator_to_disappear()
-        self.page.click_tab('Messages')
+        self.page.click_tab('id-messages', rc_dock=True)
         self.assertTrue(self.page.check_if_element_exist_by_xpath(
             QueryToolLocators.sql_editor_message.
             format('Query returned successfully')),
@@ -558,7 +560,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_name)
+        self.page.click_tab(self.data_output_tab_id, rc_dock=True)
         canvas = self.wait.until(EC.presence_of_element_located(
             (By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css)))
 
@@ -580,30 +582,20 @@ SELECT 1, pg_sleep(300)"""
         self.page.fill_codemirror_area_with(query)
 
         # query_button drop can be disabled so enable
-        commit_button = self.page.find_by_css_selector("#btn-commit")
+        commit_button = self.page.find_by_css_selector(
+            QueryToolLocators.btn_commit)
         if not commit_button.get_attribute('disabled'):
             commit_button.click()
             time.sleep(0.5)
 
-        query_op = self.page.find_by_css_selector(
-            QueryToolLocators.btn_query_dropdown)
-        query_op.click()
-
         # enable auto-commit and disable auto-rollback
         self.page.check_execute_option('auto_commit')
         self.page.uncheck_execute_option('auto_rollback')
-        # close drop down
-        query_op.click()
+
         # Execute query
-        retry = 5
-        execute_button = self.page.find_by_css_selector(
-            QueryToolLocators.btn_execute_query_css)
-        while retry > 0:
-            execute_button.click()
-            if self.page.wait_for_query_tool_loading_indicator_to_appear():
-                break
-            else:
-                retry -= 1
+        self.page.find_by_css_selector(
+            QueryToolLocators.btn_execute_query_css).click()
+
         # Providing a second of sleep since clicks on the execute and stop
         # query button is too quick that the query is not able run properly
         time.sleep(1)
@@ -611,12 +603,15 @@ 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('Messages')
-        self.assertTrue(self.page.check_if_element_exist_by_xpath(
-            '//div[contains(@class, "sql-editor-message") and '
-            '(contains(string(), "canceling statement due to user request") '
-            'or contains(string(), "Execution Cancelled!"))]'
-        ))
+        self.page.click_tab('id-messages', rc_dock=True)
+        self.assertTrue(
+            self.page.check_if_element_exist_by_xpath(
+                QueryToolLocators.sql_editor_message
+                .format('canceling statement due to user request')) or
+            self.page.check_if_element_exist_by_xpath(
+                QueryToolLocators.sql_editor_message
+                .format('Execution Cancelled!'))
+        )
 
     def _supported_server_version(self):
         connection = test_utils.get_db_connection(
@@ -632,7 +627,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('Messages')
+        self.page.click_tab('id-messages', rc_dock=True)
 
         self.assertTrue(self.page.check_if_element_exist_by_xpath(
             QueryToolLocators.sql_editor_message.format('LISTEN')),
@@ -642,9 +637,9 @@ SELECT 1, pg_sleep(300)"""
 
         print("\tNotify event without data... ", file=sys.stderr, end="")
         self.page.execute_query("NOTIFY foo;")
-        self.page.click_tab('Notifications')
+        self.page.click_tab('id-notifications', rc_dock=True)
         self.wait.until(EC.text_to_be_present_in_element(
-            (By.CSS_SELECTOR, "td.channel"), "foo")
+            (By.CSS_SELECTOR, "td[data-label='channel']"), "foo")
         )
         print("OK.", file=sys.stderr)
 
@@ -652,9 +647,9 @@ SELECT 1, pg_sleep(300)"""
         if self._supported_server_version():
             self.page.clear_query_tool()
             self.page.execute_query("SELECT pg_notify('foo', 'Hello')")
-            self.page.click_tab('Notifications')
+            self.page.click_tab('id-notifications', rc_dock=True)
             self.wait.until(WaitForAnyElementWithText(
-                (By.CSS_SELECTOR, 'td.payload'), "Hello"))
+                (By.CSS_SELECTOR, "td[data-label='payload']"), "Hello"))
             print("OK.", file=sys.stderr)
         else:
             print("Skipped.", file=sys.stderr)
@@ -700,8 +695,7 @@ SELECT 1, pg_sleep(300)"""
                    QueryToolLocators.btn_explain_buffers,
                    QueryToolLocators.btn_explain_timing):
             btn = self.page.find_by_css_selector(op)
-            check = btn.find_element(By.TAG_NAME, 'i')
-            if 'visibility-hidden' not in check.get_attribute('class'):
+            if btn.get_attribute('data-checked') == 'true':
                 btn.click()
         # click cost button
         cost_btn = self.page.find_by_css_selector(
@@ -715,7 +709,7 @@ SELECT 1, pg_sleep(300)"""
             QueryToolLocators.btn_explain_analyze).click()
 
         self.page.wait_for_query_tool_loading_indicator_to_disappear()
-        self.page.click_tab(self.data_output_tab_name)
+        self.page.click_tab(self.data_output_tab_id, rc_dock=True)
 
         canvas = self.wait.until(EC.presence_of_element_located(
             (By.CSS_SELECTOR, QueryToolLocators.query_output_canvas_css))
diff --git a/web/pgadmin/feature_tests/view_data_dml_queries.py b/web/pgadmin/feature_tests/view_data_dml_queries.py
index 7d174b7fe..566065be5 100644
--- a/web/pgadmin/feature_tests/view_data_dml_queries.py
+++ b/web/pgadmin/feature_tests/view_data_dml_queries.py
@@ -145,19 +145,7 @@ CREATE TABLE public.nonintpkey
 
     @staticmethod
     def _get_cell_xpath(cell, row):
-
-        if row == 1:
-            xpath_grid_row = "//*[contains(@class, 'ui-widget-content') " \
-                             "and contains(@style, 'top:0px')]"
-        else:
-            xpath_grid_row = "//*[contains(@class, 'ui-widget-content') " \
-                             "and contains(@style, 'top:25px')]"
-
-        xpath_row_cell = '//div[contains(@class, "' + cell + '")]'
-
-        xpath_cell = '{0}{1}'.format(xpath_grid_row, xpath_row_cell)
-
-        return xpath_cell
+        return QueryToolLocators.output_cell_xpath.format(row, cell)
 
     @staticmethod
     def _load_config_data(config_key):
@@ -179,22 +167,22 @@ CREATE TABLE public.nonintpkey
         self.page.wait_for_query_tool_loading_indicator_to_disappear()
         # Run test to insert a new row in table with default values
         self._add_row(config_data_local)
-        self._verify_row_data(row_height=0,
+        self._verify_row_data(row=1,
                               config_check_data=config_data_local['add'])
 
         # Run test to copy/paste a row
         self._copy_paste_row(config_data_local)
 
         self._update_row(config_data_local)
-        self.page.click_tab("Messages")
+        self.page.click_tab("id-messages", rc_dock=True)
         self._verify_messsages("")
-        self.page.click_tab("Data Output")
+        self.page.click_tab("id-dataoutput", rc_dock=True)
         updated_row_data = {
             i: config_data_local['update'][i] if i in config_data_local[
                 'update'] else val
             for i, val in config_data_local['add'].items()
         }
-        self._verify_row_data(row_height=0,
+        self._verify_row_data(row=1,
                               config_check_data=updated_row_data)
 
         self.page.close_data_grid()
@@ -273,14 +261,12 @@ CREATE TABLE public.nonintpkey
                 QueryToolLocators.text_editor_ok_btn_css).click()
         else:
             # Boolean editor test for to True click
+            checkbox_el = self.page.find_by_css_selector(
+                QueryToolLocators.row_editor_checkbox_css)
             if data[1] == 'true':
-                checkbox_el = cell_el.find_element(
-                    By.XPATH, ".//*[contains(@class, 'multi-checkbox')]")
                 checkbox_el.click()
             # Boolean editor test for to False click
             elif data[1] == 'false':
-                checkbox_el = cell_el.find_element(
-                    By.XPATH, ".//*[contains(@class, 'multi-checkbox')]")
                 # Sets true
                 checkbox_el.click()
                 # Sets false
@@ -312,7 +298,7 @@ CREATE TABLE public.nonintpkey
         )
 
     def _copy_paste_row(self, config_data_l):
-        row0_cell0_xpath = CheckForViewDataTest._get_cell_xpath("r0", 1)
+        row0_cell0_xpath = CheckForViewDataTest._get_cell_xpath(1, 1)
 
         self.page.find_by_xpath(row0_cell0_xpath).click()
         self.page.find_by_css_selector(
@@ -321,14 +307,15 @@ CREATE TABLE public.nonintpkey
             QueryToolLocators.paste_button_css).click()
 
         # Update primary key of copied cell
-        self._add_update_save_row(config_data_l['copy'], row=2)
+        # Copy pasted rows go to first row
+        self._add_update_save_row(config_data_l['copy'], row=1)
 
         # Verify row 1 and row 2 data
         updated_row_data = {
             i: config_data_l['copy'][i] if i in config_data_l['copy'] else val
             for i, val in config_data_l['add'].items()
         }
-        self._verify_row_data(row_height=25,
+        self._verify_row_data(row=2,
                               config_check_data=updated_row_data)
 
     def _add_update_save_row(self, data, row=1):
@@ -337,9 +324,9 @@ CREATE TABLE public.nonintpkey
             items[item] = int(items[item])
         items.sort(reverse=False)
         for idx in items:
-            cell_xpath = CheckForViewDataTest._get_cell_xpath(
-                'r' + str(idx), row
-            )
+            # rowindex starts with 2 and 1st colindex is rownum
+            cell_xpath = CheckForViewDataTest\
+                ._get_cell_xpath(str(idx + 1), row + 1)
             time.sleep(0.2)
             self._update_cell(cell_xpath, data[str(idx)])
         self.page.find_by_css_selector(
@@ -351,6 +338,9 @@ CREATE TABLE public.nonintpkey
         time.sleep(2)
 
     def _add_row(self, config_data_l):
+        self.page.find_by_css_selector(
+            QueryToolLocators.btn_add_row).click()
+        time.sleep(1)
         self._add_update_save_row(config_data_l['add'], 1)
 
     def _update_row(self, config_data_l):
@@ -361,11 +351,13 @@ CREATE TABLE public.nonintpkey
             QueryToolLocators.query_messages_panel)
         self.assertEqual(text, messages_ele.text)
 
-    def _verify_row_data(self, row_height, config_check_data):
+    def _verify_row_data(self, row, config_check_data):
         self.page.click_execute_query_button()
+        self.driver.execute_script(
+            "document.querySelector('.rdg').scrollLeft=0"
+        )
 
-        xpath = "//*[contains(@class, 'ui-widget-content') and " \
-                "contains(@style, 'top:" + str(row_height) + "px')]"
+        xpath = QueryToolLocators.output_row_xpath.format(2)
         scroll_on_arg_for_js = "arguments[0].scrollIntoView(false)"
 
         self.page.wait_for_query_tool_loading_indicator_to_disappear()
@@ -379,9 +371,10 @@ CREATE TABLE public.nonintpkey
         for idx in actual_list:
             while retry > 0:
                 try:
-                    result_row = self.page.find_by_xpath(xpath)
-                    element = \
-                        result_row.find_element(By.CLASS_NAME, "r" + str(idx))
+                    element = self.page.find_by_xpath(
+                        QueryToolLocators.output_cell_xpath
+                        .format(row + 1, idx + 1)
+                    )
                     self.page.driver.execute_script(
                         scroll_on_arg_for_js, element)
                     break
@@ -399,6 +392,7 @@ CREATE TABLE public.nonintpkey
         list_item.sort(reverse=True)
         for idx in list_item:
             time.sleep(0.4)
-            element = result_row.find_element(By.CLASS_NAME, "r" + str(idx))
+            element = self.page.find_by_xpath(
+                QueryToolLocators.output_cell_xpath.format(2, idx + 1))
             self.page.driver.execute_script(
                 scroll_on_arg_for_js, 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 efe4a9a40..96bb00522 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
@@ -196,17 +196,12 @@ class CheckForXssFeatureTest(BaseFeatureTest):
         self.page.fill_codemirror_area_with(
             "select '<img src=\"x\" onerror=\"console.log(1)\">'"
         )
-        self.page.find_by_id("btn-flash").click()
-
-        result_row = self.page.find_by_xpath(
-            "//*[contains(@class, 'ui-widget-content') and "
-            "contains(@style, 'top:0px')]"
-        )
-
-        cells = result_row.find_elements(By.TAG_NAME, 'div')
+        self.page.find_by_css_selector(
+            QueryToolLocators.btn_execute_query_css).click()
 
-        # remove first element as it is row number.
-        source_code = cells[1].get_attribute('innerHTML')
+        source_code = self.page\
+            .find_by_xpath(QueryToolLocators.output_cell_xpath.format(2, 2))\
+            .get_attribute('innerHTML')
 
         self._check_escaped_characters(
             source_code,
@@ -225,13 +220,12 @@ class CheckForXssFeatureTest(BaseFeatureTest):
         self.page.find_by_css_selector(
             QueryToolLocators.btn_execute_query_css).click()
 
-        self.page.click_tab('Query History')
+        self.page.click_tab('id-history', rc_dock=True)
 
         # Check for history entry
-        history_ele = self.page.find_by_css_selector(
-            ".query-history div.query-group:first-child"
-            " .list-item.selected .query"
-        )
+        history_ele = self.page\
+            .find_by_css_selector(
+                QueryToolLocators.query_history_specific_entry.format(2))
 
         source_code = history_ele.get_attribute('innerHTML')
 
@@ -246,7 +240,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
             try:
                 history_ele = self.driver \
                     .find_element(By.CSS_SELECTOR,
-                                  ".query-detail .content-value")
+                                  QueryToolLocators.query_history_detail)
                 source_code = history_ele.get_attribute('innerHTML')
                 break
             except StaleElementReferenceException:
@@ -258,25 +252,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
             "Query tool (History Details-Message)"
         )
 
-        retry = 2
-        while retry > 0:
-            try:
-                # Check for history details error message
-                history_ele = self.page.find_by_css_selector(
-                    ".query-detail .history-error-text"
-                )
-                source_code = history_ele.get_attribute('innerHTML')
-                break
-            except StaleElementReferenceException:
-                retry -= 1
-
-        self._check_escaped_characters(
-            source_code,
-            self.check_xss_chars_set2,
-            "Query tool (History Details-Error)"
-        )
-
-        self.page.click_tab('Query Editor')
+        self.page.click_tab('id-query', rc_dock=True)
 
     def _check_xss_view_data(self):
         print(
@@ -284,13 +260,11 @@ class CheckForXssFeatureTest(BaseFeatureTest):
             file=sys.stderr, end=""
         )
 
-        self.page.find_by_css_selector(".slick-header-column")
-        cells = self.driver. \
-            find_elements(By.CSS_SELECTOR, ".slick-header-column")
-
         # remove first element as it is row number.
         # currently 4th col
-        source_code = cells[4].get_attribute('innerHTML')
+        source_code = self.page \
+            .find_by_xpath(QueryToolLocators.output_cell_xpath.format(1, 5)) \
+            .get_attribute('innerHTML')
 
         self._check_escaped_characters(
             source_code,
@@ -310,7 +284,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('Explain')
+        self.page.click_tab('id-explain', rc_dock=True)
 
         for idx in range(3):
             # Re-try logic
@@ -318,7 +292,7 @@ class CheckForXssFeatureTest(BaseFeatureTest):
                 ActionChains(self.driver).move_to_element(
                     self.driver.find_element(
                         By.CSS_SELECTOR,
-                        'div.pgadmin-explain-container > svg > g > g > image')
+                        'div#id-explain svg > g > g > image')
                 ).click().perform()
                 break
             except Exception:
@@ -333,8 +307,8 @@ class CheckForXssFeatureTest(BaseFeatureTest):
                     raise
 
         source_code = self.driver.find_element(
-            By.CSS_SELECTOR,
-            '.pgadmin-explain-details:not(.d-none)').get_attribute('innerHTML')
+            By.CSS_SELECTOR, QueryToolLocators.explain_details)\
+            .get_attribute('innerHTML')
 
         self._check_escaped_characters(
             source_code,
diff --git a/web/pgadmin/static/js/Explain/Graphical.jsx b/web/pgadmin/static/js/Explain/Graphical.jsx
index 0ce0c6068..c402e7245 100644
--- a/web/pgadmin/static/js/Explain/Graphical.jsx
+++ b/web/pgadmin/static/js/Explain/Graphical.jsx
@@ -411,7 +411,7 @@ export default function Graphical({planData, ctx}) {
         onNodeClick={onNodeClick}
       />
       {Boolean(explainPlanDetails) &&
-      <Card className={classes.explainDetails}>
+      <Card className={classes.explainDetails} data-label="explain-details">
         <CardHeader title={<Box display="flex">
           {explainPlanTitle}
           <Box marginLeft="auto">
diff --git a/web/pgadmin/static/js/components/Buttons.jsx b/web/pgadmin/static/js/components/Buttons.jsx
index ae20f1045..eeafc7739 100644
--- a/web/pgadmin/static/js/components/Buttons.jsx
+++ b/web/pgadmin/static/js/components/Buttons.jsx
@@ -94,8 +94,9 @@ export const PrimaryButton = forwardRef((props, ref)=>{
     allClassName.push(classes.xsButton);
   }
   noBorder && allClassName.push(classes.noBorder);
+  const dataLabel = typeof(children) == 'string' ? children : undefined;
   return (
-    <Button ref={ref} size={size} className={clsx(allClassName)} {...otherProps} variant="contained" color="primary" >{children}</Button>
+    <Button ref={ref} size={size} className={clsx(allClassName)} data-label={dataLabel} {...otherProps} variant="contained" color="primary">{children}</Button>
   );
 });
 PrimaryButton.displayName = 'PrimaryButton';
@@ -116,8 +117,9 @@ export const DefaultButton = forwardRef((props, ref)=>{
     allClassName.push(classes.xsButton);
   }
   noBorder && allClassName.push(classes.noBorder);
+  const dataLabel = typeof(children) == 'string' ? children : undefined;
   return (
-    <Button variant="outlined" color="default" ref={ref} size={size} className={clsx(allClassName)} {...otherProps} >{children}</Button>
+    <Button variant="outlined" color="default" ref={ref} size={size} className={clsx(allClassName)} data-label={dataLabel} {...otherProps}>{children}</Button>
   );
 });
 DefaultButton.displayName = 'DefaultButton';
@@ -144,7 +146,7 @@ export const PgIconButton = forwardRef(({icon, title, shortcut, className, split
       return (
         <PrimaryButton ref={ref} style={style}
           className={clsx(classes.iconButton, (splitButton ? classes.splitButton : ''), className)}
-          accessKey={accesskey} {...props}>
+          accessKey={accesskey} data-label={title || ''} {...props}>
           {icon}
         </PrimaryButton>
       );
@@ -152,7 +154,7 @@ export const PgIconButton = forwardRef(({icon, title, shortcut, className, split
       return (
         <DefaultButton ref={ref} style={style}
           className={clsx(classes.iconButton, classes.iconButtonDefault, (splitButton ? classes.splitButton : ''), className)}
-          accessKey={accesskey} {...props}>
+          accessKey={accesskey} data-label={title || ''} {...props}>
           {icon}
         </DefaultButton>
       );
@@ -163,7 +165,7 @@ export const PgIconButton = forwardRef(({icon, title, shortcut, className, split
         <Tooltip title={shortcutTitle || title || ''} aria-label={title || ''}>
           <PrimaryButton ref={ref} style={style}
             className={clsx(classes.iconButton, (splitButton ? classes.splitButton : ''), className)}
-            accessKey={accesskey} {...props}>
+            accessKey={accesskey} data-label={title || ''} {...props}>
             {icon}
           </PrimaryButton>
         </Tooltip>
@@ -173,7 +175,7 @@ export const PgIconButton = forwardRef(({icon, title, shortcut, className, split
         <Tooltip title={shortcutTitle || title || ''} aria-label={title || ''}>
           <DefaultButton ref={ref} style={style}
             className={clsx(classes.iconButton, classes.iconButtonDefault, (splitButton ? classes.splitButton : ''), className)}
-            accessKey={accesskey} {...props}>
+            accessKey={accesskey} data-label={title || ''} {...props}>
             {icon}
           </DefaultButton>
         </Tooltip>
diff --git a/web/pgadmin/static/js/components/ExternalIcon.jsx b/web/pgadmin/static/js/components/ExternalIcon.jsx
index b43f61317..0edd5eac3 100644
--- a/web/pgadmin/static/js/components/ExternalIcon.jsx
+++ b/web/pgadmin/static/js/components/ExternalIcon.jsx
@@ -24,47 +24,47 @@ ExternalIcon.propTypes = {
   Icon: PropTypes.elementType.isRequired,
 };
 
-export const QueryToolIcon = ({style})=><ExternalIcon Icon={QueryToolSvg} style={{height: '1rem', ...style}} />;
+export const QueryToolIcon = ({style})=><ExternalIcon Icon={QueryToolSvg} style={{height: '1rem', ...style}} data-label="QueryToolIcon" />;
 QueryToolIcon.propTypes = {style: PropTypes.object};
 
-export const ViewDataIcon = ({style})=><ExternalIcon Icon={ViewDataSvg} style={{height: '0.8rem', ...style}} />;
+export const ViewDataIcon = ({style})=><ExternalIcon Icon={ViewDataSvg} style={{height: '0.8rem', ...style}} data-label="ViewDataIcon" />;
 ViewDataIcon.propTypes = {style: PropTypes.object};
 
-export const SaveDataIcon = ({style})=><ExternalIcon Icon={SaveDataSvg} style={{height: '1rem', ...style}} />;
+export const SaveDataIcon = ({style})=><ExternalIcon Icon={SaveDataSvg} style={{height: '1rem', ...style}} data-label="SaveDataIcon" />;
 SaveDataIcon.propTypes = {style: PropTypes.object};
 
-export const PasteIcon = ({style})=><ExternalIcon Icon={PasteSvg} style={style} />;
+export const PasteIcon = ({style})=><ExternalIcon Icon={PasteSvg} style={style} data-label="PasteIcon" />;
 PasteIcon.propTypes = {style: PropTypes.object};
 
-export const FilterIcon = ({style})=><ExternalIcon Icon={FilterSvg} style={style} />;
+export const FilterIcon = ({style})=><ExternalIcon Icon={FilterSvg} style={style} data-label="FilterIcon" />;
 FilterIcon.propTypes = {style: PropTypes.object};
 
-export const CommitIcon = ({style})=><ExternalIcon Icon={CommitSvg} style={style} />;
+export const CommitIcon = ({style})=><ExternalIcon Icon={CommitSvg} style={{height: '1.2rem', ...style}} data-label="CommitIcon" />;
 CommitIcon.propTypes = {style: PropTypes.object};
 
-export const RollbackIcon = ({style})=><ExternalIcon Icon={RollbackSvg} style={style} />;
+export const RollbackIcon = ({style})=><ExternalIcon Icon={RollbackSvg} style={{height: '1.2rem', ...style}} data-label="RollbackIcon" />;
 RollbackIcon.propTypes = {style: PropTypes.object};
 
-export const ClearIcon = ({style})=><ExternalIcon Icon={ClearSvg} style={style} />;
+export const ClearIcon = ({style})=><ExternalIcon Icon={ClearSvg} style={style} data-label="ClearIcon" />;
 ClearIcon.propTypes = {style: PropTypes.object};
 
-export const ConnectedIcon = ({style})=><ExternalIcon Icon={ConnectedSvg} style={{height: '1rem', ...style}} />;
+export const ConnectedIcon = ({style})=><ExternalIcon Icon={ConnectedSvg} style={{height: '1rem', ...style}} data-label="ConnectedIcon" />;
 ConnectedIcon.propTypes = {style: PropTypes.object};
 
-export const DisonnectedIcon = ({style})=><ExternalIcon Icon={DisconnectedSvg} style={{height: '1rem', ...style}} />;
+export const DisonnectedIcon = ({style})=><ExternalIcon Icon={DisconnectedSvg} style={{height: '1rem', ...style}} data-label="DisonnectedIcon" />;
 DisonnectedIcon.propTypes = {style: PropTypes.object};
 
-export const RegexIcon = ({style})=><ExternalIcon Icon={RegexSvg} style={style} />;
+export const RegexIcon = ({style})=><ExternalIcon Icon={RegexSvg} style={style} data-label="RegexIcon" />;
 RegexIcon.propTypes = {style: PropTypes.object};
 
-export const FormatCaseIcon = ({style})=><ExternalIcon Icon={FormatCaseSvg} style={style} />;
+export const FormatCaseIcon = ({style})=><ExternalIcon Icon={FormatCaseSvg} style={style} data-label="FormatCaseIcon" />;
 FormatCaseIcon.propTypes = {style: PropTypes.object};
 
-export const ExpandDialogIcon = ({style})=><ExternalIcon Icon={Expand} style={{height: '1.2rem', ...style}}  />;QueryToolIcon.propTypes = {style: PropTypes.object};
+export const ExpandDialogIcon = ({style})=><ExternalIcon Icon={Expand} style={{height: '1.2rem', ...style}} data-label="ExpandDialogIcon" />;
 ExpandDialogIcon.propTypes = {style: PropTypes.object};
 
-export const MinimizeDialogIcon = ({style})=><ExternalIcon Icon={Collapse} style={{height: '1.4rem', ...style}} />;
+export const MinimizeDialogIcon = ({style})=><ExternalIcon Icon={Collapse} style={{height: '1.4rem', ...style}} data-label="MinimizeDialogIcon" />;
 MinimizeDialogIcon.propTypes = {style: PropTypes.object};
 
-export const AWSIcon = ({style})=><ExternalIcon Icon={AWS} style={{height: '1.4rem', ...style}} />;
+export const AWSIcon = ({style})=><ExternalIcon Icon={AWS} style={{height: '1.4rem', ...style}} data-label="AWSIcon" />;
 AWSIcon.propTypes = {style: PropTypes.object};
diff --git a/web/pgadmin/static/js/components/Loader.jsx b/web/pgadmin/static/js/components/Loader.jsx
index edb384e92..0232090be 100644
--- a/web/pgadmin/static/js/components/Loader.jsx
+++ b/web/pgadmin/static/js/components/Loader.jsx
@@ -40,13 +40,13 @@ const useStyles = makeStyles((theme)=>({
   }
 }));
 
-export default function Loader({message, style}) {
+export default function Loader({message, style, ...props}) {
   const classes = useStyles();
   if(!message) {
     return <></>;
   }
   return (
-    <Box className={classes.root} style={style}>
+    <Box className={classes.root} style={style} data-label="loader" {...props}>
       <Box className={classes.loaderRoot}>
         <CircularProgress className={classes.loader} />
         <Typography className={classes.message}>{message}</Typography>
diff --git a/web/pgadmin/static/js/components/Menu.jsx b/web/pgadmin/static/js/components/Menu.jsx
index 84f51f65c..585c5a9a2 100644
--- a/web/pgadmin/static/js/components/Menu.jsx
+++ b/web/pgadmin/static/js/components/Menu.jsx
@@ -24,6 +24,7 @@ const useStyles = makeStyles((theme)=>({
     },
     '& .szh-menu__divider': {
       margin: 0,
+      background: theme.otherVars.borderColor,
     }
   },
   menuItem: {
@@ -47,13 +48,17 @@ const useStyles = makeStyles((theme)=>({
   }
 }));
 
-export function PgMenu({open, className, ...props}) {
+export function PgMenu({open, className, label, ...props}) {
   const classes = useStyles();
+  const state = open ? 'open' : 'closed';
+  props.anchorRef?.current?.setAttribute('data-state', state);
   return (
     <ControlledMenu
-      state={open ? 'open' : 'closed'}
+      state={state}
       {...props}
       className={clsx(classes.menu, className)}
+      aria-label={label || 'Menu'}
+      data-state={state}
     />
   );
 }
@@ -61,6 +66,8 @@ export function PgMenu({open, className, ...props}) {
 PgMenu.propTypes = {
   open: PropTypes.bool,
   className: CustomPropTypes.className,
+  label: PropTypes.string,
+  anchorRef: CustomPropTypes.ref,
 };
 
 export const PgMenuItem = applyStatics(MenuItem)(({hasCheck=false, checked=false, accesskey, shortcut, children, ...props})=>{
@@ -72,7 +79,8 @@ export const PgMenuItem = applyStatics(MenuItem)(({hasCheck=false, checked=false
       props.onClick(e);
     };
   }
-  return <MenuItem {...props} onClick={onClick} className={classes.menuItem}>
+  const dataLabel = typeof(children) == 'string' ? children : undefined;
+  return <MenuItem {...props} onClick={onClick} className={classes.menuItem} data-label={dataLabel} data-checked={checked}>
     {hasCheck && <CheckIcon className={classes.checkIcon} style={checked ? {} : {visibility: 'hidden'}} />}
     {children}
     {(shortcut || accesskey) && <div className={classes.shortcut}>({shortcutToString(shortcut, accesskey)})</div>}
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx
index 8c7ecedaf..b6204724c 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolComponent.jsx
@@ -53,18 +53,23 @@ function initConnection(api, params, passdata) {
 }
 
 function setPanelTitle(panel, title, qtState, dirty=false) {
-  if(title) {
-    title =title.split('\\').pop().split('/').pop();
-  } else if(qtState.current_file) {
+  if(qtState.current_file) {
     title = qtState.current_file.split('\\').pop().split('/').pop();
-  } else {
-    title = qtState.params.title || 'Untitled';
+  } else if (!qtState.is_new_tab) {
+    if(!title) {
+      title = panel.$titleText?.[0].textContent;
+      if(panel.is_dirty_editor) {
+        // remove asterisk
+        title = title.slice(0, -1);
+      }
+    }
   }
 
   title = title + (dirty ? '*': '');
   if (qtState.is_new_tab) {
     window.document.title = title;
   } else {
+    panel.is_dirty_editor = dirty;
     setQueryToolDockerTitle(panel, true, title, qtState.current_file ? true : false);
   }
 }
@@ -109,6 +114,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
   const setQtState = (state)=>{
     _setQtState((prev)=>({...prev,...evalFunc(null, state, prev)}));
   };
+  const isDirtyRef = useRef(false); // usefull when conn change.
   const eventBus = useRef(eventBusObj || (new EventBus()));
   const docker = useRef(null);
   const api = useMemo(()=>getApiInstance(), []);
@@ -411,6 +417,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
       [QUERY_TOOL_EVENTS.LOAD_FILE_DONE, fileDone],
       [QUERY_TOOL_EVENTS.SAVE_FILE_DONE, fileDone],
       [QUERY_TOOL_EVENTS.QUERY_CHANGED, (isDirty)=>{
+        isDirtyRef.current = isDirty;
         if(qtState.params.is_query_tool) {
           setPanelTitle(panel, null, qtState, isDirty);
         }
@@ -511,6 +518,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
               obtaining_conn: false,
             };
           });
+          setPanelTitle(panel, connectionData.title, qtState, isDirtyRef.current);
           let msg = `${connectionData['server_name']}/${connectionData['database_name']} - Database connected`;
           Notifier.success(msg);
           resolve();
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/Editors.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/Editors.jsx
index a37a98c63..6839cf65b 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/Editors.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/Editors.jsx
@@ -186,7 +186,7 @@ export function TextEditor({row, column, onRowChange, onClose}) {
     <Portal container={document.body}>
       <Box ref={(ele)=>{
         setEditorPosition(getCellElement(column.idx), ele);
-      }} className={classes.textEditor}>
+      }} className={classes.textEditor} data-label="pg-editor">
         <textarea ref={autoFocusAndSelect} className={classes.textarea} value={localVal} onChange={onChange} />
         <Box display="flex" justifyContent="flex-end">
           <DefaultButton startIcon={<CloseIcon />} onClick={()=>onClose(false)} size="small">
@@ -287,7 +287,7 @@ export function CheckboxEditor({row, column, onRowChange, onClose}) {
     className = 'intermediate';
   }
   return (
-    <div onClick={changeValue} tabIndex="0" onBlur={onBlur}>
+    <div onClick={changeValue} tabIndex="0" onBlur={onBlur} data-label="pg-checkbox-editor">
       <span className={clsx(classes.check, className)}></span>
     </div>
   );
@@ -334,7 +334,7 @@ export function JsonTextEditor({row, column, onRowChange, onClose}) {
     <Portal container={document.body}>
       <Box ref={(ele)=>{
         setEditorPosition(getCellElement(column.idx), ele);
-      }} className={classes.jsonEditor}>
+      }} className={classes.jsonEditor} data-label="pg-editor">
         <JsonEditor
           value={localVal}
           options={{
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx
index 339b5c3a5..98667e1d7 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/QueryToolDataGrid/index.jsx
@@ -8,7 +8,7 @@
 //////////////////////////////////////////////////////////////
 import { Box, makeStyles } from '@material-ui/core';
 import _ from 'lodash';
-import React, {useState, useEffect, useContext, useRef} from 'react';
+import React, {useState, useEffect, useContext, useRef, useLayoutEffect} from 'react';
 import ReactDataGrid, {Row, useRowSelection} from 'react-data-grid';
 import LockIcon from '@material-ui/icons/Lock';
 import EditIcon from '@material-ui/icons/Edit';
@@ -130,23 +130,42 @@ CustomRow.propTypes = {
   viewportColumns: PropTypes.array,
 };
 
-function SelectAllHeaderRenderer(props) {
+function getCopyShortcutHandler(handleCopy) {
+  return (e)=>{
+    if((e.ctrlKey || e.metaKey) && e.key !== 'Control' && e.keyCode == 67) {
+      handleCopy();
+    }
+  };
+}
+
+function SelectAllHeaderRenderer({onAllRowsSelectionChange, isCellSelected}) {
   const [checked, setChecked] = useState(false);
+  const cellRef = useRef();
   const eventBus = useContext(QueryToolEventsContext);
+  const dataGridExtras = useContext(DataGridExtrasContext);
   const onClick = ()=>{
     eventBus.fireEvent(QUERY_TOOL_EVENTS.FETCH_MORE_ROWS, true, ()=>{
       setChecked(!checked);
-      props.onAllRowsSelectionChange(!checked);
+      onAllRowsSelectionChange(!checked);
     });
   };
-  return <div style={{widht: '100%', height: '100%'}} onClick={onClick}></div>;
+
+  useLayoutEffect(() => {
+    if (!isCellSelected) return;
+    cellRef.current?.focus({ preventScroll: true });
+  }, [isCellSelected]);
+
+  return <div ref={cellRef} style={{width: '100%', height: '100%'}} onClick={onClick}
+    tabIndex="0" onKeyDown={getCopyShortcutHandler(dataGridExtras.handleCopy)}></div>;
 }
 SelectAllHeaderRenderer.propTypes = {
   onAllRowsSelectionChange: PropTypes.func,
+  isCellSelected: PropTypes.bool,
 };
 
 function SelectableHeaderRenderer({column, selectedColumns, onSelectedColumnsChange, isCellSelected}) {
   const classes = useStyles();
+  const cellRef = useRef();
   const eventBus = useContext(QueryToolEventsContext);
   const dataGridExtras = useContext(DataGridExtrasContext);
 
@@ -168,11 +187,17 @@ function SelectableHeaderRenderer({column, selectedColumns, onSelectedColumnsCha
 
   const isSelected = selectedColumns.has(column.idx);
 
+  useLayoutEffect(() => {
+    if (!isCellSelected) return;
+    cellRef.current?.focus({ preventScroll: true });
+  }, [isCellSelected]);
+
   return (
-    <Box className={clsx(classes.columnHeader, isSelected ? classes.colHeaderSelected : null)} onClick={onClick}>
+    <Box ref={cellRef} className={clsx(classes.columnHeader, isSelected ? classes.colHeaderSelected : null)} onClick={onClick} tabIndex="0"
+      onKeyDown={getCopyShortcutHandler(dataGridExtras.handleCopy)} data-column-key={column.key}>
       {(column.column_type_internal == 'geometry' || column.column_type_internal == 'geography') &&
       <Box>
-        <PgIconButton title={gettext('View all geometries in this column')} icon={<MapIcon />} size="small" style={{marginRight: '0.25rem'}} onClick={(e)=>{
+        <PgIconButton title={gettext('View all geometries in this column')} icon={<MapIcon data-label="MapIcon"/>} size="small" style={{marginRight: '0.25rem'}} onClick={(e)=>{
           e.stopPropagation();
           eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_RENDER_GEOMETRIES, column);
         }}/>
@@ -182,8 +207,8 @@ function SelectableHeaderRenderer({column, selectedColumns, onSelectedColumnsCha
         <span>{column.display_type}</span>
       </Box>
       <Box marginLeft="4px">{column.can_edit ?
-        <EditIcon fontSize="small" style={{fontSize: '0.875rem'}} />:
-        <LockIcon fontSize="small" style={{fontSize: '0.875rem'}} />
+        <EditIcon fontSize="small" style={{fontSize: '0.875rem'}} data-label="EditIcon"/>:
+        <LockIcon fontSize="small" style={{fontSize: '0.875rem'}} data-label="LockIcon"/>
       }</Box>
     </Box>
   );
@@ -372,7 +397,7 @@ export default function QueryToolDataGrid({columns, rows, totalRowCount, dataCha
   }
 
   return (
-    <DataGridExtrasContext.Provider value={{onSelectedCellChange}}>
+    <DataGridExtrasContext.Provider value={{onSelectedCellChange, handleCopy}}>
       <ReactDataGrid
         id="datagrid"
         columns={readyColumns}
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx
index f29eed95c..bf487a2cc 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/MainToolBar.jsx
@@ -537,6 +537,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
         anchorRef={saveAsMenuRef}
         open={openMenuName=='menu-saveas'}
         onClose={onMenuClose}
+        label={gettext('File Menu')}
       >
         <PgMenuItem onClick={()=>{saveFile(true);}}>{gettext('Save as')}</PgMenuItem>
       </PgMenu>
@@ -544,6 +545,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
         anchorRef={editMenuRef}
         open={openMenuName=='menu-edit'}
         onClose={onMenuClose}
+        label={gettext('Edit Menu')}
       >
         <PgMenuItem shortcut={FIXED_PREF.find}
           onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_FIND_REPLACE, false);}}>{gettext('Find')}</PgMenuItem>
@@ -567,6 +569,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
         anchorRef={filterMenuRef}
         open={openMenuName=='menu-filter'}
         onClose={onMenuClose}
+        label={gettext('Filter Options Menu')}
       >
         <PgMenuItem onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_INCLUDE_EXCLUDE_FILTER, true);}}>{gettext('Filter by Selection')}</PgMenuItem>
         <PgMenuItem onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_INCLUDE_EXCLUDE_FILTER, false);}}>{gettext('Exclude by Selection')}</PgMenuItem>
@@ -576,6 +579,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
         anchorRef={autoCommitMenuRef}
         open={openMenuName=='menu-autocommit'}
         onClose={onMenuClose}
+        label={gettext('Execute Options Menu')}
       >
         <PgMenuItem hasCheck value="auto_commit" checked={checkedMenuItems['auto_commit']}
           onClick={checkMenuClick}>{gettext('Auto commit?')}</PgMenuItem>
@@ -586,6 +590,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
         anchorRef={explainMenuRef}
         open={openMenuName=='menu-explain'}
         onClose={onMenuClose}
+        label={gettext('Explain Options Menu')}
       >
         <PgMenuItem hasCheck value="explain_verbose" checked={checkedMenuItems['explain_verbose']}
           onClick={checkMenuClick}>{gettext('Verbose')}</PgMenuItem>
@@ -604,6 +609,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
         anchorRef={macrosMenuRef}
         open={openMenuName=='menu-macros'}
         onClose={onMenuClose}
+        label={gettext('Macros Menu')}
       >
         <PgMenuItem onClick={onManageMacros}>{gettext('Manage macros')}</PgMenuItem>
         <PgMenuDivider />
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/Notifications.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/Notifications.jsx
index ea6a1607d..b56a5399f 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/sections/Notifications.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/Notifications.jsx
@@ -47,10 +47,10 @@ export function Notifications() {
     <tbody>
       {notices.map((notice, i)=>{
         return <tr key={i}>
-          <td>{notice.recorded_time}</td>
-          <td>{notice.channel}</td>
-          <td>{notice.pid}</td>
-          <td>{notice.payload}</td>
+          <td data-label="recorded_time">{notice.recorded_time}</td>
+          <td data-label="channel">{notice.channel}</td>
+          <td data-label="pid">{notice.pid}</td>
+          <td data-label="payload">{notice.payload}</td>
         </tr>;
       })}
     </tbody>
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/QueryHistory.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/QueryHistory.jsx
index 2f2246a85..efdd1959c 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/sections/QueryHistory.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/QueryHistory.jsx
@@ -239,11 +239,11 @@ class QueryHistoryUtils {
 function QuerySourceIcon({source}) {
   switch(JSON.stringify(source)) {
   case JSON.stringify(QuerySources.EXECUTE):
-    return <PlayArrowRoundedIcon style={{marginLeft: '-4px'}}/>;
+    return <PlayArrowRoundedIcon style={{marginLeft: '-4px'}} data-label="ExecuteIcon" />;
   case JSON.stringify(QuerySources.EXPLAIN):
-    return <ExplicitRoundedIcon/>;
+    return <ExplicitRoundedIcon data-label="ExplainIcon" />;
   case JSON.stringify(QuerySources.EXPLAIN_ANALYZE):
-    return <AssessmentRoundedIcon/>;
+    return <AssessmentRoundedIcon data-label="ExplainAnalyzeIcon" />;
   case JSON.stringify(QuerySources.COMMIT):
     return <CommitIcon style={{marginLeft: '-4px'}}/>;
   case JSON.stringify(QuerySources.ROLLBACK):
@@ -262,7 +262,7 @@ QuerySourceIcon.propTypes = {
 
 function HistoryEntry({entry, formatEntryDate, itemKey, selectedItemKey, onClick}) {
   const classes = useStyles();
-  return <ListItem tabIndex="0" ref={(ele)=>{
+  return <ListItem tabIndex="0" data-label="history-entry" data-pgadmin={entry.is_pgadmin_query} ref={(ele)=>{
     selectedItemKey==itemKey && ele && ele.scrollIntoView({
       block: 'center',
       behavior: 'smooth',
@@ -324,7 +324,7 @@ function QueryHistoryDetails({entry}) {
   return (
     <>
       {entry.info && <Box className={classes.infoHeader}>{entry.info}</Box>}
-      <Box padding="0.5rem">
+      <Box padding="0.5rem" data-label="history-detail">
         <Grid container>
           <Grid item sm={4}>{entry.start_time.toLocaleDateString() + ' ' + entry.start_time.toLocaleTimeString()}</Grid>
           <Grid item sm={4}>{entry?.row_affected > 0 && entry.row_affected}</Grid>
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx
index 95982ba8f..095a0b7ab 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx
@@ -1225,7 +1225,7 @@ export function ResultSet() {
   return (
     <Box className={classes.root} ref={containerRef} tabIndex="0">
       <Loader message={loaderText} />
-      <Loader message={isLoadingMore ? gettext('Loading more rows...') : null} style={{top: 'unset', right: 'unset', padding: '0.5rem 1rem'}}/>
+      <Loader data-label="loader-more-rows" message={isLoadingMore ? gettext('Loading more rows...') : null} style={{top: 'unset', right: 'unset', padding: '0.5rem 1rem'}}/>
       {!queryData &&
         <EmptyPanelMessage text={gettext('No data output. Execute a query to get output.')}/>
       }
diff --git a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSetToolbar.jsx b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSetToolbar.jsx
index bdab9e7d8..e525776fe 100644
--- a/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSetToolbar.jsx
+++ b/web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSetToolbar.jsx
@@ -163,6 +163,7 @@ export function ResultSetToolbar({containerRef, canEdit, totalRowCount}) {
         anchorRef={copyMenuRef}
         open={menuOpenId=='menu-copyheader'}
         onClose={handleMenuClose}
+        label={gettext('Copy Options Menu')}
       >
         <PgMenuItem hasCheck value="copy_with_headers" checked={checkedMenuItems['copy_with_headers']} onClick={checkMenuClick}>{gettext('Copy with headers')}</PgMenuItem>
       </PgMenu>
diff --git a/web/regression/feature_utils/locators.py b/web/regression/feature_utils/locators.py
index 23ccd0ee9..4ae72b84a 100644
--- a/web/regression/feature_utils/locators.py
+++ b/web/regression/feature_utils/locators.py
@@ -108,105 +108,127 @@ class NavMenuLocators:
         "//*[contains(@class,'wcTabTop')]//*[contains(@class,'wcPanelTab') " \
         "and contains(.,'{}')]"
 
+    rcdock_tab = "div.dock-tab-btn[id$='{0}']"
+
     process_watcher_error_close_xpath = \
         ".btn.btn-sm-sq.btn-primary.pg-bg-close > i"
 
 
 class QueryToolLocators:
-    btn_save_file = "#btn-save-file"
+    btn_save_file = "button[data-label='Save File']"
 
-    btn_save_data = "#btn-save-data"
+    btn_save_data = "button[data-label='Save Data Changes']"
 
-    btn_query_dropdown = "#btn-query-dropdown"
+    btn_query_dropdown = "button[data-label='Execute options']"
 
-    btn_auto_rollback = "#btn-auto-rollback"
+    btn_auto_rollback = "li[data-label='Auto rollback on error?']"
 
     btn_auto_rollback_check_status = "#btn-auto-rollback > i"
 
-    btn_auto_commit = "#btn-auto-commit"
+    btn_auto_commit = "li[data-label='Auto commit?']"
 
     btn_auto_commit_check_status = "#btn-auto-commit > i"
 
-    btn_cancel_query = "#btn-cancel-query"
+    btn_cancel_query = "button[data-label='Cancel query']"
 
-    btn_explain = "#btn-explain"
+    btn_explain = "button[data-label='Explain']"
 
-    btn_explain_analyze = "#btn-explain-analyze"
+    btn_explain_analyze = "button[data-label='Explain Analyze']"
 
-    btn_explain_options_dropdown = "#btn-explain-options-dropdown"
+    btn_explain_options_dropdown = "button[data-label='Explain Settings']"
 
-    btn_explain_verbose = "#btn-explain-verbose"
+    btn_explain_verbose = "li[data-label='Verbose']"
 
-    btn_explain_costs = "#btn-explain-costs"
+    btn_explain_costs = "li[data-label='Costs']"
 
-    btn_explain_buffers = "#btn-explain-buffers"
+    btn_explain_buffers = "li[data-label='Buffers']"
 
-    btn_explain_timing = "#btn-explain-timing"
+    btn_explain_timing = "li[data-label='Timing']"
 
-    btn_clear_dropdown = "#btn-clear-dropdown"
+    btn_edit_dropdown = "button[data-label='Edit']"
 
     btn_clear_history = "#btn-clear-history"
 
-    btn_clear = "#btn-clear"
+    btn_clear = "li[data-label='Clear Query']"
+
+    btn_add_row = "button[data-label='Add row']"
 
-    query_editor_panel = "#output-panel"
+    query_tool_menu = "ul[aria-label='{0}']"
 
-    query_history_selected = "#query_list .selected"
+    query_editor_panel = "#id-query"
 
-    query_history_entries = "#query_list>.query-group>ul>li"
+    query_history_selected = \
+        "#id-history li[data-label='history-entry'].Mui-selected"
+
+    query_history_entries = "#id-history li[data-label='history-entry']"
 
     query_history_specific_entry = \
-        "#query_list>.query-group>ul>li:nth-child({})"
+        "#id-history li[data-label='history-entry']:nth-child({0})"
+
+    query_history_detail = "#id-history div[data-label='history-detail']"
 
-    query_history_detail = "#query_detail"
+    query_history_selected_icon = query_history_selected + ' svg'
 
-    invalid_query_history_entry_css = "#query_list .entry.error .query"
+    invalid_query_history_entry_css = \
+        "#id-history li[data-label='history-entry'][class*='itemError']"
+
+    explain_details = "#id-explain div[data-label='explain-details']"
 
     editor_panel = "#output-panel"
 
-    query_messages_panel = ".sql-editor-message"
+    query_messages_panel = "#id-messages"
+
+    output_row = "#id-dataoutput div.rdg-row[aria-rowindex={0}]"
 
-    output_row_xpath = "//div[contains(@class, 'slick-row')][{}]/*[1]"
+    output_row_col = "#id-dataoutput div.rdg-row[aria-rowindex='{0}']" \
+                     " div.rdg-cell[aria-colindex='{1}']"
 
-    output_column_header_css = "[data-column-id='{}']"
+    output_column_header_css = \
+        "#id-dataoutput div.rdg-cell div[data-column-key='{0}']"
 
-    output_column_data_xpath = "//div[contains(@class, 'slick-cell')]" \
+    output_column_data_xpath = "//div[contains(@class, 'rdg-cell')]" \
                                "[contains(., '{}')]"
-    output_cell_xpath = "//div[contains(@class, 'slick-cell') and " \
-                        "contains(@class, 'l{0} r{1}')]"
+    output_row_xpath = "//div[@aria-rowindex='{0}']"
+    output_cell_xpath = "//div[@aria-rowindex='{0}']/div[@aria-colindex='{1}']"
 
     select_all_column = \
-        "//div[contains(@id,'row-header-column')]"
+        "//div[@role='columnheader'][@aria-colindex='1']"
 
     new_row_xpath = "//div[contains(@class, 'new-row')]"
 
-    scratch_pad_css = ".sql-scratch > textarea"
+    scratch_pad_css = "#id-scratch textarea"
+
+    copy_button_css = "#id-dataoutput button[data-label='Copy']"
 
-    copy_button_css = "#btn-copy-row"
+    copy_options_css = "#id-dataoutput button[data-label='Copy options']"
 
-    paste_button_css = "#btn-paste-row"
+    copy_headers_btn_css = "li[data-label='Copy with headers']"
 
-    row_editor_text_area_css = ".pg-text-editor > textarea"
+    paste_button_css = "#id-dataoutput button[data-label='Paste']"
+
+    row_editor_text_area_css = "div[data-label='pg-editor'] textarea"
 
     json_editor_text_area_css = \
         "div.ace_layer.ace_text-layer .ace_line_group .ace_line"
 
-    text_editor_ok_btn_css = ".btn.btn-primary.long_text_editor"
+    row_editor_checkbox_css = "div[data-label='pg-checkbox-editor']"
+
+    text_editor_ok_btn_css = \
+        "div[data-label='pg-editor'] button[data-label='OK']"
 
-    btn_load_file_css = "#btn-load-file"
+    btn_load_file_css = "button[data-label='Open File']"
 
-    btn_execute_query_css = "#btn-flash"
+    btn_execute_query_css = "button[data-label='Execute/Refresh']"
 
     input_file_path_css = "input#file-input-path"
 
     select_file_content_css = "table#contents"
 
-    query_output_canvas_css = "#datagrid .slick-viewport .grid-canvas"
+    query_output_canvas_css = "#id-dataoutput .rdg"
 
-    query_output_cells = ".slick-cell"
+    query_output_cells = ".rdg-cell[role='gridcell']"
 
-    sql_editor_message = "//div[contains(@class, 'sql-editor-message') and " \
-                         "contains(string(), '{}')]"
+    sql_editor_message = "//div[@id='id-messages'][contains(string(), '{}')]"
 
     code_mirror_hint_box_xpath = "//ul[@class='CodeMirror-hints default']"
 
@@ -215,32 +237,19 @@ class QueryToolLocators:
 
     code_mirror_data_xpath = "//pre[@class=' CodeMirror-line ']/span"
 
-    save_data_icon = "icon-save-data-changes"
-
-    commit_icon = "icon-commit"
-
-    execute_icon = "fa-play"
-
-    explain_icon = "fa-hand-pointer"
-
-    explain_analyze_icon = "fa-list-alt"
-
-    query_history_selected_icon = '#query_list .selected #query_source_icon'
+    btn_commit = "button[data-label='Commit']"
 
-    btn_commit = "#btn-commit"
+    btn_history_remove_all = "#id-history button[data-label='Remove All']"
 
     show_query_internally_btn = \
-        "//div[label[contains(normalize-space(text())," \
-        "'Show queries generated internally by')]]//" \
-        "div[contains(@class,'toggle btn')]"
+        "//div[contains(normalize-space(text())," \
+        "'Show queries generated internally by')]/span/span[1]"
 
-    editable_column_icon_xpath = "//div[contains(@class," \
-                                 " 'editable-column-header-icon')]" \
-                                 "/i[contains(@class, 'fa-pencil-alt')]"
+    editable_column_icon_xpath = \
+        "//div[@role='columnheader']/div/div/*[@data-label='EditIcon']"
 
-    read_only_column_icon_xpath = "//div[contains(@class," \
-                                  " 'editable-column-header-icon')]" \
-                                  "/i[contains(@class, 'fa-lock')]"
+    read_only_column_icon_xpath = \
+        "//div[@role='columnheader']/div/div/*[@data-label='LockIcon']"
 
 
 class ConnectToServerDiv:
diff --git a/web/regression/feature_utils/pgadmin_page.py b/web/regression/feature_utils/pgadmin_page.py
index f99b1aeb5..d9d53c446 100644
--- a/web/regression/feature_utils/pgadmin_page.py
+++ b/web/regression/feature_utils/pgadmin_page.py
@@ -87,9 +87,9 @@ class PgadminPage:
 
         # In case of react dialog we use different xpath
         if react_dialog:
-            modal_button = self.find_by_xpath(
-                "//button[contains(@class,'MuiButtonBase-root')]"
-                "//span[text()='%s']" % button_text)
+            modal_button = self.find_by_css_selector(
+                ".react-draggable button[data-label='{0}']"
+                .format(button_text))
         else:
             modal_button = self.find_by_xpath(
                 "//div[contains(@class, 'alertify') and "
@@ -203,9 +203,7 @@ class PgadminPage:
             self.driver.switch_to.frame(
                 self.driver.find_elements(By.TAG_NAME, "iframe")[0])
             time.sleep(.5)
-            self.click_element(self.find_by_xpath(
-                '//button[contains(@class, "ajs-button") and '
-                'contains(.,"Don\'t save")]'))
+            self.find_by_css_selector("button[data-test='dont-save']").click()
 
             if self.check_if_element_exist_by_xpath(
                     "//button[text()='Rollback']", 1):
@@ -214,15 +212,22 @@ class PgadminPage:
         self.driver.switch_to.default_content()
 
     def clear_query_tool(self):
-        self.click_element(
-            self.find_by_css_selector(QueryToolLocators.btn_clear_dropdown)
-        )
+        retry = 3
+        edit_options = self.find_by_css_selector(
+            QueryToolLocators.btn_edit_dropdown)
+        while retry > 0:
+            self.click_element(edit_options)
+            time.sleep(0.3)
+            if edit_options.get_attribute("data-state") == "open":
+                break
+            else:
+                retry -= 1
+
         ActionChains(self.driver).move_to_element(
             self.find_by_css_selector(QueryToolLocators.btn_clear)).perform()
         self.click_element(
             self.find_by_css_selector(QueryToolLocators.btn_clear)
         )
-        self.driver.switch_to.default_content()
         self.click_modal('Yes', True)
 
     def execute_query(self, query):
@@ -230,90 +235,76 @@ class PgadminPage:
         self.click_execute_query_button()
 
     def click_execute_query_button(self, timeout=20):
-        retry = 5
         execute_button = self.find_by_css_selector(
             QueryToolLocators.btn_execute_query_css)
-        first_click = execute_button.get_attribute('data-click-counter')
-        while retry > 0:
-            execute_button.click()
-            execute_button = self.find_by_css_selector(
-                QueryToolLocators.btn_execute_query_css)
-            second_click = execute_button.get_attribute(
-                'data-click-counter')
-            if first_click != second_click:
-                self.wait_for_query_tool_loading_indicator_to_appear()
-                break
-            else:
-                retry -= 1
+        execute_button.click()
         self.wait_for_query_tool_loading_indicator_to_disappear(timeout)
 
     def check_execute_option(self, option):
         """"This function will check auto commit or auto roll back based on
         user input. If button is already checked, no action will be taken"""
-        query_options = self.driver.find_element(
-            By.CSS_SELECTOR, QueryToolLocators.btn_query_dropdown)
-        expanded = query_options.get_attribute("aria-expanded")
-        if expanded == "false":
-            query_options.click()
-
-        def update_execute_option_setting(
-                css_selector_of_option_status, css_selector_of_option,):
+        menu_btn = self.driver.find_element_by_css_selector(
+            QueryToolLocators.btn_query_dropdown)
+        if menu_btn.get_attribute('data-state') == "closed":
+            menu_btn.click()
+
+        def update_execute_option_setting(css_selector_of_option):
             retry = 3
-            check_status = self.driver.find_element(
-                By.CSS_SELECTOR, css_selector_of_option_status)
-            if 'visibility-hidden' in check_status.get_attribute('class'):
+            menu_option = self.driver.find_element_by_css_selector(
+                css_selector_of_option)
+            if menu_option.get_attribute('data-checked') == 'false':
                 while retry > 0:
-                    self.find_by_css_selector(css_selector_of_option).click()
+                    menu_option.click()
                     time.sleep(0.2)
-                    if 'visibility-hidden' not in \
-                            check_status.get_attribute('class'):
+                    if menu_option.get_attribute('data-checked') == 'true':
                         break
                     else:
                         retry -= 1
 
         if option == 'auto_commit':
             update_execute_option_setting(
-                QueryToolLocators.btn_auto_commit_check_status,
                 QueryToolLocators.btn_auto_commit)
         if option == 'auto_rollback':
             update_execute_option_setting(
-                QueryToolLocators.btn_auto_rollback_check_status,
                 QueryToolLocators.btn_auto_rollback)
 
+        if menu_btn.get_attribute('data-state') == "open":
+            menu_btn.click()
+
     def uncheck_execute_option(self, option):
         """"This function will uncheck auto commit or auto roll back based on
         user input. If button is already unchecked, no action will be taken"""
-        query_options = self.driver.find_element_by_css_selector(
-            QueryToolLocators.btn_query_dropdown)
-        expanded = query_options.get_attribute("aria-expanded")
-        if expanded == "false":
-            query_options.click()
+        menu = self.driver.find_element_by_css_selector(
+            QueryToolLocators.query_tool_menu.format('Execute Options Menu'))
 
-        def update_execute_option_setting(
-                css_selector_of_option_status, css_selector_of_option):
+        if menu.get_attribute('data-state') == "closed":
+            self.driver.find_element_by_css_selector(
+                QueryToolLocators.btn_query_dropdown).click()
+
+        def update_execute_option_setting(css_selector_of_option):
             retry = 3
-            check_status = self.driver.find_element_by_css_selector(
-                css_selector_of_option_status)
-            if 'visibility-hidden' not in check_status.get_attribute('class'):
+            menu_option = self.driver.find_element_by_css_selector(
+                css_selector_of_option)
+            if menu_option.get_attribute('data-checked') == 'true':
                 while retry > 0:
-                    self.find_by_css_selector(
-                        css_selector_of_option).click()
+                    menu_option.click()
                     time.sleep(0.2)
-                    if 'visibility-hidden' in \
-                            check_status.get_attribute('class'):
+                    if menu_option.get_attribute('data-checked') == 'false':
                         break
                     else:
                         retry -= 1
 
         if option == 'auto_commit':
             update_execute_option_setting(
-                QueryToolLocators.btn_auto_commit_check_status,
                 QueryToolLocators.btn_auto_commit)
         if option == 'auto_rollback':
             update_execute_option_setting(
-                QueryToolLocators.btn_auto_rollback_check_status,
                 QueryToolLocators.btn_auto_rollback)
 
+        if menu.get_attribute('data-state') == "open":
+            self.driver.find_element_by_css_selector(
+                QueryToolLocators.btn_query_dropdown).click()
+
     def close_data_grid(self):
         self.driver.switch_to.default_content()
         xpath = "//*[@id='dockerContainer']/div/div[3]/div/div[2]/div[1]"
@@ -331,6 +322,7 @@ class PgadminPage:
             self.click_element(object_menu_item)
             delete_menu_item = self.find_by_partial_link_text("Remove Server")
             self.click_element(delete_menu_item)
+            self.driver.switch_to.default_content()
             self.click_modal('Yes', True)
             time.sleep(1)
         else:
@@ -1054,15 +1046,15 @@ class PgadminPage:
                 driver.switch_to.default_content()
                 driver.switch_to.frame(
                     driver.find_element_by_tag_name("iframe"))
-                element = driver.find_element_by_css_selector(
-                    "#output-panel .CodeMirror")
+                element = driver.find_element(
+                    By.CSS_SELECTOR, "#sqleditor-container .CodeMirror")
                 if element.is_displayed() and element.is_enabled():
                     return element
             except (NoSuchElementException, WebDriverException):
                 return False
 
         time.sleep(1)
-        self.wait_for_query_tool_loading_indicator_to_disappear(12)
+        # self.wait_for_query_tool_loading_indicator_to_disappear(12)
 
         retry = 2
         while retry > 0:
@@ -1071,7 +1063,9 @@ class PgadminPage:
                 WebDriverWait(self.driver, 10).until(
                     EC.frame_to_be_available_and_switch_to_it(
                         (By.TAG_NAME, "iframe")))
-                self.find_by_xpath("//a[text()='Query Editor']").click()
+                self.find_by_css_selector(
+                    "div.dock-tab-btn[id$=\"id-query\"]").click()
+                # self.find_by_xpath("//div[text()='Query Editor']").click()
 
                 codemirror_ele = WebDriverWait(
                     self.driver, timeout=self.timeout, poll_frequency=0.01) \
@@ -1099,11 +1093,16 @@ class PgadminPage:
                 "arguments[0].CodeMirror.lineCount(),0);",
                 codemirror_ele, field_content)
 
-    def click_tab(self, tab_name):
+    def click_tab(self, tab_name, rc_dock=False):
+        if rc_dock:
+            tab = self.find_by_css_selector(
+                NavMenuLocators.rcdock_tab.format(tab_name))
+            self.click_element(tab)
+            return
+
         WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable(
             (By.XPATH, NavMenuLocators.select_tab_xpath.format(tab_name))))
-        click_tab = True
-        while click_tab:
+        while True:
             tab = self.find_by_xpath(
                 NavMenuLocators.select_tab_xpath.format(tab_name))
             self.click_element(tab)
@@ -1188,15 +1187,16 @@ class PgadminPage:
 
         self._wait_for("spinner to disappear", spinner_has_disappeared, 20)
 
-    def wait_for_query_tool_loading_indicator_to_disappear(self, timeout=20):
+    def wait_for_query_tool_loading_indicator_to_disappear(
+            self, timeout=20, container_id="id-dataoutput"):
         def spinner_has_disappeared(driver):
             try:
                 # Refer the status message as spinner appears only on the
                 # the data output panel
-                spinner = driver.find_element(
+                driver.find_element(
                     By.CSS_SELECTOR,
-                    ".sql-editor .sql-editor-busy-text-status")
-                return "d-none" in spinner.get_attribute("class")
+                    "#{0} div[data-label='loader']".format(container_id))
+                return False
             except NoSuchElementException:
                 # wait for loading indicator disappear animation to complete.
                 time.sleep(0.5)
@@ -1207,8 +1207,7 @@ class PgadminPage:
 
     def wait_for_query_tool_loading_indicator_to_appear(self):
         status = self.check_if_element_exist_by_xpath(
-            "//div[@id='editor-panel']//"
-            "div[@class='pg-sp-container sql-editor-busy-fetching']", 1)
+            "//div[@id='id-dataoutput']//div[@data-label='loader']", 1)
         return status
 
     def wait_for_app(self):
@@ -1340,14 +1339,15 @@ class PgadminPage:
 
         if required_status == 'Yes':
             status_changed_successfully = \
-                self.toggle_switch_box(switch_box_element,
-                                       expected_attr_in_class_tag='success',
-                                       unexpected_attr_in_class_tag='off')
+                self.toggle_switch_box(
+                    switch_box_element,
+                    expected_attr_in_class_tag='Mui-checked',
+                    unexpected_attr_in_class_tag='')
         else:
             status_changed_successfully = \
-                self.toggle_switch_box(switch_box_element,
-                                       expected_attr_in_class_tag='off',
-                                       unexpected_attr_in_class_tag='success')
+                self.toggle_switch_box(
+                    switch_box_element, expected_attr_in_class_tag='',
+                    unexpected_attr_in_class_tag='Mui-checked')
         return status_changed_successfully
 
     def toggle_switch_box(self, switch_box_ele, expected_attr_in_class_tag,
diff --git a/web/regression/runtests.py b/web/regression/runtests.py
index 6bc82a317..083402895 100644
--- a/web/regression/runtests.py
+++ b/web/regression/runtests.py
@@ -298,7 +298,7 @@ def setup_webdriver_specification(arguments):
         options.add_argument("--window-size=1790,1080")
         options.add_argument("--disable-infobars")
         # options.add_experimental_option('w3c', False)
-        driver_local = webdriver.Chrome(chrome_options=options)
+        driver_local = webdriver.Chrome(options=options)
 
     # maximize browser window
     driver_local.maximize_window()
