From a18cf0568268fb989ba1c3af7a4b5553cb7acd9c Mon Sep 17 00:00:00 2001 From: Dhruv Maniya Date: Fri, 10 Jul 2026 19:33:18 +0530 Subject: [PATCH] [tests] Add ChromeDriver log output #717 Allow Selenium tests to write verbose ChromeDriver logs when CHROMEDRIVER_LOG is set.\n\nFixes #717 --- docs/developer/test-utilities.rst | 2 ++ openwisp_utils/tests/selenium.py | 12 ++++++-- .../test_project/tests/test_selenium_mixin.py | 29 +++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/docs/developer/test-utilities.rst b/docs/developer/test-utilities.rst index 772cb35a..77205ae8 100644 --- a/docs/developer/test-utilities.rst +++ b/docs/developer/test-utilities.rst @@ -268,6 +268,8 @@ Applies a number of settings by default to improve test reliability. - Uses the ``CHROME_BIN`` environment variable to specify a custom Chrome binary location. + - Uses the ``CHROMEDRIVER_LOG`` environment variable to enable verbose + ChromeDriver logging to ``chromedriver.log``. - Uses ``page_load_strategy = "eager"`` to start interacting with the page before it's fully loaded. - Adds flags: ``--ignore-certificate-errors``, ``--no-sandbox``, diff --git a/openwisp_utils/tests/selenium.py b/openwisp_utils/tests/selenium.py index 30c7333f..77ba7c11 100644 --- a/openwisp_utils/tests/selenium.py +++ b/openwisp_utils/tests/selenium.py @@ -277,9 +277,15 @@ def get_chrome_webdriver(cls): # generate a unique port for each browser instance. options.add_argument(f"--remote-debugging-port={free_port()}") options.set_capability("goog:loggingPrefs", {"browser": "ALL"}) - return webdriver.Chrome( - options=options, - ) + kwargs = dict(options=options) + # Optional: Store ChromeDriver logs in a file. + # Pass CHROMEDRIVER_LOG=1 when running tests. + CHROMEDRIVER_LOG = os.environ.get("CHROMEDRIVER_LOG", None) + if CHROMEDRIVER_LOG: + kwargs["service"] = webdriver.ChromeService( + service_args=["--verbose"], log_output="chromedriver.log" + ) + return webdriver.Chrome(**kwargs) def setUp(self): self.admin = self._create_admin( diff --git a/tests/test_project/tests/test_selenium_mixin.py b/tests/test_project/tests/test_selenium_mixin.py index b0488101..79733d8e 100644 --- a/tests/test_project/tests/test_selenium_mixin.py +++ b/tests/test_project/tests/test_selenium_mixin.py @@ -1,7 +1,9 @@ import importlib +import os import sys from types import ModuleType from unittest import TestResult, TestSuite, skip +from unittest.mock import patch from django.conf import settings from django.db.backends.base.base import BaseDatabaseWrapper @@ -25,6 +27,33 @@ def setUp(self): pass +class TestChromeWebDriverLogging(SimpleTestCase): + @patch("openwisp_utils.tests.selenium.webdriver.Chrome") + @patch("openwisp_utils.tests.selenium.webdriver.ChromeService") + def test_chromedriver_log_enables_verbose_file_logging( + self, chrome_service, chrome + ): + with patch.dict(os.environ, {"CHROMEDRIVER_LOG": "1"}): + SeleniumTestMixin.get_chrome_webdriver() + + chrome_service.assert_called_once_with( + service_args=["--verbose"], log_output="chromedriver.log" + ) + chrome.assert_called_once_with( + options=chrome.call_args.kwargs["options"], + service=chrome_service.return_value, + ) + + @patch("openwisp_utils.tests.selenium.webdriver.Chrome") + @patch("openwisp_utils.tests.selenium.webdriver.ChromeService") + def test_chromedriver_log_is_opt_in(self, chrome_service, chrome): + with patch.dict(os.environ, {}, clear=True): + SeleniumTestMixin.get_chrome_webdriver() + + chrome_service.assert_not_called() + chrome.assert_called_once_with(options=chrome.call_args.kwargs["options"]) + + class TestSeleniumMixinSkipHandling(SimpleTestCase): def _run_skipped_standard_test(self): class SkippedSeleniumTest(SeleniumTestMixin, SimpleTestCase):