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 e26e993c..ab54d289 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 @@ -200,7 +200,7 @@ class CopySelectedQueryResultsFeatureTest(BaseFeatureTest): ActionChains(self.page.driver).key_down( Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform() - self.assertEqual('"cool info"', pyperclip.paste()) + self.assertIn('"cool info"', pyperclip.paste()) def after(self): self.page.close_query_tool() diff --git a/web/pgadmin/feature_tests/view_data_dml_queries.py b/web/pgadmin/feature_tests/view_data_dml_queries.py index 343be0ef..f5dc6590 100644 --- a/web/pgadmin/feature_tests/view_data_dml_queries.py +++ b/web/pgadmin/feature_tests/view_data_dml_queries.py @@ -185,6 +185,8 @@ CREATE TABLE public.defaults_{0} (By.XPATH, xpath)), CheckForViewDataTest.TIMEOUT_STRING ) cell_el = self.page.find_by_xpath(xpath) + self.page.driver.execute_script("arguments[0].scrollIntoView()", + cell_el) ActionChains(self.driver).move_to_element(cell_el).double_click( cell_el ).perform() diff --git a/web/pgadmin/feature_tests/xss_checks_file_manager_test.py b/web/pgadmin/feature_tests/xss_checks_file_manager_test.py index dfad314e..60d7e91c 100644 --- a/web/pgadmin/feature_tests/xss_checks_file_manager_test.py +++ b/web/pgadmin/feature_tests/xss_checks_file_manager_test.py @@ -8,6 +8,7 @@ ########################################################################## import os +import time from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By @@ -98,7 +99,18 @@ class CheckFileManagerFeatureTest(BaseFeatureTest): self.page.find_by_id("file-input-path").send_keys( Keys.RETURN ) - contents = self.page.find_by_id("contents").get_attribute('innerHTML') + + if self.page.driver.capabilities['browserName'] == 'firefox': + table = self.page.wait_for_element_to_reload( + lambda driver: + driver.find_element_by_css_selector("table#contents") + ) + else: + table = self.page.driver \ + .find_element_by_css_selector("table#contents") + + contents = table.get_attribute('innerHTML') + self.page.click_modal('Cancel') self.page.wait_for_query_tool_loading_indicator_to_disappear() self._check_escaped_characters( diff --git a/web/regression/README b/web/regression/README index 88edbd80..7e668cfd 100644 --- a/web/regression/README +++ b/web/regression/README @@ -46,7 +46,7 @@ General Information - 'pgAdmin4/web/pgadmin/browser/server_groups/tests/' shows an example of tree traversal of the pgAdmin modules and how the test folder is required for each individual module. - + - 'pgadmin/browser/server_groups/servers/tests/' directory will have separate file for each test-case: @@ -127,6 +127,15 @@ Python Tests: https://sites.google.com/a/chromium.org/chromedriver/downloads or a package manager and make sure it is in the PATH +- For feature tests to run on Firefox, geckodriver need to be installed; + - Get geckodriver from https://github.com/mozilla/geckodriver/releases. + - Extract the binary and run chmod +x geckodriver. + - Copy geckodriver into /usr/local/bin or make sure path of the + geckodriver must be specified in the PATH. + - Set the "default_browser" parameter in test_config file or pass the command + line option --default_browser. Supported browsers are "Chrome" and + "Firefox". + - The test framework is modular and pluggable and dynamically locates tests for modules which are discovered at runtime. All test cases are found and registered automatically by its module name in diff --git a/web/regression/feature_utils/app_starter.py b/web/regression/feature_utils/app_starter.py index 013f757c..795ec1e4 100644 --- a/web/regression/feature_utils/app_starter.py +++ b/web/regression/feature_utils/app_starter.py @@ -12,6 +12,7 @@ import signal import random import time +from selenium.common.exceptions import WebDriverException class AppStarter: @@ -41,10 +42,26 @@ class AppStarter: env=env ) - self.driver.get( - "http://" + self.app_config.DEFAULT_SERVER + ":" + - random_server_port - ) + def launch_browser(retry_count): + try: + self.driver.get( + "http://" + self.app_config.DEFAULT_SERVER + ":" + + random_server_port + ) + + except WebDriverException as e: + # In case of WebDriverException sleep for 1 second and retry + # again. Retry 10 times and if still app will not start then + # raise exception. + time.sleep(1) + if retry_count < 60: + retry_count = retry_count + 1 + launch_browser(retry_count) + else: + raise Exception('Unable to start python server even after ' + 'retrying 60 times.') + + launch_browser(0) def stop_app(self): """ This function stop the started app by killing process """ diff --git a/web/regression/feature_utils/pgadmin_page.py b/web/regression/feature_utils/pgadmin_page.py index be0f1c21..4b6bc21c 100644 --- a/web/regression/feature_utils/pgadmin_page.py +++ b/web/regression/feature_utils/pgadmin_page.py @@ -60,6 +60,8 @@ class PgadminPage: self.fill_input_by_field_name("port", server_config['port']) self.fill_input_by_field_name("username", server_config['username']) self.fill_input_by_field_name("password", server_config['db_password']) + # Required sleep to avoid "fe_sendauth" password error. + time.sleep(0.5) self.find_by_xpath("//button[contains(.,'Save')]").click() self.find_by_xpath( @@ -318,6 +320,14 @@ class PgadminPage: self._wait_for("app to start", page_shows_app, self.app_start_timeout) + def wait_for_element_to_reload(self, element_selector): + WebDriverWait(self.driver, 20) \ + .until(EC.staleness_of(element_selector(self.driver))) + WebDriverWait(self.driver, 20) \ + .until_not(EC.staleness_of(element_selector(self.driver))) + + return element_selector(self.driver) + def _wait_for(self, waiting_for_message, condition_met_function, timeout=None): if timeout is None: diff --git a/web/regression/runtests.py b/web/regression/runtests.py index a20c8f68..d7866926 100644 --- a/web/regression/runtests.py +++ b/web/regression/runtests.py @@ -22,6 +22,7 @@ import json from selenium import webdriver from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities if sys.version_info < (2, 7): import unittest2 as unit_test @@ -181,13 +182,40 @@ def get_test_modules(arguments): exclude_pkgs += arguments['exclude'].split(',') if 'feature_tests' not in exclude_pkgs: - options = Options() - if test_setup.config_data: - if 'headless_chrome' in test_setup.config_data: - if test_setup.config_data['headless_chrome']: - options.add_argument("--headless") - options.add_argument("--window-size=1280x1024") - driver = webdriver.Chrome(chrome_options=options) + default_browser = 'chrome' + + # Check default browser provided through command line. If provided + # then use that browser as default browser else check for the setting + # provided in test_config.json file. + if ( + 'default_browser' in arguments and + arguments['default_browser'] is not None + ): + default_browser = arguments['default_browser'].lower() + elif ( + test_setup.config_data and + "default_browser" in test_setup.config_data + ): + default_browser = test_setup.config_data['default_browser'].lower() + + if default_browser == 'firefox': + cap = DesiredCapabilities.FIREFOX + cap['requireWindowFocus'] = True + cap['enablePersistentHover'] = False + profile = webdriver.FirefoxProfile() + profile.set_preference("dom.disable_beforeunload", True) + driver = webdriver.Firefox(capabilities=cap, + firefox_profile=profile) + driver.implicitly_wait(1) + else: + options = Options() + if test_setup.config_data: + if 'headless_chrome' in test_setup.config_data: + if test_setup.config_data['headless_chrome']: + options.add_argument("--headless") + options.add_argument("--window-size=1280x1024") + driver = webdriver.Chrome(chrome_options=options) + app_starter = AppStarter(driver, config) app_starter.start_app() @@ -229,6 +257,10 @@ def add_arguments(): help='Skips execution of the test cases of particular package and ' 'sub-packages' ) + parser.add_argument( + '--default_browser', + help='Executes the feature test in specific browser' + ) arg = parser.parse_args() return arg @@ -341,7 +373,12 @@ if __name__ == '__main__': sys.stderr = StreamToLogger(stderr_logger, logging.ERROR) args = vars(add_arguments()) # Get test module list - test_module_list = get_test_modules(args) + try: + test_module_list = get_test_modules(args) + except Exception as e: + print(str(e)) + sys.exit(1) + # Login the test client test_utils.login_tester_account(test_client) diff --git a/web/regression/test_config.json.in b/web/regression/test_config.json.in index 54eeddbb..ebc1466f 100644 --- a/web/regression/test_config.json.in +++ b/web/regression/test_config.json.in @@ -1,5 +1,6 @@ { "headless_chrome": false, + "default_browser": "Chrome", "pgAdmin4_login_credentials": { "new_password": "NEWPASSWORD", "login_password": "PASSWORD",