diff --git a/python.iml b/python.iml index 3c8cbb09..7e39384d 100644 --- a/python.iml +++ b/python.iml @@ -5,13 +5,17 @@ <configuration sdkName="" /> </facet> </component> + <component name="ModuleRunConfigurationManager"> + <shared /> + </component> <component name="NewModuleRootManager" inherit-compiler-output="true"> <exclude-output /> <content url="file://$MODULE_DIR$"> <sourceFolder url="file://$MODULE_DIR$/selenium" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" /> + <excludeFolder url="file://$MODULE_DIR$/venv" /> </content> - <orderEntry type="jdk" jdkName="Python 2.7" jdkType="Python SDK" /> + <orderEntry type="jdk" jdkName="Python 3.9 (py)" jdkType="Python SDK" /> <orderEntry type="sourceFolder" forTests="false" /> </component> <component name="sonarModuleSettings"> diff --git a/selenium/webdriver/common/options.py b/selenium/webdriver/common/options.py index 601bdb10..2d8e4b8b 100644 --- a/selenium/webdriver/common/options.py +++ b/selenium/webdriver/common/options.py @@ -44,7 +44,7 @@ class BaseOptions(metaclass=ABCMeta): """ :returns: the version of the browser if set, otherwise None. """ - return self._caps["browserVersion"] + return self._caps.get("browserVersion") @browser_version.setter def browser_version(self, version: str) -> None: diff --git a/selenium/webdriver/common/selenium_manager.py b/selenium/webdriver/common/selenium_manager.py index 8eb2909f..15e64d41 100644 --- a/selenium/webdriver/common/selenium_manager.py +++ b/selenium/webdriver/common/selenium_manager.py @@ -19,7 +19,7 @@ import logging import subprocess import sys from pathlib import Path -from typing import Tuple +from typing import List from selenium.common.exceptions import SeleniumManagerException from selenium.webdriver.common.options import BaseOptions @@ -87,20 +87,19 @@ class SeleniumManager: browser = allowed_browsers[browser] - binary, browser_flag, browser, output_flag, output = ( - str(self.get_binary()), - "--browser", - browser, - "--output", - "json", - ) - result = self.run((binary, browser_flag, browser, output_flag, output)) + args = [str(self.get_binary()), "--browser", browser, "--output", "json"] + + if options.browser_version: + args.append("--browser-version") + args.append(str(options.browser_version)) + + result = self.run(args) executable = result.split("\t")[-1].strip() logger.debug(f"Using driver at: {executable}") return executable @staticmethod - def run(args: Tuple[str, str, str, str, str]) -> str: + def run(args: List[str]) -> str: """ Executes the Selenium Manager Binary. :Args: @@ -108,16 +107,16 @@ class SeleniumManager: :Returns: The log string containing the driver location. """ command = " ".join(args) - logger.debug(f"Executing: {command}") + logger.info(f"Executing: {command}") completed_proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = completed_proc.stdout.decode("utf-8").rstrip("\n") stderr = completed_proc.stderr.decode("utf-8").rstrip("\n") output = json.loads(stdout) result = output["result"]["message"] if completed_proc.returncode: - raise SeleniumManagerException(f"Selenium manager failed for: {command}.\n{result}{stderr}") + raise SeleniumManagerException(f"Selenium Manager failed for: {command}.\n{result}{stderr}") else: - # Selenium Manager exited 0 successfully, return executable path and print warnings (if any) + # Selenium Manager exited successfully, return executable path and print warnings for item in output["logs"]: if item["level"] == "WARN": logger.warning(item["message"]) diff --git a/test/selenium/webdriver/common/selenium_manager_tests.py b/test/selenium/webdriver/common/selenium_manager_tests.py index 1af705f5..e3d6de5b 100644 --- a/test/selenium/webdriver/common/selenium_manager_tests.py +++ b/test/selenium/webdriver/common/selenium_manager_tests.py @@ -15,6 +15,8 @@ # specific language governing permissions and limitations # under the License. +from unittest.mock import Mock + import pytest from selenium.common.exceptions import SeleniumManagerException @@ -30,9 +32,28 @@ def test_non_supported_browser_raises_sme(): _ = SeleniumManager().driver_location(options) +def test_browser_version_is_used_for_sm(mocker): + import subprocess + + mock_run = mocker.patch("subprocess.run") + mocked_result = Mock() + mocked_result.configure_mock( + **{"stdout.decode.return_value": '{"result": {"message": "driver"}, "logs": []}', "returncode": 0} + ) + mock_run.return_value = mocked_result + options = Options() + options.capabilities["browserName"] = "chrome" + options.browser_version = 110 + + _ = SeleniumManager().driver_location(options) + args, kwargs = subprocess.run.call_args + assert "--browser-version" in args[0] + assert "110" in args[0] + + def test_stderr_is_propagated_to_exception_messages(): - msg = r"Selenium manager failed for:.* --browser foo --output json\.\nInvalid browser name: foo\n" + msg = r"Selenium Manager failed for:.* --browser foo --output json\.\nInvalid browser name: foo\n" with pytest.raises(SeleniumManagerException, match=msg): manager = SeleniumManager() binary = manager.get_binary() - _ = manager.run((str(binary), "--browser", "foo", "--output", "json")) + _ = manager.run([str(binary), "--browser", "foo", "--output", "json"])