the admin s javascript should be compatible with csp def processresponseself request response response headerscontentsecuritypolicy defaultsrc self return response modifysettingsmiddlewareappend django contrib admin tests cspmiddleware class adminseleniumtestcaseseleniumtestcase staticliveservertestcase availableapps django contrib admin django contrib auth django contrib contenttypes django contrib sessions django contrib sites def waituntilself callback timeout10 from selenium webdriver support wait import webdriverwait webdriverwaitself selenium timeout untilcallback def waitforandswitchtopopupself numwindows2 timeout10 self waituntillambda d lend windowhandles numwindows timeout self selenium switchto windowself selenium windowhandles1 self waitpageready def waitforself cssselector timeout10 from selenium webdriver common by import by from selenium webdriver support import expectedconditions as ec self waituntil ec presenceofelementlocatedby cssselector cssselector timeout def waitfortextself cssselector text timeout10 from selenium webdriver common by import by from selenium webdriver support import expectedconditions as ec self waituntil ec texttobepresentinelementby cssselector cssselector text timeout def waitforvalueself cssselector text timeout10 from selenium webdriver common by import by from selenium webdriver support import expectedconditions as ec self waituntil ec texttobepresentinelementvalue by cssselector cssselector text timeout def waituntilvisibleself cssselector timeout10 from selenium webdriver common by import by from selenium webdriver support import expectedconditions as ec self waituntil ec visibilityofelementlocatedby cssselector cssselector timeout def waituntilinvisibleself cssselector timeout10 from selenium webdriver common by import by from selenium webdriver support import expectedconditions as ec self waituntil ec invisibilityofelementlocatedby cssselector cssselector timeout def waitpagereadyself timeout10 self waituntil lambda driver driver executescriptreturn document readystate complete timeout contextmanager def waitpageloadedself timeout10 from selenium webdriver common by import by from selenium webdriver support import expectedconditions as ec oldpage self selenium findelementby tagname html yield wait for the next page to be loaded self waituntilec stalenessofoldpage timeouttimeout self waitpagereadytimeouttimeout def adminloginself username password loginurladmin from selenium webdriver common by import by self selenium getss self liveserverurl loginurl usernameinput self selenium findelementby name username usernameinput sendkeysusername passwordinput self selenium findelementby name password passwordinput sendkeyspassword logintext log in with self waitpageloaded self selenium findelement by xpath inputvalues logintext click def selectoptionself selector value from selenium webdriver common by import by from selenium webdriver support ui import select select selectself selenium findelementby cssselector selector select selectbyvaluevalue def deselectoptionself selector value from selenium webdriver common by import by from selenium webdriver support ui import select select selectself selenium findelementby cssselector selector select deselectbyvaluevalue def assertcountseleniumelementsself selector count rootelementnone from selenium webdriver common by import by rootelement rootelement or self selenium self assertequal lenrootelement findelementsby cssselector selector count def assertoptionsvaluesself optionsselector values from selenium webdriver common by import by if values options self selenium findelementsby cssselector optionsselector actualvalues for option in options actualvalues appendoption getattributevalue self assertequalvalues actualvalues else prevent the findelementsby cssselector call from blocking if the selector doesn t match any options as we expect it to be the case with self disableimplicitwait self waituntil lambda driver not driver findelements by cssselector optionsselector def assertselectoptionsself selector values self assertoptionsvaluess option selector values def assertselectedoptionsself selector values self assertoptionsvaluess option checked selector values def hascssclassself selector klass from selenium webdriver common by import by return self selenium findelement by cssselector selector getattributeclass findklass 1 the admin s javascript should be compatible with csp block the execution of the tests until the specified callback returns a value that is not falsy this method can be called for example after clicking a link or submitting a form see the other public methods that call this function for more details block until num_windows are present and are ready usually 2 but can be overridden in the case of pop ups opening other pop ups switch the current window to the new pop up block until a css selector is found on the page block until the text is found in the css selector block until the value is found in the css selector block until the element described by the css selector is visible block until the element described by the css selector is invisible block until the page is ready block until a new page has loaded and is ready wait for the next page to be loaded log in to the admin select the option with the value value inside the select widget identified by the css selector selector deselect the option with the value value inside the select widget identified by the css selector selector assert number of matches for a css selector root_element allow restriction to a pre selected node prevent the find_elements by css_selector call from blocking if the selector doesn t match any options as we expect it to be the case assert that the select widget identified by selector has the options with the given values assert that the select widget identified by selector has the selected options with the given values return true if the element identified by selector has the css class klass
from contextlib import contextmanager

from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from django.test import modify_settings
from django.test.selenium import SeleniumTestCase
from django.utils.deprecation import MiddlewareMixin
from django.utils.translation import gettext as _


class CSPMiddleware(MiddlewareMixin):
    

    def process_response(self, request, response):
        response.headers["Content-Security-Policy"] = "default-src 'self'"
        return response


@modify_settings(MIDDLEWARE={"append": "django.contrib.admin.tests.CSPMiddleware"})
class AdminSeleniumTestCase(SeleniumTestCase, StaticLiveServerTestCase):
    available_apps = [
        "django.contrib.admin",
        "django.contrib.auth",
        "django.contrib.contenttypes",
        "django.contrib.sessions",
        "django.contrib.sites",
    ]

    def wait_until(self, callback, timeout=10):
        
        from selenium.webdriver.support.wait import WebDriverWait

        WebDriverWait(self.selenium, timeout).until(callback)

    def wait_for_and_switch_to_popup(self, num_windows=2, timeout=10):
        
        self.wait_until(lambda d: len(d.window_handles) == num_windows, timeout)
        self.selenium.switch_to.window(self.selenium.window_handles[-1])
        self.wait_page_ready()

    def wait_for(self, css_selector, timeout=10):
        
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support import expected_conditions as ec

        self.wait_until(
            ec.presence_of_element_located((By.CSS_SELECTOR, css_selector)), timeout
        )

    def wait_for_text(self, css_selector, text, timeout=10):
        
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support import expected_conditions as ec

        self.wait_until(
            ec.text_to_be_present_in_element((By.CSS_SELECTOR, css_selector), text),
            timeout,
        )

    def wait_for_value(self, css_selector, text, timeout=10):
        
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support import expected_conditions as ec

        self.wait_until(
            ec.text_to_be_present_in_element_value(
                (By.CSS_SELECTOR, css_selector), text
            ),
            timeout,
        )

    def wait_until_visible(self, css_selector, timeout=10):
        
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support import expected_conditions as ec

        self.wait_until(
            ec.visibility_of_element_located((By.CSS_SELECTOR, css_selector)), timeout
        )

    def wait_until_invisible(self, css_selector, timeout=10):
        
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support import expected_conditions as ec

        self.wait_until(
            ec.invisibility_of_element_located((By.CSS_SELECTOR, css_selector)), timeout
        )

    def wait_page_ready(self, timeout=10):
        
        self.wait_until(
            lambda driver: driver.execute_script("return document.readyState;")
            == "complete",
            timeout,
        )

    @contextmanager
    def wait_page_loaded(self, timeout=10):
        
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support import expected_conditions as ec

        old_page = self.selenium.find_element(By.TAG_NAME, "html")
        yield
        
        self.wait_until(ec.staleness_of(old_page), timeout=timeout)
        self.wait_page_ready(timeout=timeout)

    def admin_login(self, username, password, login_url="/admin/"):
        
        from selenium.webdriver.common.by import By

        self.selenium.get("%s%s" % (self.live_server_url, login_url))
        username_input = self.selenium.find_element(By.NAME, "username")
        username_input.send_keys(username)
        password_input = self.selenium.find_element(By.NAME, "password")
        password_input.send_keys(password)
        login_text = _("Log in")
        with self.wait_page_loaded():
            self.selenium.find_element(
                By.XPATH, '//input[@value="%s"]' % login_text
            ).click()

    def select_option(self, selector, value):
        
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support.ui import Select

        select = Select(self.selenium.find_element(By.CSS_SELECTOR, selector))
        select.select_by_value(value)

    def deselect_option(self, selector, value):
        
        from selenium.webdriver.common.by import By
        from selenium.webdriver.support.ui import Select

        select = Select(self.selenium.find_element(By.CSS_SELECTOR, selector))
        select.deselect_by_value(value)

    def assertCountSeleniumElements(self, selector, count, root_element=None):
        
        from selenium.webdriver.common.by import By

        root_element = root_element or self.selenium
        self.assertEqual(
            len(root_element.find_elements(By.CSS_SELECTOR, selector)), count
        )

    def _assertOptionsValues(self, options_selector, values):
        from selenium.webdriver.common.by import By

        if values:
            options = self.selenium.find_elements(By.CSS_SELECTOR, options_selector)
            actual_values = []
            for option in options:
                actual_values.append(option.get_attribute("value"))
            self.assertEqual(values, actual_values)
        else:
            
            
            
            with self.disable_implicit_wait():
                self.wait_until(
                    lambda driver: not driver.find_elements(
                        By.CSS_SELECTOR, options_selector
                    )
                )

    def assertSelectOptions(self, selector, values):
        
        self._assertOptionsValues("%s > option" % selector, values)

    def assertSelectedOptions(self, selector, values):
        
        self._assertOptionsValues("%s > option:checked" % selector, values)

    def has_css_class(self, selector, klass):
        
        from selenium.webdriver.common.by import By

        return (
            self.selenium.find_element(
                By.CSS_SELECTOR,
                selector,
            )
            .get_attribute("class")
            .find(klass)
            != -1
        )