From 56b344089cafadbea0a928619d8c65f184d0ed3d Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Thu, 9 Nov 2017 19:01:14 +0100 Subject: [PATCH] [py] Add WebKitGTK driver (#4635) * [py] Add WebKitGTK driver --- py/conftest.py | 1 + py/selenium/webdriver/__init__.py | 2 + .../webdriver/common/desired_capabilities.py | 6 ++ py/selenium/webdriver/webkitgtk/__init__.py | 16 ++++ py/selenium/webdriver/webkitgtk/options.py | 96 +++++++++++++++++++ py/selenium/webdriver/webkitgtk/service.py | 42 ++++++++ py/selenium/webdriver/webkitgtk/webdriver.py | 73 ++++++++++++++ .../common/driver_element_finding_tests.py | 1 + .../webdriver/common/frame_switching_tests.py | 1 + 9 files changed, 238 insertions(+) create mode 100644 py/selenium/webdriver/webkitgtk/__init__.py create mode 100644 py/selenium/webdriver/webkitgtk/options.py create mode 100644 py/selenium/webdriver/webkitgtk/service.py create mode 100644 py/selenium/webdriver/webkitgtk/webdriver.py diff --git a/py/conftest.py b/py/conftest.py index 1e632d7f9e406..ae06833333dd4 100644 --- a/py/conftest.py +++ b/py/conftest.py @@ -44,6 +44,7 @@ 'PhantomJS', 'Remote', 'Safari', + 'WebKitGTK', ) diff --git a/py/selenium/webdriver/__init__.py b/py/selenium/webdriver/__init__.py index cc6eaa9f575b6..b7cc21a28841d 100644 --- a/py/selenium/webdriver/__init__.py +++ b/py/selenium/webdriver/__init__.py @@ -26,6 +26,8 @@ from .blackberry.webdriver import WebDriver as BlackBerry # noqa from .phantomjs.webdriver import WebDriver as PhantomJS # noqa from .android.webdriver import WebDriver as Android # noqa +from .webkitgtk.webdriver import WebDriver as WebKitGTK # noqa +from .webkitgtk.options import Options as WebKitGTKOptions # noqa from .remote.webdriver import WebDriver as Remote # noqa from .common.desired_capabilities import DesiredCapabilities # noqa from .common.action_chains import ActionChains # noqa diff --git a/py/selenium/webdriver/common/desired_capabilities.py b/py/selenium/webdriver/common/desired_capabilities.py index 678a3f64c81b6..a1d09a557e720 100644 --- a/py/selenium/webdriver/common/desired_capabilities.py +++ b/py/selenium/webdriver/common/desired_capabilities.py @@ -120,3 +120,9 @@ class DesiredCapabilities(object): "platform": "ANY", "javascriptEnabled": True, } + + WEBKITGTK = { + "browserName": "MiniBrowser", + "version": "", + "platform": "ANY", + } diff --git a/py/selenium/webdriver/webkitgtk/__init__.py b/py/selenium/webdriver/webkitgtk/__init__.py new file mode 100644 index 0000000000000..a5b1e6f85a09e --- /dev/null +++ b/py/selenium/webdriver/webkitgtk/__init__.py @@ -0,0 +1,16 @@ +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. diff --git a/py/selenium/webdriver/webkitgtk/options.py b/py/selenium/webdriver/webkitgtk/options.py new file mode 100644 index 0000000000000..7b6e5f3f8ea2e --- /dev/null +++ b/py/selenium/webdriver/webkitgtk/options.py @@ -0,0 +1,96 @@ +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities + + +class Options(object): + + def __init__(self): + self._browser_executable_path = '' + self._browser_arguments = [] + self._overlay_scrollbars_enabled = True + + @property + def browser_executable_path(self): + """ + Returns the location of the browser binary otherwise an empty string + """ + return self._browser_executable_path + + @browser_executable_path.setter + def browser_executable_path(self, value): + """ + Allows you to set the browser binary to launch + + :Args: + - value : path to the browser binary + """ + self._browser_executable_path = value + + @property + def browser_arguments(self): + """ + Returns a list of arguments needed for the browser + """ + return self._browser_arguments + + def add_browser_argument(self, argument): + """ + Adds an argument to the list + + :Args: + - Sets the arguments + """ + if argument: + self._browser_arguments.append(argument) + else: + raise ValueError("argument can not be null") + + @property + def overlay_scrollbars_enabled(self): + """ + Returns whether overlay scrollbars should be enabled + """ + return self._overlay_scrollbars_enabled + + @overlay_scrollbars_enabled.setter + def overlay_scrollbars_enabled(self, value): + """ + Allows you to enable or disable overlay scrollbars + + :Args: + - value : True or False + """ + self._overlay_scrollbars_enabled = value + + def to_capabilities(self): + """ + Creates a capabilities with all the options that have been set and + returns a dictionary with everything + """ + webkitgtk = DesiredCapabilities.WEBKITGTK.copy() + + browser_options = {} + if self.browser_executable_path: + browser_options["binary"] = self.browser_executable_path + browser_options["args"] = self.browser_arguments + browser_options["useOverlayScrollbars"] = self.overlay_scrollbars_enabled + + webkitgtk["webkitgtk:browserOptions"] = browser_options + + return webkitgtk diff --git a/py/selenium/webdriver/webkitgtk/service.py b/py/selenium/webdriver/webkitgtk/service.py new file mode 100644 index 0000000000000..26dad7412934c --- /dev/null +++ b/py/selenium/webdriver/webkitgtk/service.py @@ -0,0 +1,42 @@ +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +from selenium.webdriver.common import service + + +class Service(service.Service): + """ + Object that manages the starting and stopping of the WebKitGTKDriver + """ + + def __init__(self, executable_path, port=0, log_path=None): + """ + Creates a new instance of the Service + + :Args: + - executable_path : Path to the WebKitGTKDriver + - port : Port the service is running on + - log_path : Path for the WebKitGTKDriver service to log to + """ + log_file = open(log_path, "wb") if log_path is not None and log_path != "" else None + service.Service.__init__(self, executable_path, port, log_file) + + def command_line_args(self): + return ["-p", "%d" % self.port] + + def send_remote_shutdown_command(self): + pass diff --git a/py/selenium/webdriver/webkitgtk/webdriver.py b/py/selenium/webdriver/webkitgtk/webdriver.py new file mode 100644 index 0000000000000..6208f391c40be --- /dev/null +++ b/py/selenium/webdriver/webkitgtk/webdriver.py @@ -0,0 +1,73 @@ +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +try: + import http.client as http_client +except ImportError: + import httplib as http_client + +from selenium.webdriver.common.desired_capabilities import DesiredCapabilities +from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver +from .service import Service + + +class WebDriver(RemoteWebDriver): + """ + Controls the WebKitGTKDriver and allows you to drive the browser. + """ + + def __init__(self, executable_path="WebKitWebDriver", port=0, + browser_options=None, + desired_capabilities=DesiredCapabilities.WEBKITGTK, + service_log_path=None): + """ + Creates a new instance of the WebKitGTK driver. + + Starts the service and then creates new instance of WebKitGTK Driver. + + :Args: + - executable_path : path to the executable. If the default is used it assumes the executable is in the $PATH. + - port : port you would like the service to run, if left as 0, a free port will be found. + - browser_options : an instance of WebKitGTKOptions + - desired_capabilities : Dictionary object with desired capabilities + - service_log_path : Path to write service stdout and stderr output. + """ + if browser_options is not None: + capabilities = browser_options.to_capabilities() + capabilities.update(desired_capabilities) + desired_capabilities = capabilities + + self.service = Service(executable_path, port=port, log_path=service_log_path) + self.service.start() + + RemoteWebDriver.__init__( + self, + command_executor=self.service.service_url, + desired_capabilities=desired_capabilities) + self._is_remote = False + + def quit(self): + """ + Closes the browser and shuts down the WebKitGTKDriver executable + that is started when starting the WebKitGTKDriver + """ + try: + RemoteWebDriver.quit(self) + except http_client.BadStatusLine: + pass + finally: + self.service.stop() diff --git a/py/test/selenium/webdriver/common/driver_element_finding_tests.py b/py/test/selenium/webdriver/common/driver_element_finding_tests.py index 1cc1bc1e22839..b4dc2bd3857d7 100755 --- a/py/test/selenium/webdriver/common/driver_element_finding_tests.py +++ b/py/test/selenium/webdriver/common/driver_element_finding_tests.py @@ -358,6 +358,7 @@ def test_Finding_ALink_By_Xpath_Using_Contains_Keyword_Should_Work(driver, pages @pytest.mark.xfail_marionette(raises=WebDriverException) @pytest.mark.xfail_phantomjs(raises=InvalidSelectorException) @pytest.mark.xfail_safari(raises=NoSuchElementException) +@pytest.mark.xfail_webkitgtk(raises=InvalidSelectorException) def test_Should_Be_Able_To_Find_Element_By_XPath_With_Namespace(driver, pages): pages.load("svgPage.html") element = driver.find_element(By.XPATH, "//svg:svg//svg:text") diff --git a/py/test/selenium/webdriver/common/frame_switching_tests.py b/py/test/selenium/webdriver/common/frame_switching_tests.py index 3184e32b982e7..bd9cc5d9eec9e 100644 --- a/py/test/selenium/webdriver/common/frame_switching_tests.py +++ b/py/test/selenium/webdriver/common/frame_switching_tests.py @@ -382,6 +382,7 @@ def testShouldBeAbleToSwitchToTheTopIfTheFrameIsDeletedFromUnderUsWithWebelement @pytest.mark.xfail_phantomjs(raises=BadStatusLine) @pytest.mark.xfail_marionette(raises=WebDriverException, reason='https://github.com/mozilla/geckodriver/issues/614') +@pytest.mark.xfail_webkitgtk(raises=NoSuchElementException) def testShouldNotBeAbleToDoAnythingTheFrameIsDeletedFromUnderUs(driver, pages): if driver.name == 'firefox' and driver.w3c: pytest.skip('Stalls tests, https://bugzilla.mozilla.org/show_bug.cgi?id=1410799')