Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 617f16f

Browse files
bwaldermanAutomatedTester
andauthoredMar 10, 2020
[py] Use a capability to switch engines for Edge (#8096)
* Use ms:edgeChromium capability in python bindings. * Update edge_options_tests. * Fix chromium command prefixes. * Import warnings for edge webdriver.py. Co-authored-by: David Burns <david.burns@theautomatedtester.co.uk>
1 parent 53761e3 commit 617f16f

File tree

9 files changed

+144
-93
lines changed

9 files changed

+144
-93
lines changed
 

‎py/BUILD.bazel

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,52 @@ py_test_suite(
160160
],
161161
)
162162

163+
py_test_suite(
164+
name = "test-edge",
165+
size = "large",
166+
srcs = glob([
167+
"test/selenium/webdriver/edge/**/*.py",
168+
"test/selenium/webdriver/common/**/*.py",
169+
"test/selenium/webdriver/support/**/*.py",
170+
]),
171+
args = [
172+
"--instafail",
173+
"--driver=Edge",
174+
],
175+
tags = [
176+
"no-sandbox",
177+
],
178+
deps = [
179+
":init-tree",
180+
":selenium",
181+
":webserver",
182+
"//third_party/py:pytest",
183+
],
184+
)
185+
186+
py_test_suite(
187+
name = "test-edge-chromium",
188+
size = "large",
189+
srcs = glob([
190+
"test/selenium/webdriver/edge/**/*.py",
191+
"test/selenium/webdriver/common/**/*.py",
192+
"test/selenium/webdriver/support/**/*.py",
193+
]),
194+
args = [
195+
"--instafail",
196+
"--driver=ChromiumEdge",
197+
],
198+
tags = [
199+
"no-sandbox",
200+
],
201+
deps = [
202+
":init-tree",
203+
":selenium",
204+
":webserver",
205+
"//third_party/py:pytest",
206+
],
207+
)
208+
163209
py_test_suite(
164210
name = "test-firefox",
165211
size = "large",

‎py/conftest.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ def fin():
120120
options = get_options(driver_class, request.config)
121121
if driver_class == 'ChromiumEdge':
122122
options = get_options(driver_class, request.config)
123-
kwargs.update({'is_legacy': False})
124123
if driver_path is not None:
125124
kwargs['executable_path'] = driver_path
126125
if options is not None:
@@ -136,10 +135,12 @@ def get_options(driver_class, config):
136135
browser_args = config.option.args
137136
options = None
138137

138+
if driver_class == 'ChromiumEdge':
139+
options = getattr(webdriver, 'EdgeOptions')()
140+
options.use_chromium = True
141+
139142
if browser_path or browser_args:
140-
if driver_class == 'ChromiumEdge':
141-
options = getattr(webdriver, 'EdgeOptions')(False)
142-
else:
143+
if not options:
143144
options = getattr(webdriver, '{}Options'.format(driver_class))()
144145
if driver_class == 'WebKitGTK':
145146
options.overlay_scrollbars_enabled = False

‎py/selenium/webdriver/chrome/webdriver.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from selenium.webdriver.chromium.webdriver import ChromiumDriver
1919
from .options import Options
2020
from .service import Service
21+
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
2122

2223

2324
DEFAULT_PORT = 0
@@ -49,6 +50,9 @@ def __init__(self, executable_path="chromedriver", port=DEFAULT_PORT,
4950
- service_log_path - Deprecated: Where to log information from the driver.
5051
- keep_alive - Whether to configure ChromeRemoteConnection to use HTTP keep-alive.
5152
"""
53+
if executable_path != 'chromedriver':
54+
warnings.warn('executable_path has been deprecated, please pass in a Service object',
55+
DeprecationWarning, stacklevel=2)
5256
if chrome_options:
5357
warnings.warn('use options instead of chrome_options',
5458
DeprecationWarning, stacklevel=2)
@@ -57,7 +61,8 @@ def __init__(self, executable_path="chromedriver", port=DEFAULT_PORT,
5761
if service is None:
5862
service = Service(executable_path, port, service_args, service_log_path)
5963

60-
super(WebDriver, self).__init__(executable_path, port, options,
64+
super(WebDriver, self).__init__(DesiredCapabilities.CHROME['browserName'], "goog",
65+
port, options,
6166
service_args, desired_capabilities,
6267
service_log_path, service, keep_alive)
6368

‎py/selenium/webdriver/chromium/remote_connection.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,15 @@
2020

2121

2222
class ChromiumRemoteConnection(RemoteConnection):
23-
24-
browser_name = DesiredCapabilities.CHROME['browserName']
25-
26-
def __init__(self, remote_server_addr, keep_alive=True):
23+
def __init__(self, remote_server_addr, vendor_prefix, browser_name, keep_alive=True):
2724
RemoteConnection.__init__(self, remote_server_addr, keep_alive)
25+
self.browser_name = browser_name
2826
self._commands["launchApp"] = ('POST', '/session/$sessionId/chromium/launch_app')
2927
self._commands["setNetworkConditions"] = ('POST', '/session/$sessionId/chromium/network_conditions')
3028
self._commands["getNetworkConditions"] = ('GET', '/session/$sessionId/chromium/network_conditions')
31-
self._commands['executeCdpCommand'] = ('POST', '/session/$sessionId/goog/cdp/execute')
32-
self._commands['getSinks'] = ('GET', '/session/$sessionId/goog/cast/get_sinks')
33-
self._commands['getIssueMessage'] = ('GET', '/session/$sessionId/goog/cast/get_issue_message')
34-
self._commands['setSinkToUse'] = ('POST', '/session/$sessionId/goog/cast/set_sink_to_use')
35-
self._commands['startTabMirroring'] = ('POST', '/session/$sessionId/goog/cast/start_tab_mirroring')
36-
self._commands['stopCasting'] = ('POST', '/session/$sessionId/goog/cast/stop_casting')
29+
self._commands['executeCdpCommand'] = ('POST', '/session/$sessionId/{}/cdp/execute'.format(vendor_prefix))
30+
self._commands['getSinks'] = ('GET', '/session/$sessionId/{}/cast/get_sinks'.format(vendor_prefix))
31+
self._commands['getIssueMessage'] = ('GET', '/session/$sessionId/{}/cast/get_issue_message'.format(vendor_prefix))
32+
self._commands['setSinkToUse'] = ('POST', '/session/$sessionId/{}/cast/set_sink_to_use'.format(vendor_prefix))
33+
self._commands['startTabMirroring'] = ('POST', '/session/$sessionId/{}/cast/start_tab_mirroring'.format(vendor_prefix))
34+
self._commands['stopCasting'] = ('POST', '/session/$sessionId/{}/cast/stop_casting'.format(vendor_prefix))

‎py/selenium/webdriver/chromium/webdriver.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,17 @@ class ChromiumDriver(RemoteWebDriver):
2828
Controls the WebDriver instance of ChromiumDriver and allows you to drive the browser.
2929
"""
3030

31-
def __init__(self, executable_path="chromedriver", port=DEFAULT_PORT,
32-
options=None, service_args=None,
31+
def __init__(self, browser_name, vendor_prefix,
32+
port=DEFAULT_PORT, options=None, service_args=None,
3333
desired_capabilities=None, service_log_path=DEFAULT_SERVICE_LOG_PATH,
3434
service=None, keep_alive=True):
3535
"""
3636
Creates a new WebDriver instance of the ChromiumDriver.
3737
Starts the service and then creates new WebDriver instance of ChromiumDriver.
3838
3939
:Args:
40-
- executable_path - Deprecated: path to the executable. If the default is used it assumes the executable is in the $PATH
40+
browser_name - Browser name used when matching capabilities.
41+
vendor_prefix - Company prefix to apply to vendor-specific WebDriver extension commands.
4142
- port - Deprecated: port you would like the service to run, if left as 0, a free port will be found.
4243
- options - this takes an instance of ChromiumOptions
4344
- service_args - Deprecated: List of args to pass to the driver service
@@ -46,9 +47,6 @@ def __init__(self, executable_path="chromedriver", port=DEFAULT_PORT,
4647
- service_log_path - Deprecated: Where to log information from the driver.
4748
- keep_alive - Whether to configure ChromiumRemoteConnection to use HTTP keep-alive.
4849
"""
49-
if executable_path != 'chromedriver':
50-
warnings.warn('executable_path has been deprecated, please pass in a Service object',
51-
DeprecationWarning, stacklevel=2)
5250
if desired_capabilities is not None:
5351
warnings.warn('desired_capabilities has been deprecated, please pass in a Service object',
5452
DeprecationWarning, stacklevel=2)
@@ -81,6 +79,7 @@ def __init__(self, executable_path="chromedriver", port=DEFAULT_PORT,
8179
self,
8280
command_executor=ChromiumRemoteConnection(
8381
remote_server_addr=self.service.service_url,
82+
browser_name=browser_name, vendor_prefix=vendor_prefix,
8483
keep_alive=keep_alive),
8584
desired_capabilities=desired_capabilities)
8685
except Exception:

‎py/selenium/webdriver/edge/options.py

Lines changed: 21 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,52 +22,42 @@
2222
class Options(ChromiumOptions):
2323
KEY = "ms:edgeOptions"
2424

25-
def __init__(self, is_legacy=True):
25+
def __init__(self):
2626
super(Options, self).__init__()
27-
self._is_legacy = is_legacy
28-
self._custom_browser_name = None
29-
30-
if is_legacy:
31-
self._page_load_strategy = "normal"
27+
self._use_chromium = False
28+
self._use_webview = False
3229

3330
@property
34-
def custom_browser_name(self):
35-
return self._custom_browser_name
31+
def use_chromium(self):
32+
return self._use_chromium
3633

37-
@custom_browser_name.setter
38-
def custom_browser_name(self, value):
39-
self._custom_browser_name = value
34+
@use_chromium.setter
35+
def use_chromium(self, value):
36+
self._use_chromium = bool(value)
4037

4138
@property
42-
def page_load_strategy(self):
43-
if not self._is_legacy:
44-
raise AttributeError("Page Load Strategy only exists in Legacy Mode")
45-
46-
return self._page_load_strategy
47-
48-
@page_load_strategy.setter
49-
def page_load_strategy(self, value):
50-
if not self._is_legacy:
51-
raise AttributeError("Page Load Strategy only exists in Legacy Mode")
39+
def use_webview(self):
40+
return self._use_webview
5241

53-
if value not in ['normal', 'eager', 'none']:
54-
raise ValueError("Page Load Strategy should be 'normal', 'eager' or 'none'.")
55-
self._page_load_strategy = value
42+
@use_webview.setter
43+
def use_webview(self, value):
44+
self._use_webview = bool(value)
5645

5746
def to_capabilities(self):
5847
"""
5948
Creates a capabilities with all the options that have been set and
6049
:Returns: A dictionary with everything
6150
"""
62-
if not self._is_legacy:
63-
return_caps = super(Options, self).to_capabilities()
64-
if self._custom_browser_name:
65-
return_caps['browserName'] = self._custom_browser_name
66-
return return_caps
67-
6851
caps = self._caps
69-
caps['pageLoadStrategy'] = self._page_load_strategy
7052

53+
if self._use_chromium:
54+
caps = super(Options, self).to_capabilities()
55+
if self._use_webview:
56+
caps['browserName'] = 'WebView2'
57+
else:
58+
caps['platform'] = 'windows'
59+
60+
caps['ms:edgeChromium'] = self._use_chromium
7161
return caps
7262

7363
@property

‎py/selenium/webdriver/edge/service.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
class Service(service.ChromiumService):
2222

2323
def __init__(self, executable_path, port=0, verbose=False, log_path=None,
24-
is_legacy=True, service_args=None, env=None):
24+
service_args=None, env=None):
2525
"""
2626
Creates a new instance of the EdgeDriver service.
2727
EdgeDriver provides an interface for Microsoft WebDriver to use
@@ -32,19 +32,16 @@ def __init__(self, executable_path, port=0, verbose=False, log_path=None,
3232
- port : Run the remote service on a specified port. Defaults to 0, which binds to a random open port
3333
of the system's choosing.
3434
- verbose : Whether to make the webdriver more verbose (passes the --verbose option to the binary).
35-
Defaults to False. Should be only used for legacy mode.
35+
Defaults to False.
3636
- log_path : Optional path for the webdriver binary to log to. Defaults to None which disables logging.
37-
- is_legacy : Whether to use MicrosoftWebDriver.exe (legacy) or MSEdgeDriver.exe (chromium-based). Defaults to True.
3837
- service_args : List of args to pass to the WebDriver service.
3938
"""
4039
self.service_args = service_args or []
4140

42-
if is_legacy:
43-
if verbose:
44-
self.service_args.append("--verbose")
41+
if verbose:
42+
self.service_args.append("--verbose")
4543

46-
service.ChromiumService.__init__(
47-
self,
44+
super(Service, self).__init__(
4845
executable_path,
4946
port,
5047
service_args,

‎py/selenium/webdriver/edge/webdriver.py

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,52 +14,58 @@
1414
# KIND, either express or implied. See the License for the
1515
# specific language governing permissions and limitations
1616
# under the License.
17-
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
18-
from selenium.webdriver.edge.service import Service
17+
import warnings
1918
from selenium.webdriver.chromium.webdriver import ChromiumDriver
19+
from .options import Options
20+
from .service import Service
21+
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
2022

2123

2224
DEFAULT_PORT = 0
2325
DEFAULT_SERVICE_LOG_PATH = None
2426

2527

2628
class WebDriver(ChromiumDriver):
29+
"""
30+
Controls the Microsoft Edge driver and allows you to drive the browser.
31+
You will need to download either the MicrosoftWebDriver (Legacy)
32+
or MSEdgeDriver (Chromium) executable from
33+
https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
34+
"""
2735

28-
def __init__(self, executable_path='MicrosoftWebDriver.exe',
29-
capabilities=None, port=DEFAULT_PORT, verbose=False,
30-
service_log_path=None, log_path=DEFAULT_SERVICE_LOG_PATH,
31-
service=None, options=None, keep_alive=False, is_legacy=True,
32-
service_args=None):
36+
def __init__(self, executable_path='MicrosoftWebDriver.exe', port=DEFAULT_PORT,
37+
options=None, service_args=None,
38+
capabilities=None, service_log_path=DEFAULT_SERVICE_LOG_PATH,
39+
service=None, keep_alive=False, verbose=False):
3340
"""
3441
Creates a new instance of the edge driver.
3542
Starts the service and then creates new instance of edge driver.
3643
3744
:Args:
3845
- executable_path - Deprecated: path to the executable. If the default is used it assumes the executable is in the $PATH
39-
- capabilities - Dictionary object with non-browser specific capabilities only, such as "proxy" or "loggingPref".
40-
Only available in Legacy mode
4146
- port - Deprecated: port you would like the service to run, if left as 0, a free port will be found.
42-
- verbose - whether to set verbose logging in the service. Only available in Legacy Mode
47+
- options - this takes an instance of EdgeOptions
48+
- service_args - Deprecated: List of args to pass to the driver service
49+
- capabilities - Deprecated: Dictionary object with non-browser specific
50+
capabilities only, such as "proxy" or "loggingPref".
4351
- service_log_path - Deprecated: Where to log information from the driver.
4452
- keep_alive - Whether to configure EdgeRemoteConnection to use HTTP keep-alive.
45-
- service_args - Deprecated: List of args to pass to the driver service
46-
- is_legacy: Whether to use MicrosoftWebDriver.exe (legacy) or MSEdgeDriver.exe (chromium-based). Defaults to True.
53+
- verbose - whether to set verbose logging in the service.
4754
"""
48-
if not is_legacy:
55+
if executable_path != 'MicrosoftWebDriver.exe':
56+
warnings.warn('executable_path has been deprecated, please pass in a Service object',
57+
DeprecationWarning, stacklevel=2)
58+
59+
if options is not None and options.use_chromium:
4960
executable_path = "msedgedriver"
5061

51-
service = service or Service(executable_path,
52-
port=port,
53-
verbose=verbose,
54-
log_path=service_log_path,
55-
is_legacy=is_legacy)
62+
if service is None:
63+
service = Service(executable_path, port, service_args, service_log_path)
64+
65+
super(WebDriver, self).__init__(DesiredCapabilities.EDGE['browserName'], "ms",
66+
port, options,
67+
service_args, capabilities,
68+
service_log_path, service, keep_alive)
5669

57-
super(WebDriver, self).__init__(
58-
executable_path,
59-
port,
60-
options,
61-
service_args,
62-
DesiredCapabilities.EDGE,
63-
service_log_path,
64-
service,
65-
keep_alive)
70+
def create_options(self):
71+
return Options()

‎py/test/unit/selenium/webdriver/edge/edge_options_tests.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ def test_raises_exception_with_invalid_page_load_strategy(options):
3232

3333
def test_set_page_load_strategy(options):
3434
options.page_load_strategy = 'normal'
35-
assert options._page_load_strategy == 'normal'
35+
caps = options.to_capabilities()
36+
assert caps['pageLoadStrategy'] == 'normal'
3637

3738

3839
def test_get_page_load_strategy(options):
39-
options._page_load_strategy = 'normal'
40+
options._caps['pageLoadStrategy'] = 'normal'
4041
assert options.page_load_strategy == 'normal'
4142

4243

@@ -58,8 +59,16 @@ def test_is_a_baseoptions(options):
5859
assert isinstance(options, BaseOptions)
5960

6061

61-
def test_custom_browser_name():
62-
options = Options(is_legacy=False)
63-
options.custom_browser_name = "testbrowsername"
62+
def test_use_chromium():
63+
options = Options()
64+
options.use_chromium = True
65+
caps = options.to_capabilities()
66+
assert caps['ms:edgeChromium'] == True
67+
68+
69+
def test_use_webview():
70+
options = Options()
71+
options.use_chromium = True
72+
options.use_webview = True
6473
caps = options.to_capabilities()
65-
assert caps['browserName'] == "testbrowsername"
74+
assert caps['browserName'] == "WebView2"

0 commit comments

Comments
 (0)
Please sign in to comment.