pgadmin4/web/pgadmin/feature_tests/query_tool_journey_test.py

276 lines
10 KiB
Python

##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2019, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
import sys
import pyperclip
import random
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from regression.python_test_utils import test_utils
from regression.feature_utils.base_feature_test import BaseFeatureTest
from .locators import QueryToolLocatorsCss
class QueryToolJourneyTest(BaseFeatureTest):
"""
Tests the path through the query tool
"""
scenarios = [
("Tests the path through the query tool", dict())
]
test_table_name = ""
test_editable_table_name = ""
def before(self):
self.test_table_name = "test_table" + str(random.randint(1000, 3000))
test_utils.create_table(
self.server, self.test_db, self.test_table_name)
self.test_editable_table_name = "test_editable_table" + \
str(random.randint(1000, 3000))
create_sql = '''
CREATE TABLE "%s" (
pk_column NUMERIC PRIMARY KEY,
normal_column NUMERIC
);
''' % self.test_editable_table_name
test_utils.create_table_with_query(
self.server, self.test_db, create_sql)
self.page.add_server(self.server)
driver_version = test_utils.get_driver_version()
self.driver_version = float('.'.join(driver_version.split('.')[:2]))
def runTest(self):
self._navigate_to_query_tool()
self._execute_query(
"SELECT * FROM %s ORDER BY value " % self.test_table_name)
print("Copy rows...", file=sys.stderr, end="")
self._test_copies_rows()
print(" OK.", file=sys.stderr)
print("Copy columns...", file=sys.stderr, end="")
self._test_copies_columns()
print(" OK.", file=sys.stderr)
print("History tab...", file=sys.stderr, end="")
self._test_history_tab()
print(" OK.", file=sys.stderr)
print("Updatable resultsets...", file=sys.stderr, end="")
self._test_updatable_resultset()
print(" OK.", file=sys.stderr)
def _test_copies_rows(self):
pyperclip.copy("old clipboard contents")
self.page.driver.switch_to.default_content()
self.page.driver.switch_to_frame(
self.page.driver.find_element_by_tag_name("iframe"))
self.page.find_by_xpath(
"//*[contains(@class, 'slick-row')]/*[1]").click()
self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
self.assertEqual('"Some-Name"\t"6"\t"some info"',
pyperclip.paste())
def _test_copies_columns(self):
pyperclip.copy("old clipboard contents")
self.page.driver.switch_to.default_content()
self.page.driver.switch_to_frame(
self.page.driver.find_element_by_tag_name("iframe"))
self.page.find_by_xpath(
"//*[@data-test='output-column-header' and "
"contains(., 'some_column')]"
).click()
self.page.find_by_xpath("//*[@id='btn-copy-row']").click()
self.assertTrue('"Some-Name"' in pyperclip.paste())
self.assertTrue('"Some-Other-Name"' in pyperclip.paste())
self.assertTrue('"Yet-Another-Name"' in pyperclip.paste())
def _test_history_tab(self):
self.__clear_query_tool()
editor_input = self.page.find_by_css_selector(
QueryToolLocatorsCss.query_editor_panel)
self.page.click_element(editor_input)
self._execute_query("SELECT * FROM table_that_doesnt_exist")
self.page.click_tab("Query History")
selected_history_entry = self.page.find_by_css_selector(
QueryToolLocatorsCss.query_history_selected)
self.assertIn("SELECT * FROM table_that_doesnt_exist",
selected_history_entry.text)
failed_history_detail_pane = self.page.find_by_css_selector(
QueryToolLocatorsCss.query_history_detail)
self.assertIn(
"Error Message relation \"table_that_doesnt_exist\" "
"does not exist", failed_history_detail_pane.text
)
self.page.wait_for_element(lambda driver: driver
.find_element_by_css_selector(
"#query_list> .query-group>ul>li"))
# get the query history rows and click the previous query row which
# was executed and verify it
history_rows = self.driver.find_elements_by_css_selector(
"#query_list> .query-group>ul>li")
history_rows[1].click()
selected_history_entry = self.page.find_by_css_selector(
"#query_list .selected")
self.assertIn(("SELECT * FROM %s ORDER BY value" %
self.test_table_name),
selected_history_entry.text)
# check second(invalid) query also exist in the history tab with error
newly_selected_history_entry = self.page.find_by_xpath(
"//*[@id='query_list']/div/ul/li[1]")
self.page.click_element(newly_selected_history_entry)
selected_invalid_history_entry = self.page.find_by_css_selector(
"#query_list .selected .entry.error .query")
self.assertIn("SELECT * FROM table_that_doesnt_exist",
selected_invalid_history_entry.text)
self.page.click_tab("Query Editor")
self.__clear_query_tool()
self.page.click_element(editor_input)
self.page.fill_codemirror_area_with("SELECT * FROM hats")
for _ in range(15):
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab("Query History")
query_we_need_to_scroll_to = self.page.find_by_xpath(
"//*[@id='query_list']/div/ul/li[17]")
self.page.click_element(query_we_need_to_scroll_to)
for _ in range(17):
ActionChains(self.page.driver) \
.send_keys(Keys.ARROW_DOWN) \
.perform()
self._assert_clickable(query_we_need_to_scroll_to)
self.page.click_tab("Query Editor")
self.__clear_query_tool()
self.page.click_element(editor_input)
self.page.fill_codemirror_area_with("SELECT * FROM hats")
for _ in range(15):
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
self.page.wait_for_query_tool_loading_indicator_to_disappear()
self.page.click_tab("History")
query_we_need_to_scroll_to = self.page.find_by_xpath(
"//*[@id='query_list']/div/ul/li[17]"
)
for _ in range(17):
ActionChains(self.page.driver) \
.send_keys(Keys.ARROW_DOWN) \
.perform()
self._assert_clickable(query_we_need_to_scroll_to)
def _test_updatable_resultset(self):
if self.driver_version < 2.8:
return
self.page.click_tab("Query Editor")
# Insert data into test table
self.__clear_query_tool()
self._execute_query(
"INSERT INTO %s VALUES (1, 1), (2, 2);"
% self.test_editable_table_name
)
# Select all data (contains the primary key -> should be editable)
self.__clear_query_tool()
query = "SELECT pk_column, normal_column FROM %s" \
% self.test_editable_table_name
self._check_query_results_editable(query, True)
# Select data without primary keys -> should not be editable
self.__clear_query_tool()
query = "SELECT normal_column FROM %s" % self.test_editable_table_name
self._check_query_results_editable(query, False)
def __clear_query_tool(self):
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear-dropdown']")
)
ActionChains(self.driver)\
.move_to_element(self.page.find_by_xpath("//*[@id='btn-clear']"))\
.perform()
self.page.click_element(
self.page.find_by_xpath("//*[@id='btn-clear']")
)
self.page.click_modal('Yes')
def _navigate_to_query_tool(self):
self.page.toggle_open_tree_item(self.server['name'])
self.page.toggle_open_tree_item('Databases')
self.page.toggle_open_tree_item(self.test_db)
self.page.open_query_tool()
self.page.wait_for_spinner_to_disappear()
def _execute_query(self, query):
self.page.fill_codemirror_area_with(query)
self.page.find_by_css_selector(
QueryToolLocatorsCss.btn_execute_query).click()
def _assert_clickable(self, element):
self.page.click_element(element)
def _check_query_results_editable(self, query, should_be_editable):
self._execute_query(query)
self.page.wait_for_spinner_to_disappear()
# Check if the first cell in the first row is editable
is_editable = self._check_cell_editable(1)
self.assertEqual(is_editable, should_be_editable)
# Check that new rows cannot be added
can_add_rows = self._check_can_add_row()
self.assertEqual(can_add_rows, should_be_editable)
def _check_cell_editable(self, cell_index):
xpath = '//div[contains(@class, "slick-cell") and ' \
'contains(@class, "r' + str(cell_index) + '")]'
cell_el = self.page.find_by_xpath(xpath)
cell_classes = cell_el.get_attribute('class')
cell_classes = cell_classes.split(" ")
self.assertFalse('editable' in cell_classes)
ActionChains(self.driver).double_click(cell_el).perform()
cell_classes = cell_el.get_attribute('class')
cell_classes = cell_classes.split(" ")
return 'editable' in cell_classes
def _check_can_add_row(self):
return self.page.check_if_element_exist_by_xpath(
'//div[contains(@class, "new-row")]')
def after(self):
self.page.close_query_tool()
self.page.remove_server(self.server)