Skip to content

Commit

Permalink
[py] Add support for the new MicrosoftEdge (#7459)
Browse files Browse the repository at this point in the history
Extracting Chromium from Chrome module. Have both Chrome and Edge
inherited from Chromium module. Add is_legacy parameter to launch
the new MicrosoftEdge.
  • Loading branch information
loly89 authored and lmtierney committed Aug 2, 2019
1 parent 9e02de5 commit 139ca6c
Show file tree
Hide file tree
Showing 30 changed files with 574 additions and 424 deletions.
1 change: 1 addition & 0 deletions py/MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ recursive-include selenium/webdriver/common *.py
recursive-include selenium/webdriver/common/actions *.py
recursive-include selenium/webdriver/common/html5 *.py
recursive-include selenium/common *.py
recursive-include selenium/webdriver/chromium *.py
recursive-include selenium/webdriver/chrome *.py
recursive-include selenium/webdriver/opera *.py
recursive-include selenium/webdriver/phantomjs *.py
Expand Down
5 changes: 5 additions & 0 deletions py/build.desc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ py_test(
deps = [":test_edge"],
browsers = [ "edge"])

py_test(
name = "chromium_edge_test",
deps = [":test_edge"],
browsers = ["chromiumedge"])

py_test(
name = "remote_firefox_test",
deps = [ ":test_remote_firefox" ],
Expand Down
8 changes: 8 additions & 0 deletions py/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
'Remote',
'Safari',
'WebKitGTK',
'ChromiumEdge',
)


Expand Down Expand Up @@ -117,6 +118,9 @@ def fin():
options = get_options('Firefox', request.config)
if driver_class == 'WebKitGTK':
options = get_options(driver_class, request.config)
if driver_class == 'ChromiumEdge':
options = get_options('Edge', request.config)
kwargs.update({'is_legacy': False})
if driver_path is not None:
kwargs['executable_path'] = driver_path
if options is not None:
Expand All @@ -131,6 +135,10 @@ def get_options(driver_class, config):
browser_path = config.option.binary
browser_args = config.option.args
options = None

if driver_class == 'Edge':
return getattr(webdriver, '{}Options'.format(driver_class))(False)

if browser_path or browser_args:
options = getattr(webdriver, '{}Options'.format(driver_class))()
if driver_class == 'WebKitGTK':
Expand Down
2 changes: 2 additions & 0 deletions py/selenium/webdriver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
from .ie.webdriver import WebDriver as Ie # noqa
from .ie.options import Options as IeOptions # noqa
from .edge.webdriver import WebDriver as Edge # noqa
from .edge.webdriver import WebDriver as ChromiumEdge # noqa
from .edge.options import Options as EdgeOptions #noqa
from .opera.webdriver import WebDriver as Opera # noqa
from .safari.webdriver import WebDriver as Safari # noqa
from .blackberry.webdriver import WebDriver as BlackBerry # noqa
Expand Down
152 changes: 6 additions & 146 deletions py/selenium/webdriver/chrome/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,159 +19,19 @@
import os

from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.common.options import ArgOptions
from selenium.webdriver.chromium.options import ChromiumOptions


class Options(ArgOptions):
class Options(ChromiumOptions):
KEY = "goog:chromeOptions"

def __init__(self):
super(Options, self).__init__()
self._binary_location = ''
self._extension_files = []
self._extensions = []
self._experimental_options = {}
self._debugger_address = None

@property
def binary_location(self):
"""
:Returns: The location of the binary, otherwise an empty string
"""
return self._binary_location

@binary_location.setter
def binary_location(self, value):
"""
Allows you to set where the chromium binary lives
:Args:
- value: path to the Chromium binary
"""
self._binary_location = value

@property
def debugger_address(self):
"""
:Returns: The address of the remote devtools instance
"""
return self._debugger_address

@debugger_address.setter
def debugger_address(self, value):
"""
Allows you to set the address of the remote devtools instance
that the ChromeDriver instance will try to connect to during an
active wait.
:Args:
- value: address of remote devtools instance if any (hostname[:port])
"""
self._debugger_address = value

@property
def extensions(self):
"""
:Returns: A list of encoded extensions that will be loaded into chrome
"""
encoded_extensions = []
for ext in self._extension_files:
file_ = open(ext, 'rb')
# Should not use base64.encodestring() which inserts newlines every
# 76 characters (per RFC 1521). Chromedriver has to remove those
# unnecessary newlines before decoding, causing performance hit.
encoded_extensions.append(base64.b64encode(file_.read()).decode('UTF-8'))

file_.close()
return encoded_extensions + self._extensions

def add_extension(self, extension):
"""
Adds the path to the extension to a list that will be used to extract it
to the ChromeDriver
:Args:
- extension: path to the \\*.crx file
"""
if extension:
extension_to_add = os.path.abspath(os.path.expanduser(extension))
if os.path.exists(extension_to_add):
self._extension_files.append(extension_to_add)
else:
raise IOError("Path to the extension doesn't exist")
else:
raise ValueError("argument can not be null")

def add_encoded_extension(self, extension):
"""
Adds Base64 encoded string with extension data to a list that will be used to extract it
to the ChromeDriver
:Args:
- extension: Base64 encoded string with extension data
"""
if extension:
self._extensions.append(extension)
else:
raise ValueError("argument can not be null")

@property
def experimental_options(self):
"""
:Returns: A dictionary of experimental options for chrome
"""
return self._experimental_options

def add_experimental_option(self, name, value):
"""
Adds an experimental option which is passed to chrome.
:Args:
name: The experimental option name.
value: The option value.
"""
self._experimental_options[name] = value

@property
def headless(self):
"""
:Returns: True if the headless argument is set, else False
"""
return '--headless' in self._arguments

@headless.setter
def headless(self, value):
"""
Sets the headless argument
:Args:
value: boolean value indicating to set the headless option
"""
args = {'--headless'}
if value is True:
self._arguments.extend(args)
else:
self._arguments = list(set(self._arguments) - args)
def default_capabilities(self):
return DesiredCapabilities.CHROME.copy()

def to_capabilities(self):
"""
Creates a capabilities with all the options that have been set
Creates a capabilities with all the options that have been set and
:Returns: A dictionary with everything
"""
caps = self._caps
chrome_options = self.experimental_options.copy()
chrome_options["extensions"] = self.extensions
if self.binary_location:
chrome_options["binary"] = self.binary_location
chrome_options["args"] = self.arguments
if self.debugger_address:
chrome_options["debuggerAddress"] = self.debugger_address

caps[self.KEY] = chrome_options

return caps

@property
def default_capabilities(self):
return DesiredCapabilities.CHROME.copy()
return super(Options, self).to_capabilities(self.KEY)
21 changes: 9 additions & 12 deletions py/selenium/webdriver/chrome/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
# specific language governing permissions and limitations
# under the License.

from selenium.webdriver.common import service
from selenium.webdriver.chromium import service


class Service(service.Service):
class Service(service.ChromiumService):
"""
Object that manages the starting and stopping of the ChromeDriver
"""
Expand All @@ -27,19 +27,16 @@ def __init__(self, executable_path, port=0, service_args=None,
log_path=None, env=None):
"""
Creates a new instance of the Service
:Args:
- executable_path : Path to the ChromeDriver
- port : Port the service is running on
- service_args : List of args to pass to the chromedriver service
- log_path : Path for the chromedriver service to log to"""

self.service_args = service_args or []
if log_path:
self.service_args.append('--log-path=%s' % log_path)

service.Service.__init__(self, executable_path, port=port, env=env,
start_error_message="Please see https://sites.google.com/a/chromium.org/chromedriver/home")

def command_line_args(self):
return ["--port=%d" % self.port] + self.service_args
super(Service, self).__init__(
executable_path,
port,
service_args,
log_path,
env,
"Please see https://sites.google.com/a/chromium.org/chromedriver/home")

0 comments on commit 139ca6c

Please sign in to comment.