diff --git a/help_docs/method_summary.md b/help_docs/method_summary.md index 593d2b1d..3b3c4699 100755 --- a/help_docs/method_summary.md +++ b/help_docs/method_summary.md @@ -85,6 +85,9 @@ self.maximize_window() self.activate_jquery() +self.get_property_value(selector, property, by=By.CSS_SELECTOR, + timeout=settings.SMALL_TIMEOUT) + self.bring_to_front(selector, by=By.CSS_SELECTOR) self.highlight(selector, by=By.CSS_SELECTOR, loops=4, scroll=True) diff --git a/help_docs/webdriver_installation.md b/help_docs/webdriver_installation.md index 26fc7240..e48e3375 100755 --- a/help_docs/webdriver_installation.md +++ b/help_docs/webdriver_installation.md @@ -1,9 +1,9 @@ ## Installing Google Chromedriver, Firefox Geckodriver, and other drivers -To run automation on various web browsers, you'll need to download a driver file for each one and place it on your System **[PATH](http://java.com/en/download/help/path.xml)**. On a Mac, ``/usr/local/bin`` is a good spot. On Windows, make sure you set the System Path under Environment Variables to include the location where you placed the driver files: +To run automation on various web browsers, you'll need to download a driver file for each one and place it on your System **[PATH](http://java.com/en/download/help/path.xml)**. On a Mac, ``/usr/local/bin`` is a good spot. On Windows, make sure you set the System Path under Environment Variables to include the location where you placed the driver files. You may want to download newer versions of drivers as they become available. -* For Chrome, get [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads) on your System Path. (**[Version 2.37](https://chromedriver.storage.googleapis.com/index.html?path=2.37/) or above is recommended!**) +* For Chrome, get [Chromedriver](https://sites.google.com/a/chromium.org/chromedriver/downloads) on your System Path. * For Firefox, get [Geckodriver](https://github.com/mozilla/geckodriver/releases) on your System Path. @@ -34,15 +34,15 @@ brew upgrade geckodriver Linux: ```bash -wget http://chromedriver.storage.googleapis.com/2.36/chromedriver_linux64.zip +wget http://chromedriver.storage.googleapis.com/2.37/chromedriver_linux64.zip unzip chromedriver_linux64.zip mv chromedriver /usr/local/bin/ chmod +x /usr/local/bin/chromedriver ``` ```bash -wget https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz -tar xvfz geckodriver-v0.19.1-linux64.tar.gz +wget https://github.com/mozilla/geckodriver/releases/download/v0.20.0/geckodriver-v0.20.0-linux64.tar.gz +tar xvfz geckodriver-v0.20.0-linux64.tar.gz mv geckodriver /usr/local/bin/ chmod +x /usr/local/bin/geckodriver ``` diff --git a/seleniumbase/config/proxy_list.py b/seleniumbase/config/proxy_list.py index a3aadc1e..1467fa84 100755 --- a/seleniumbase/config/proxy_list.py +++ b/seleniumbase/config/proxy_list.py @@ -19,7 +19,6 @@ you can try finding one from one of following sites: PROXY_LIST = { # "example1": "35.196.26.166:3128", # (Example) - set your own proxy here - # "example2": "208.95.62.81:3128", # (Example) - set your own proxy here "proxy1": None, "proxy2": None, "proxy3": None, diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index 755f60da..dce9f4dc 100755 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -7,6 +7,38 @@ from seleniumbase.config import settings from seleniumbase.config import proxy_list from seleniumbase.core import download_helper from seleniumbase.fixtures import constants +from seleniumbase.fixtures import page_utils + + +def _set_chrome_options(downloads_path, proxy_string): + chrome_options = webdriver.ChromeOptions() + prefs = { + "download.default_directory": downloads_path, + "credentials_enable_service": False, + "profile": { + "password_manager_enabled": False + } + } + chrome_options.add_experimental_option("prefs", prefs) + chrome_options.add_argument("--test-type") + chrome_options.add_argument("--no-first-run") + chrome_options.add_argument("--ignore-certificate-errors") + chrome_options.add_argument("--allow-file-access-from-files") + chrome_options.add_argument("--allow-insecure-localhost") + chrome_options.add_argument("--allow-running-insecure-content") + chrome_options.add_argument("--disable-infobars") + chrome_options.add_argument("--disable-save-password-bubble") + chrome_options.add_argument("--disable-single-click-autofill") + chrome_options.add_argument("--disable-translate") + chrome_options.add_argument("--disable-web-security") + if proxy_string: + chrome_options.add_argument('--proxy-server=%s' % proxy_string) + if settings.START_CHROME_IN_FULL_SCREEN_MODE: + # Run Chrome in full screen mode on WINDOWS + chrome_options.add_argument("--start-maximized") + # Run Chrome in full screen mode on MAC/Linux + chrome_options.add_argument("--kiosk") + return chrome_options def _create_firefox_profile(downloads_path, proxy_string): @@ -42,8 +74,8 @@ def _create_firefox_profile(downloads_path, proxy_string): def display_proxy_warning(proxy_string): message = ('\n\nWARNING: Proxy String ["%s"] is NOT in the expected ' - '"ip_address:port" format, (OR the key does not exist ' - 'in proxy_list.PROXY_LIST). ' + '"ip_address:port" or "server:port" format, ' + '(OR the key does not exist in proxy_list.PROXY_LIST). ' '*** DEFAULTING to NOT USING a Proxy Server! ***' % proxy_string) warnings.simplefilter('always', Warning) # See Warnings @@ -56,10 +88,24 @@ def validate_proxy_string(proxy_string): proxy_string = proxy_list.PROXY_LIST[proxy_string] if not proxy_string: return None - valid = re.match('^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$', proxy_string) - if valid: - proxy_string = valid.group() + valid = False + val_ip = re.match('^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$', proxy_string) + if not val_ip: + if proxy_string.startswith('http://'): + proxy_string = proxy_string.split('http://')[1] + elif proxy_string.startswith('https://'): + proxy_string = proxy_string.split('https://')[1] + elif '://' in proxy_string: + proxy_string = proxy_string.split('://')[1] + chunks = proxy_string.split(':') + if len(chunks) == 2: + if re.match('^\d+$', chunks[1]): + if page_utils.is_valid_url('http://' + proxy_string): + valid = True else: + proxy_string = val_ip.group() + valid = True + if not valid: display_proxy_warning(proxy_string) proxy_string = None return proxy_string @@ -82,33 +128,14 @@ def get_remote_driver(browser_name, headless, servername, port, proxy_string): address = "http://%s:%s/wd/hub" % (servername, port) if browser_name == constants.Browser.GOOGLE_CHROME: - chrome_options = webdriver.ChromeOptions() - prefs = { - "download.default_directory": downloads_path, - "credentials_enable_service": False, - "profile": { - "password_manager_enabled": False - } - } - chrome_options.add_experimental_option("prefs", prefs) - chrome_options.add_argument("--allow-file-access-from-files") - chrome_options.add_argument("--allow-running-insecure-content") - chrome_options.add_argument("--disable-infobars") + chrome_options = _set_chrome_options(downloads_path, proxy_string) if headless: chrome_options.add_argument("--headless") - if proxy_string: - chrome_options.add_argument('--proxy-server=%s' % proxy_string) - if settings.START_CHROME_IN_FULL_SCREEN_MODE: - # Run Chrome in full screen mode on WINDOWS - chrome_options.add_argument("--start-maximized") - # Run Chrome in full screen mode on MAC/Linux - chrome_options.add_argument("--kiosk") capabilities = chrome_options.to_capabilities() return webdriver.Remote( command_executor=address, desired_capabilities=capabilities) - - if browser_name == constants.Browser.FIREFOX: + elif browser_name == constants.Browser.FIREFOX: try: # Use Geckodriver for Firefox if it's on the PATH profile = _create_firefox_profile(downloads_path, proxy_string) @@ -136,23 +163,22 @@ def get_remote_driver(browser_name, headless, servername, port, proxy_string): command_executor=address, desired_capabilities=capabilities, browser_profile=profile) - - if browser_name == constants.Browser.INTERNET_EXPLORER: + elif browser_name == constants.Browser.INTERNET_EXPLORER: return webdriver.Remote( command_executor=address, desired_capabilities=( webdriver.DesiredCapabilities.INTERNETEXPLORER)) - if browser_name == constants.Browser.EDGE: + elif browser_name == constants.Browser.EDGE: return webdriver.Remote( command_executor=address, desired_capabilities=( webdriver.DesiredCapabilities.EDGE)) - if browser_name == constants.Browser.SAFARI: + elif browser_name == constants.Browser.SAFARI: return webdriver.Remote( command_executor=address, desired_capabilities=( webdriver.DesiredCapabilities.SAFARI)) - if browser_name == constants.Browser.PHANTOM_JS: + elif browser_name == constants.Browser.PHANTOM_JS: with warnings.catch_warnings(): # Ignore "PhantomJS has been deprecated" UserWarning warnings.simplefilter("ignore", category=UserWarning) @@ -195,40 +221,22 @@ def get_local_driver(browser_name, headless, proxy_string): if headless: raise Exception(e) return webdriver.Firefox() - if browser_name == constants.Browser.INTERNET_EXPLORER: + elif browser_name == constants.Browser.INTERNET_EXPLORER: return webdriver.Ie() - if browser_name == constants.Browser.EDGE: + elif browser_name == constants.Browser.EDGE: return webdriver.Edge() - if browser_name == constants.Browser.SAFARI: + elif browser_name == constants.Browser.SAFARI: return webdriver.Safari() - if browser_name == constants.Browser.PHANTOM_JS: + elif browser_name == constants.Browser.PHANTOM_JS: with warnings.catch_warnings(): # Ignore "PhantomJS has been deprecated" UserWarning warnings.simplefilter("ignore", category=UserWarning) return webdriver.PhantomJS() - if browser_name == constants.Browser.GOOGLE_CHROME: + elif browser_name == constants.Browser.GOOGLE_CHROME: try: - chrome_options = webdriver.ChromeOptions() - prefs = { - "download.default_directory": downloads_path, - "credentials_enable_service": False, - "profile": { - "password_manager_enabled": False - } - } - chrome_options.add_experimental_option("prefs", prefs) - chrome_options.add_argument("--allow-file-access-from-files") - chrome_options.add_argument("--allow-running-insecure-content") - chrome_options.add_argument("--disable-infobars") + chrome_options = _set_chrome_options(downloads_path, proxy_string) if headless: chrome_options.add_argument("--headless") - if proxy_string: - chrome_options.add_argument('--proxy-server=%s' % proxy_string) - if settings.START_CHROME_IN_FULL_SCREEN_MODE: - # Run Chrome in full screen mode on WINDOWS - chrome_options.add_argument("--start-maximized") - # Run Chrome in full screen mode on MAC/Linux - chrome_options.add_argument("--kiosk") return webdriver.Chrome(options=chrome_options) except Exception as e: if headless: diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 3faa262e..bdae3950 100755 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -198,12 +198,12 @@ class BaseCase(unittest.TestCase): return attribute_value if hard_fail: raise Exception( - 'Unable to find attribute [%s] from link text [%s]!' + 'Unable to find attribute {%s} from link text {%s}!' % (attribute, link_text)) else: return None if hard_fail: - raise Exception("Link text [%s] was not found!" % link_text) + raise Exception("Link text {%s} was not found!" % link_text) else: return None @@ -214,7 +214,7 @@ class BaseCase(unittest.TestCase): for x in range(int(timeout * 5)): try: if not self.is_link_text_present(link_text): - raise Exception("Link text [%s] not found!" % link_text) + raise Exception("Link text {%s} not found!" % link_text) return except Exception: now_ms = time.time() * 1000.0 @@ -222,7 +222,7 @@ class BaseCase(unittest.TestCase): break time.sleep(0.2) raise Exception( - "Link text [%s] was not present after %s seconds!" % ( + "Link text {%s} was not present after %s seconds!" % ( link_text, timeout)) def click_link_text(self, link_text, timeout=settings.SMALL_TIMEOUT): @@ -336,9 +336,9 @@ class BaseCase(unittest.TestCase): return raise Exception( 'Could not parse link from partial link_text ' - '[%s]' % partial_link_text) + '{%s}' % partial_link_text) raise Exception( - "Partial link text [%s] was not found!" % partial_link_text) + "Partial link text {%s} was not found!" % partial_link_text) # Not using phantomjs element = self.wait_for_partial_link_text( partial_link_text, timeout=timeout) @@ -405,7 +405,7 @@ class BaseCase(unittest.TestCase): if attribute_value is not None: return attribute_value else: - raise Exception("Element [%s] has no attribute [%s]!" % ( + raise Exception("Element {%s} has no attribute {%s}!" % ( selector, attribute)) def refresh_page(self): @@ -706,6 +706,40 @@ class BaseCase(unittest.TestCase): # Since jQuery still isn't activating, give up and raise an exception raise Exception("Exception: WebDriver could not activate jQuery!") + def get_property_value(self, selector, property, by=By.CSS_SELECTOR, + timeout=settings.SMALL_TIMEOUT): + """ Returns the property value of a page element's computed style. + Example: + opacity = self.get_property_value("html body a", "opacity") + self.assertTrue(float(opacity) > 0, "Element not visible!") """ + if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT: + timeout = self._get_new_timeout(timeout) + if page_utils.is_xpath_selector(selector): + by = By.XPATH + if page_utils.is_link_text_selector(selector): + selector = page_utils.get_link_text_from_selector(selector) + by = By.LINK_TEXT + self.wait_for_ready_state_complete() + page_actions.wait_for_element_present( + self.driver, selector, by, timeout) + try: + selector = self.convert_to_css_selector(selector, by=by) + except Exception: + # Don't run action if can't convert to CSS_Selector for JavaScript + raise Exception( + "Exception: Could not convert {%s}(by=%s) to CSS_SELECTOR!" % ( + selector, by)) + selector = self.jq_format(selector) + script = ("""var $elm = document.querySelector('%s'); + $val = window.getComputedStyle($elm).getPropertyValue('%s'); + return $val;""" + % (selector, property)) + value = self.execute_script(script) + if value is not None: + return value + else: + return "" # Return an empty string if the property doesn't exist + def bring_to_front(self, selector, by=By.CSS_SELECTOR): """ Updates the Z-index of a page element to bring it into view. Useful when getting a WebDriverException, such as the one below: @@ -717,10 +751,10 @@ class BaseCase(unittest.TestCase): try: selector = self.convert_to_css_selector(selector, by=by) except Exception: - # Don't perform action if can't convert to CSS_SELECTOR for jQuery + # Don't run action if can't convert to CSS_Selector for JavaScript return - - script = ("""document.querySelector('%s').style.zIndex = "1";""" + selector = self.jq_format(selector) + script = ("""document.querySelector('%s').style.zIndex = "100";""" % selector) self.execute_script(script) @@ -960,7 +994,7 @@ class BaseCase(unittest.TestCase): return 'a:contains("%s")' % selector else: raise Exception( - "Exception: Could not convert [%s](by=%s) to CSS_SELECTOR!" % ( + "Exception: Could not convert {%s}(by=%s) to CSS_SELECTOR!" % ( selector, by)) def set_value(self, selector, new_value, by=By.CSS_SELECTOR, @@ -1081,12 +1115,12 @@ class BaseCase(unittest.TestCase): (This generates real traffic for testing analytics software.) """ if not page_utils.is_valid_url(destination_page): raise Exception( - "Exception: destination_page [%s] is not a valid URL!" + "Exception: destination_page {%s} is not a valid URL!" % destination_page) if start_page: if not page_utils.is_valid_url(start_page): raise Exception( - "Exception: start_page [%s] is not a valid URL! " + "Exception: start_page {%s} is not a valid URL! " "(Use an empty string or None to start from current page.)" % start_page) self.open(start_page) diff --git a/server_setup.py b/server_setup.py index 858bc5f3..7ff4570d 100755 --- a/server_setup.py +++ b/server_setup.py @@ -7,7 +7,7 @@ from setuptools import setup, find_packages # noqa setup( name='seleniumbase', - version='1.7.4', + version='1.7.5', description='Web Automation & Testing Framework - http://seleniumbase.com', long_description='Web Automation and Testing Framework - seleniumbase.com', platforms='Mac * Windows * Linux * Docker', diff --git a/setup.py b/setup.py index a64ed2a2..9bb41bcc 100755 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ from setuptools import setup, find_packages # noqa setup( name='seleniumbase', - version='1.7.4', + version='1.7.5', description='Web Automation & Testing Framework - http://seleniumbase.com', long_description='Web Automation and Testing Framework - seleniumbase.com', platforms='Mac * Windows * Linux * Docker',