From 39828fa7786a805f7a542abb929f352d3c5b722c Mon Sep 17 00:00:00 2001 From: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Date: Tue, 16 Apr 2024 09:28:34 +0200 Subject: [PATCH] Added a high contrast mode to screenshot cases. Thank you to Sarah Abderemane and Nick Pope for the reviews. --- django/test/selenium.py | 20 +++++++++++++++++++ .../contributing/writing-code/unit-tests.txt | 11 +++++----- tests/admin_views/tests.py | 10 +++++----- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/django/test/selenium.py b/django/test/selenium.py index 07df34ae1f..eecfd87bf1 100644 --- a/django/test/selenium.py +++ b/django/test/selenium.py @@ -191,6 +191,26 @@ class SeleniumTestCase(LiveServerTestCase, metaclass=SeleniumTestCaseBase): finally: self.selenium.execute_script("localStorage.removeItem('theme');") + def set_emulated_media(self, features, media=""): + if self.browser != "chrome": + self.skipTest("Emulated media controls are only supported on Chrome.") + # Chrome Dev Tools Protocol Emulation.setEmulatedMedia + # https://chromedevtools.github.io/devtools-protocol/1-3/Emulation/#method-setEmulatedMedia + self.selenium.execute_cdp_cmd( + "Emulation.setEmulatedMedia", {"media": media, "features": features} + ) + + @contextmanager + def high_contrast(self): + self.set_emulated_media(features=[{"name": "forced-colors", "value": "active"}]) + with self.desktop_size(): + try: + yield + finally: + self.set_emulated_media( + features=[{"name": "forced-colors", "value": "none"}] + ) + def take_screenshot(self, name): if not self.screenshots: return diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt index 1e86a5802d..ca4029dbfa 100644 --- a/docs/internals/contributing/writing-code/unit-tests.txt +++ b/docs/internals/contributing/writing-code/unit-tests.txt @@ -278,16 +278,16 @@ For testing changes to the admin UI, the selenium tests can be run with the To define when screenshots should be taken during a selenium test, the test class must use the ``@django.test.selenium.screenshot_cases`` decorator with a list of supported screenshot types (``"desktop_size"``, ``"mobile_size"``, -``"small_screen_size"``, ``"rtl"``, and ``"dark"``). It can then call -``self.take_screenshot("unique-screenshot-name")`` at the desired point to -generate the screenshots. For example:: +``"small_screen_size"``, ``"rtl"``, ``"dark"``, and ``"high_contrast"``). It +can then call ``self.take_screenshot("unique-screenshot-name")`` at the desired +point to generate the screenshots. For example:: from django.test.selenium import SeleniumTestCase, screenshot_cases from django.urls import reverse class SeleniumTests(SeleniumTestCase): - @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark"]) + @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"]) def test_login_button_centered(self): self.selenium.get(self.live_server_url + reverse("admin:login")) self.take_screenshot("login") @@ -295,7 +295,8 @@ generate the screenshots. For example:: This generates multiple screenshots of the login page - one for a desktop screen, one for a mobile screen, one for right-to-left languages on desktop, -and one for the dark mode on desktop. +one for the dark mode on desktop, and one for high contrast mode on desktop +when using chrome. .. versionchanged:: 5.1 diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index 5877abf781..5e300de8bc 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -5764,7 +5764,7 @@ class SeleniumTests(AdminSeleniumTestCase): title="A Long Title", published=True, slug="a-long-title" ) - @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark"]) + @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"]) def test_login_button_centered(self): from selenium.webdriver.common.by import By @@ -6070,7 +6070,7 @@ class SeleniumTests(AdminSeleniumTestCase): self.assertEqual(slug1, "this-is-the-main-name-the-best-2012-02-18") self.assertEqual(slug2, "option-two-this-is-the-main-name-the-best") - @screenshot_cases(["desktop_size", "mobile_size", "dark"]) + @screenshot_cases(["desktop_size", "mobile_size", "dark", "high_contrast"]) def test_collapsible_fieldset(self): """ The 'collapse' class in fieldsets definition allows to @@ -6093,7 +6093,7 @@ class SeleniumTests(AdminSeleniumTestCase): ) self.take_screenshot("expanded") - @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark"]) + @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"]) def test_selectbox_height_collapsible_fieldset(self): from selenium.webdriver.common.by import By @@ -6121,7 +6121,7 @@ class SeleniumTests(AdminSeleniumTestCase): ) self.take_screenshot("selectbox-collapsible") - @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark"]) + @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"]) def test_selectbox_height_not_collapsible_fieldset(self): from selenium.webdriver.common.by import By @@ -6152,7 +6152,7 @@ class SeleniumTests(AdminSeleniumTestCase): ) self.take_screenshot("selectbox-non-collapsible") - @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark"]) + @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"]) def test_first_field_focus(self): """JavaScript-assisted auto-focus on first usable form field.""" from selenium.webdriver.common.by import By