2020-05-06 16:29:51 +08:00
|
|
|
from django.contrib import admin
|
|
|
|
from django.contrib.admin.tests import AdminSeleniumTestCase
|
|
|
|
from django.contrib.auth.models import User
|
|
|
|
from django.test import TestCase, override_settings
|
|
|
|
from django.urls import path, reverse
|
|
|
|
|
2021-08-26 23:43:40 +08:00
|
|
|
from .models import Héllo
|
|
|
|
|
2020-05-06 16:29:51 +08:00
|
|
|
|
|
|
|
class AdminSiteWithSidebar(admin.AdminSite):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class AdminSiteWithoutSidebar(admin.AdminSite):
|
|
|
|
enable_nav_sidebar = False
|
|
|
|
|
|
|
|
|
|
|
|
site_with_sidebar = AdminSiteWithSidebar(name="test_with_sidebar")
|
|
|
|
site_without_sidebar = AdminSiteWithoutSidebar(name="test_without_sidebar")
|
|
|
|
|
|
|
|
site_with_sidebar.register(User)
|
2021-08-26 23:43:40 +08:00
|
|
|
site_with_sidebar.register(Héllo)
|
2020-05-06 16:29:51 +08:00
|
|
|
|
|
|
|
urlpatterns = [
|
|
|
|
path("test_sidebar/admin/", site_with_sidebar.urls),
|
|
|
|
path("test_wihout_sidebar/admin/", site_without_sidebar.urls),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
@override_settings(ROOT_URLCONF="admin_views.test_nav_sidebar")
|
|
|
|
class AdminSidebarTests(TestCase):
|
|
|
|
@classmethod
|
|
|
|
def setUpTestData(cls):
|
|
|
|
cls.superuser = User.objects.create_superuser(
|
|
|
|
username="super",
|
|
|
|
password="secret",
|
|
|
|
email="super@example.com",
|
|
|
|
)
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
self.client.force_login(self.superuser)
|
|
|
|
|
|
|
|
def test_sidebar_not_on_index(self):
|
|
|
|
response = self.client.get(reverse("test_with_sidebar:index"))
|
2021-02-18 16:18:19 +08:00
|
|
|
self.assertContains(response, '<div class="main" id="main">')
|
2020-05-06 16:29:51 +08:00
|
|
|
self.assertNotContains(response, '<nav class="sticky" id="nav-sidebar">')
|
|
|
|
|
|
|
|
def test_sidebar_disabled(self):
|
|
|
|
response = self.client.get(reverse("test_without_sidebar:index"))
|
|
|
|
self.assertNotContains(response, '<nav class="sticky" id="nav-sidebar">')
|
|
|
|
|
|
|
|
def test_sidebar_unauthenticated(self):
|
|
|
|
self.client.logout()
|
|
|
|
response = self.client.get(reverse("test_with_sidebar:login"))
|
|
|
|
self.assertNotContains(response, '<nav class="sticky" id="nav-sidebar">')
|
|
|
|
|
|
|
|
def test_sidebar_aria_current_page(self):
|
2020-05-14 16:27:35 +08:00
|
|
|
url = reverse("test_with_sidebar:auth_user_changelist")
|
|
|
|
response = self.client.get(url)
|
2020-05-06 16:29:51 +08:00
|
|
|
self.assertContains(response, '<nav class="sticky" id="nav-sidebar">')
|
2020-05-14 16:27:35 +08:00
|
|
|
self.assertContains(
|
|
|
|
response, '<a href="%s" aria-current="page">Users</a>' % url
|
|
|
|
)
|
|
|
|
|
|
|
|
@override_settings(
|
|
|
|
TEMPLATES=[
|
|
|
|
{
|
|
|
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
|
|
|
"DIRS": [],
|
|
|
|
"APP_DIRS": True,
|
|
|
|
"OPTIONS": {
|
|
|
|
"context_processors": [
|
|
|
|
"django.contrib.auth.context_processors.auth",
|
|
|
|
"django.contrib.messages.context_processors.messages",
|
|
|
|
],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
]
|
|
|
|
)
|
|
|
|
def test_sidebar_aria_current_page_missing_without_request_context_processor(self):
|
|
|
|
url = reverse("test_with_sidebar:auth_user_changelist")
|
|
|
|
response = self.client.get(url)
|
|
|
|
self.assertContains(response, '<nav class="sticky" id="nav-sidebar">')
|
|
|
|
# Does not include aria-current attribute.
|
|
|
|
self.assertContains(response, '<a href="%s">Users</a>' % url)
|
|
|
|
self.assertNotContains(response, "aria-current")
|
2020-05-06 16:29:51 +08:00
|
|
|
|
2020-08-11 16:11:42 +08:00
|
|
|
@override_settings(DEBUG=True)
|
|
|
|
def test_included_app_list_template_context_fully_set(self):
|
|
|
|
# All context variables should be set when rendering the sidebar.
|
|
|
|
url = reverse("test_with_sidebar:auth_user_changelist")
|
2021-01-08 00:54:40 +08:00
|
|
|
with self.assertNoLogs("django.template", "DEBUG"):
|
|
|
|
self.client.get(url)
|
2020-08-11 16:11:42 +08:00
|
|
|
|
2021-08-26 23:43:40 +08:00
|
|
|
def test_sidebar_model_name_non_ascii(self):
|
|
|
|
url = reverse("test_with_sidebar:admin_views_héllo_changelist")
|
|
|
|
response = self.client.get(url)
|
|
|
|
self.assertContains(
|
|
|
|
response, '<div class="app-admin_views module current-app">'
|
|
|
|
)
|
|
|
|
self.assertContains(response, '<tr class="model-héllo current-model">')
|
|
|
|
self.assertContains(
|
|
|
|
response,
|
|
|
|
'<th scope="row">'
|
|
|
|
'<a href="/test_sidebar/admin/admin_views/h%C3%A9llo/" aria-current="page">'
|
|
|
|
"Héllos</a></th>",
|
|
|
|
)
|
|
|
|
|
2020-05-06 16:29:51 +08:00
|
|
|
|
|
|
|
@override_settings(ROOT_URLCONF="admin_views.test_nav_sidebar")
|
|
|
|
class SeleniumTests(AdminSeleniumTestCase):
|
2021-08-26 23:43:40 +08:00
|
|
|
available_apps = ["admin_views"] + AdminSeleniumTestCase.available_apps
|
|
|
|
|
2020-05-06 16:29:51 +08:00
|
|
|
def setUp(self):
|
|
|
|
self.superuser = User.objects.create_superuser(
|
|
|
|
username="super",
|
|
|
|
password="secret",
|
|
|
|
email="super@example.com",
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2020-05-06 16:29:51 +08:00
|
|
|
self.admin_login(
|
|
|
|
username="super",
|
|
|
|
password="secret",
|
|
|
|
login_url=reverse("test_with_sidebar:index"),
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2020-05-06 16:29:51 +08:00
|
|
|
self.selenium.execute_script(
|
|
|
|
"localStorage.removeItem('django.admin.navSidebarIsOpen')"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_sidebar_starts_open(self):
|
2021-10-20 21:54:30 +08:00
|
|
|
from selenium.webdriver.common.by import By
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2020-05-06 16:29:51 +08:00
|
|
|
self.selenium.get(
|
|
|
|
self.live_server_url + reverse("test_with_sidebar:auth_user_changelist")
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2021-10-20 21:54:30 +08:00
|
|
|
main_element = self.selenium.find_element(By.CSS_SELECTOR, "#main")
|
2020-05-06 16:29:51 +08:00
|
|
|
self.assertIn("shifted", main_element.get_attribute("class").split())
|
|
|
|
|
|
|
|
def test_sidebar_can_be_closed(self):
|
2021-10-20 21:54:30 +08:00
|
|
|
from selenium.webdriver.common.by import By
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2020-05-06 16:29:51 +08:00
|
|
|
self.selenium.get(
|
|
|
|
self.live_server_url + reverse("test_with_sidebar:auth_user_changelist")
|
2021-10-20 21:54:30 +08:00
|
|
|
)
|
|
|
|
toggle_button = self.selenium.find_element(
|
|
|
|
By.CSS_SELECTOR, "#toggle-nav-sidebar"
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2020-05-16 20:16:56 +08:00
|
|
|
self.assertEqual(toggle_button.tag_name, "button")
|
|
|
|
self.assertEqual(toggle_button.get_attribute("aria-label"), "Toggle navigation")
|
2021-10-20 21:54:30 +08:00
|
|
|
for link in self.selenium.find_elements(By.CSS_SELECTOR, "#nav-sidebar a"):
|
2020-05-16 20:16:56 +08:00
|
|
|
self.assertEqual(link.get_attribute("tabIndex"), "0")
|
2022-05-23 12:06:37 +08:00
|
|
|
filter_input = self.selenium.find_element(By.CSS_SELECTOR, "#nav-filter")
|
2022-05-20 22:21:31 +08:00
|
|
|
self.assertEqual(filter_input.get_attribute("tabIndex"), "0")
|
2020-05-06 16:29:51 +08:00
|
|
|
toggle_button.click()
|
2020-05-16 20:16:56 +08:00
|
|
|
# Hidden sidebar is not reachable via keyboard navigation.
|
2021-10-20 21:54:30 +08:00
|
|
|
for link in self.selenium.find_elements(By.CSS_SELECTOR, "#nav-sidebar a"):
|
2020-05-16 20:16:56 +08:00
|
|
|
self.assertEqual(link.get_attribute("tabIndex"), "-1")
|
2022-05-23 12:06:37 +08:00
|
|
|
filter_input = self.selenium.find_element(By.CSS_SELECTOR, "#nav-filter")
|
2022-05-20 22:21:31 +08:00
|
|
|
self.assertEqual(filter_input.get_attribute("tabIndex"), "-1")
|
2021-10-20 21:54:30 +08:00
|
|
|
main_element = self.selenium.find_element(By.CSS_SELECTOR, "#main")
|
2020-05-06 16:29:51 +08:00
|
|
|
self.assertNotIn("shifted", main_element.get_attribute("class").split())
|
|
|
|
|
|
|
|
def test_sidebar_state_persists(self):
|
2021-10-20 21:54:30 +08:00
|
|
|
from selenium.webdriver.common.by import By
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2020-05-06 16:29:51 +08:00
|
|
|
self.selenium.get(
|
|
|
|
self.live_server_url + reverse("test_with_sidebar:auth_user_changelist")
|
|
|
|
)
|
|
|
|
self.assertIsNone(
|
|
|
|
self.selenium.execute_script(
|
|
|
|
"return localStorage.getItem('django.admin.navSidebarIsOpen')"
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2021-10-20 21:54:30 +08:00
|
|
|
)
|
|
|
|
toggle_button = self.selenium.find_element(
|
|
|
|
By.CSS_SELECTOR, "#toggle-nav-sidebar"
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2020-05-06 16:29:51 +08:00
|
|
|
toggle_button.click()
|
|
|
|
self.assertEqual(
|
|
|
|
self.selenium.execute_script(
|
|
|
|
"return localStorage.getItem('django.admin.navSidebarIsOpen')"
|
|
|
|
),
|
|
|
|
"false",
|
|
|
|
)
|
|
|
|
self.selenium.get(
|
|
|
|
self.live_server_url + reverse("test_with_sidebar:auth_user_changelist")
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2021-10-20 21:54:30 +08:00
|
|
|
main_element = self.selenium.find_element(By.CSS_SELECTOR, "#main")
|
2020-05-06 16:29:51 +08:00
|
|
|
self.assertNotIn("shifted", main_element.get_attribute("class").split())
|
|
|
|
|
2021-10-20 21:54:30 +08:00
|
|
|
toggle_button = self.selenium.find_element(
|
|
|
|
By.CSS_SELECTOR, "#toggle-nav-sidebar"
|
|
|
|
)
|
2020-05-16 20:16:56 +08:00
|
|
|
# Hidden sidebar is not reachable via keyboard navigation.
|
2021-10-20 21:54:30 +08:00
|
|
|
for link in self.selenium.find_elements(By.CSS_SELECTOR, "#nav-sidebar a"):
|
2020-05-16 20:16:56 +08:00
|
|
|
self.assertEqual(link.get_attribute("tabIndex"), "-1")
|
2022-05-23 12:06:37 +08:00
|
|
|
filter_input = self.selenium.find_element(By.CSS_SELECTOR, "#nav-filter")
|
2022-05-20 22:21:31 +08:00
|
|
|
self.assertEqual(filter_input.get_attribute("tabIndex"), "-1")
|
2020-05-06 16:29:51 +08:00
|
|
|
toggle_button.click()
|
2021-10-20 21:54:30 +08:00
|
|
|
for link in self.selenium.find_elements(By.CSS_SELECTOR, "#nav-sidebar a"):
|
2020-05-16 20:16:56 +08:00
|
|
|
self.assertEqual(link.get_attribute("tabIndex"), "0")
|
2022-05-23 12:06:37 +08:00
|
|
|
filter_input = self.selenium.find_element(By.CSS_SELECTOR, "#nav-filter")
|
2022-05-20 22:21:31 +08:00
|
|
|
self.assertEqual(filter_input.get_attribute("tabIndex"), "0")
|
2020-05-06 16:29:51 +08:00
|
|
|
self.assertEqual(
|
|
|
|
self.selenium.execute_script(
|
|
|
|
"return localStorage.getItem('django.admin.navSidebarIsOpen')"
|
|
|
|
),
|
|
|
|
"true",
|
|
|
|
)
|
|
|
|
self.selenium.get(
|
|
|
|
self.live_server_url + reverse("test_with_sidebar:auth_user_changelist")
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2021-10-20 21:54:30 +08:00
|
|
|
main_element = self.selenium.find_element(By.CSS_SELECTOR, "#main")
|
2020-05-06 16:29:51 +08:00
|
|
|
self.assertIn("shifted", main_element.get_attribute("class").split())
|
2020-12-04 19:50:11 +08:00
|
|
|
|
|
|
|
def test_sidebar_filter_persists(self):
|
2021-10-20 21:54:30 +08:00
|
|
|
from selenium.webdriver.common.by import By
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2020-12-04 19:50:11 +08:00
|
|
|
self.selenium.get(
|
|
|
|
self.live_server_url + reverse("test_with_sidebar:auth_user_changelist")
|
|
|
|
)
|
|
|
|
filter_value_script = (
|
2021-10-06 15:01:31 +08:00
|
|
|
"return sessionStorage.getItem('django.admin.navSidebarFilterValue')"
|
2020-12-04 19:50:11 +08:00
|
|
|
)
|
|
|
|
self.assertIsNone(self.selenium.execute_script(filter_value_script))
|
2021-10-20 21:54:30 +08:00
|
|
|
filter_input = self.selenium.find_element(By.CSS_SELECTOR, "#nav-filter")
|
2020-12-04 19:50:11 +08:00
|
|
|
filter_input.send_keys("users")
|
|
|
|
self.assertEqual(self.selenium.execute_script(filter_value_script), "users")
|