diff --git a/web/pgadmin/feature_tests/locators.py b/web/pgadmin/feature_tests/locators.py
index 46673f10..3b5a549d 100644
--- a/web/pgadmin/feature_tests/locators.py
+++ b/web/pgadmin/feature_tests/locators.py
@@ -20,3 +20,4 @@ class QueryToolLocatorsCss:
     query_history_selected = "#query_list .selected"
     query_history_detail = "#query_detail"
     editor_panel = "#output-panel"
+    query_messages_panel = ".sql-editor-message"
diff --git a/web/pgadmin/feature_tests/test_data.json b/web/pgadmin/feature_tests/test_data.json
index 50374c6c..41640673 100644
--- a/web/pgadmin/feature_tests/test_data.json
+++ b/web/pgadmin/feature_tests/test_data.json
@@ -1,6 +1,11 @@
 {
+  "comment": {
+    "sample_test_case": {
+      "colno": ["value to set", "value to verfiy", "data type"]
+    }
+  },
   "table_insert_update_cases": {
-    "add_update": {
+    "add": {
       "1": [1, "1", "int", "Value at 0 index is actual value(to be inserted), Value at index 1 is expected value, int is column type"],
       "2": ["", "1", "int"],
       "3": ["", "[null]", "int"],
@@ -21,6 +26,28 @@
       "18": ["{123,123,456}", "{123,123,456}", "int[]"],
       "19": ["", "[null]", "boolean[]"],
       "20": ["{false,null,true}", "{f,NULL,t}", "boolean[]"]
+    },
+    "copy": {
+      "1": [2, "2", "int"],
+      "2": ["1", "1", "int"]
+    },
+    "update": {
+      "4": ["Hello World Again", "Hello World Again", "text"]
+    }
+  },
+  "table_insert_update_nonint": {
+    "add": {
+      "1": ["pk%ey1", "pk%ey1", "text"],
+      "2": ["sometext", "sometext", "text"],
+      "3": [123, "123", "int"]
+    },
+    "copy": {
+      "1": ["pk%ey2", "pk%ey2", "text"]
+    },
+    "update": {
+      "1": ["pk%ey1", "pk%ey1", "text"],
+      "2": ["sometextchange", "sometextchange", "text"],
+      "3": [321, "321", "int"]
     }
   }
 }
diff --git a/web/pgadmin/feature_tests/view_data_dml_queries.py b/web/pgadmin/feature_tests/view_data_dml_queries.py
index 8e69ffc5..e47145e2 100644
--- a/web/pgadmin/feature_tests/view_data_dml_queries.py
+++ b/web/pgadmin/feature_tests/view_data_dml_queries.py
@@ -15,17 +15,19 @@ from selenium.webdriver import ActionChains
 from regression.python_test_utils import test_utils
 from regression.feature_utils.base_feature_test import BaseFeatureTest
 from selenium.webdriver.common.by import By
+from selenium.webdriver.common.keys import Keys
 from selenium.webdriver.support import expected_conditions as EC
 from selenium.webdriver.support.ui import WebDriverWait
+from .locators import QueryToolLocatorsCss
 
 CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
 
-try:
-    with open(CURRENT_PATH + '/test_data.json') as data_file:
-        config_data = json.load(data_file)[
-            'table_insert_update_cases']['add_update']
-except Exception as e:
-    print(str(e))
+config_data = config_data_json = {}
+# try:
+with open(CURRENT_PATH + '/test_data.json') as data_file:
+    config_data_json = json.load(data_file)
+# except Exception as e:
+#     print(str(e))
 
 
 class CheckForViewDataTest(BaseFeatureTest):
@@ -80,6 +82,15 @@ CREATE TABLE public.defaults_{0}
     CONSTRAINT defaults_pkey_{0} PRIMARY KEY ({1})
 )
 """
+    non_int_pkey_table = """
+CREATE TABLE public.nonintpkey
+(
+    charid text COLLATE pg_catalog."default" NOT NULL,
+    col1 text,
+    col2 numeric(100),
+    CONSTRAINT nonintpkey_pkey PRIMARY KEY (charid)
+)
+    """
 
     def before(self):
         with test_utils.Database(self.server) as (connection, _):
@@ -95,6 +106,12 @@ CREATE TABLE public.defaults_{0}
                 self.test_db,
                 CheckForViewDataTest.defaults_query.format(k, v))
 
+        test_utils.create_table_with_query(
+            self.server,
+            self.test_db,
+            CheckForViewDataTest.non_int_pkey_table
+        )
+
         # Initialize an instance of WebDriverWait with timeout of 3 seconds
         self.wait = WebDriverWait(self.driver, 3)
 
@@ -105,20 +122,15 @@ CREATE TABLE public.defaults_{0}
         self.page.wait_for_spinner_to_disappear()
         self.page.add_server(self.server)
         self._tables_node_expandable()
+
+        self._load_config_data('table_insert_update_cases')
         # iterate on both tables
         for cnt in (1, 2):
-            self.page.select_tree_item('defaults_{0}'.format(str(cnt)))
-            # Open Object -> View/Edit data
-            self._view_data_grid('defaults_{0}'.format(str(cnt)))
+            self._perform_test_for_table('defaults_{0}'.format(str(cnt)))
 
-            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()
-            self._verify_row_data(True)
-
-            # Run test to copy/paste a row
-            self._copy_paste_row()
-            self.page.close_data_grid()
+        # test nonint pkey table
+        self._load_config_data('table_insert_update_nonint')
+        self._perform_test_for_table('nonintpkey')
 
     def after(self):
         self.page.remove_server(self.server)
@@ -139,6 +151,36 @@ CREATE TABLE public.defaults_{0}
 
         return xpath_cell
 
+    @staticmethod
+    def _load_config_data(config_key):
+        global config_data
+        config_data = config_data_json[config_key]
+
+    def _perform_test_for_table(self, table_name):
+        self.page.select_tree_item(table_name)
+        # Open Object -> View/Edit data
+        self._view_data_grid(table_name)
+
+        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()
+        self._verify_row_data(True, config_data['add'])
+
+        # Run test to copy/paste a row
+        self._copy_paste_row()
+
+        self._update_row()
+        self.page.click_tab("Messages")
+        self._verify_messsages("")
+        self.page.click_tab("Data Output")
+        updated_row_data = {
+            i: config_data['update'][i] if i in config_data['update'] else val
+            for i, val in config_data['add'].items()
+        }
+        self._verify_row_data(False, updated_row_data)
+
+        self.page.close_data_grid()
+
     def _compare_cell_value(self, xpath, value):
         # Initialize an instance of WebDriverWait with timeout of 5 seconds
         wait = WebDriverWait(self.driver, 5)
@@ -181,10 +223,12 @@ CREATE TABLE public.defaults_{0}
             if value == 'clear':
                 cell_el.find_element_by_css_selector('input').clear()
             else:
-                ActionChains(self.driver).send_keys(value).perform()
+                ActionChains(self.driver).send_keys(value).\
+                    send_keys(Keys.ENTER).perform()
         elif cell_type in ['text', 'json', 'text[]', 'boolean[]']:
             text_area_ele = self.page.find_by_css_selector(
                 ".pg-text-editor > textarea")
+            text_area_ele.clear()
             text_area_ele.click()
             text_area_ele.send_keys(value)
 
@@ -238,47 +282,28 @@ CREATE TABLE public.defaults_{0}
 
     def _copy_paste_row(self):
         row0_cell0_xpath = CheckForViewDataTest._get_cell_xpath("r0", 1)
-        row1_cell1_xpath = CheckForViewDataTest._get_cell_xpath("r1", 2)
-        row1_cell2_xpath = CheckForViewDataTest._get_cell_xpath("r2", 2)
 
         self.page.find_by_xpath(row0_cell0_xpath).click()
         self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
         self.page.find_by_xpath("//*[@id='btn-paste-row']").click()
-        # Update primary key of copied cell
-        self._update_cell(row1_cell1_xpath, [2, "", "int"])
-        self.page.find_by_xpath(
-            CheckForViewDataTest._get_cell_xpath("r1", "3")
-        ).click()
-
-        # Check if removing a cell value with default value sets
-        # markup to [default] if cell is cleared
-        self._update_cell(row1_cell2_xpath, ["clear", "", "int"])
-        # click outside
-        self.page.find_by_xpath(
-            CheckForViewDataTest._get_cell_xpath("r1", "3")
-        ).click()
-
-        self._compare_cell_value(row1_cell2_xpath, "[default]")
-        # reset cell value to previous one
-        self._update_cell(row1_cell2_xpath, ["1", "", "int"])
 
-        self.page.find_by_id("btn-save").click()  # Save data
-        # There should be some delay after save button is clicked, as it
-        # takes some time to complete save ajax call otherwise discard unsaved
-        # changes dialog will appear if we try to execute query before previous
-        # save ajax is completed.
-        time.sleep(2)
+        # Update primary key of copied cell
+        self._add_update_save_row(config_data['copy'], row=2)
 
         # Verify row 1 and row 2 data
-        self._verify_row_data(False)
-
-    def _add_row(self):
-        for idx in range(1, len(config_data.keys()) + 1):
+        updated_row_data = {
+            i: config_data['copy'][i] if i in config_data['copy'] else val
+            for i, val in config_data['add'].items()
+        }
+        self._verify_row_data(False, updated_row_data)
+
+    def _add_update_save_row(self, data, row=1):
+        for idx in data.keys():
             cell_xpath = CheckForViewDataTest._get_cell_xpath(
-                'r' + str(idx), 1
+                'r' + str(idx), row
             )
             time.sleep(0.2)
-            self._update_cell(cell_xpath, config_data[str(idx)])
+            self._update_cell(cell_xpath, data[str(idx)])
         self.page.find_by_id("btn-save").click()  # Save data
         # There should be some delay after save button is clicked, as it
         # takes some time to complete save ajax call otherwise discard unsaved
@@ -286,7 +311,18 @@ CREATE TABLE public.defaults_{0}
         # save ajax is completed.
         time.sleep(2)
 
-    def _verify_row_data(self, is_new_row):
+    def _add_row(self):
+        self._add_update_save_row(config_data['add'], 1)
+
+    def _update_row(self):
+        self._add_update_save_row(config_data['update'], 1)
+
+    def _verify_messsages(self, text):
+        messages_ele = self.page.find_by_css_selector(
+            QueryToolLocatorsCss.query_messages_panel)
+        self.assertEquals(text, messages_ele.text)
+
+    def _verify_row_data(self, is_new_row, config_check_data):
         self.page.find_by_id("btn-flash").click()
 
         # First row if row height = 0, second row if its 25
@@ -300,21 +336,17 @@ CREATE TABLE public.defaults_{0}
         result_row = self.page.find_by_xpath(xpath)
 
         # List of row values in an array
-        for idx in range(1, len(config_data.keys()) + 1):
-            # after copy & paste row, the first cell of row 1 and
-            # row 2(being primary keys) won't match
-            # see if cell values matched to actual value
+        for idx in config_check_data.keys():
             element = result_row.find_element_by_class_name("r" + str(idx))
             self.page.driver.execute_script(
                 "arguments[0].scrollIntoView(false)", element)
 
-            if (idx != 1 and not is_new_row) or is_new_row:
-                self.assertEquals(element.text, config_data[str(idx)][1])
-                self.assertEquals(element.text, config_data[str(idx)][1])
+            self.assertEquals(element.text, config_check_data[str(idx)][1])
+            self.assertEquals(element.text, config_check_data[str(idx)][1])
 
         # scroll browser back to the left
         # to reset position so other assertions can succeed
-        for idx in range(len(config_data.keys()), 1, -1):
+        for idx in reversed(list(config_check_data.keys())):
             element = result_row.find_element_by_class_name("r" + str(idx))
             self.page.driver.execute_script(
                 "arguments[0].scrollIntoView(false)", element)
