test_nav_sidebar.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. from django.contrib import admin
  2. from django.contrib.admin.tests import AdminSeleniumTestCase
  3. from django.contrib.auth.models import User
  4. from django.test import TestCase, override_settings
  5. from django.urls import path, reverse
  6. class AdminSiteWithSidebar(admin.AdminSite):
  7. pass
  8. class AdminSiteWithoutSidebar(admin.AdminSite):
  9. enable_nav_sidebar = False
  10. site_with_sidebar = AdminSiteWithSidebar(name='test_with_sidebar')
  11. site_without_sidebar = AdminSiteWithoutSidebar(name='test_without_sidebar')
  12. site_with_sidebar.register(User)
  13. urlpatterns = [
  14. path('test_sidebar/admin/', site_with_sidebar.urls),
  15. path('test_wihout_sidebar/admin/', site_without_sidebar.urls),
  16. ]
  17. @override_settings(ROOT_URLCONF='admin_views.test_nav_sidebar')
  18. class AdminSidebarTests(TestCase):
  19. @classmethod
  20. def setUpTestData(cls):
  21. cls.superuser = User.objects.create_superuser(
  22. username='super',
  23. password='secret',
  24. email='super@example.com',
  25. )
  26. def setUp(self):
  27. self.client.force_login(self.superuser)
  28. def test_sidebar_not_on_index(self):
  29. response = self.client.get(reverse('test_with_sidebar:index'))
  30. self.assertContains(response, '<div class="main" id="main">')
  31. self.assertNotContains(response, '<nav class="sticky" id="nav-sidebar">')
  32. def test_sidebar_disabled(self):
  33. response = self.client.get(reverse('test_without_sidebar:index'))
  34. self.assertNotContains(response, '<nav class="sticky" id="nav-sidebar">')
  35. def test_sidebar_unauthenticated(self):
  36. self.client.logout()
  37. response = self.client.get(reverse('test_with_sidebar:login'))
  38. self.assertNotContains(response, '<nav class="sticky" id="nav-sidebar">')
  39. def test_sidebar_aria_current_page(self):
  40. url = reverse('test_with_sidebar:auth_user_changelist')
  41. response = self.client.get(url)
  42. self.assertContains(response, '<nav class="sticky" id="nav-sidebar">')
  43. self.assertContains(response, '<a href="%s" aria-current="page">Users</a>' % url)
  44. @override_settings(
  45. TEMPLATES=[{
  46. 'BACKEND': 'django.template.backends.django.DjangoTemplates',
  47. 'DIRS': [],
  48. 'APP_DIRS': True,
  49. 'OPTIONS': {
  50. 'context_processors': [
  51. 'django.contrib.auth.context_processors.auth',
  52. 'django.contrib.messages.context_processors.messages',
  53. ],
  54. },
  55. }]
  56. )
  57. def test_sidebar_aria_current_page_missing_without_request_context_processor(self):
  58. url = reverse('test_with_sidebar:auth_user_changelist')
  59. response = self.client.get(url)
  60. self.assertContains(response, '<nav class="sticky" id="nav-sidebar">')
  61. # Does not include aria-current attribute.
  62. self.assertContains(response, '<a href="%s">Users</a>' % url)
  63. self.assertNotContains(response, 'aria-current')
  64. @override_settings(DEBUG=True)
  65. def test_included_app_list_template_context_fully_set(self):
  66. # All context variables should be set when rendering the sidebar.
  67. url = reverse('test_with_sidebar:auth_user_changelist')
  68. with self.assertNoLogs('django.template', 'DEBUG'):
  69. self.client.get(url)
  70. @override_settings(ROOT_URLCONF='admin_views.test_nav_sidebar')
  71. class SeleniumTests(AdminSeleniumTestCase):
  72. def setUp(self):
  73. self.superuser = User.objects.create_superuser(
  74. username='super',
  75. password='secret',
  76. email='super@example.com',
  77. )
  78. self.admin_login(username='super', password='secret', login_url=reverse('test_with_sidebar:index'))
  79. self.selenium.execute_script("localStorage.removeItem('django.admin.navSidebarIsOpen')")
  80. def test_sidebar_starts_open(self):
  81. self.selenium.get(self.live_server_url + reverse('test_with_sidebar:auth_user_changelist'))
  82. main_element = self.selenium.find_element_by_css_selector('#main')
  83. self.assertIn('shifted', main_element.get_attribute('class').split())
  84. def test_sidebar_can_be_closed(self):
  85. self.selenium.get(self.live_server_url + reverse('test_with_sidebar:auth_user_changelist'))
  86. toggle_button = self.selenium.find_element_by_css_selector('#toggle-nav-sidebar')
  87. self.assertEqual(toggle_button.tag_name, 'button')
  88. self.assertEqual(toggle_button.get_attribute('aria-label'), 'Toggle navigation')
  89. for link in self.selenium.find_elements_by_css_selector('#nav-sidebar a'):
  90. self.assertEqual(link.get_attribute('tabIndex'), '0')
  91. toggle_button.click()
  92. # Hidden sidebar is not reachable via keyboard navigation.
  93. for link in self.selenium.find_elements_by_css_selector('#nav-sidebar a'):
  94. self.assertEqual(link.get_attribute('tabIndex'), '-1')
  95. main_element = self.selenium.find_element_by_css_selector('#main')
  96. self.assertNotIn('shifted', main_element.get_attribute('class').split())
  97. def test_sidebar_state_persists(self):
  98. self.selenium.get(self.live_server_url + reverse('test_with_sidebar:auth_user_changelist'))
  99. self.assertIsNone(self.selenium.execute_script("return localStorage.getItem('django.admin.navSidebarIsOpen')"))
  100. toggle_button = self.selenium.find_element_by_css_selector('#toggle-nav-sidebar')
  101. toggle_button.click()
  102. self.assertEqual(
  103. self.selenium.execute_script("return localStorage.getItem('django.admin.navSidebarIsOpen')"),
  104. 'false',
  105. )
  106. self.selenium.get(self.live_server_url + reverse('test_with_sidebar:auth_user_changelist'))
  107. main_element = self.selenium.find_element_by_css_selector('#main')
  108. self.assertNotIn('shifted', main_element.get_attribute('class').split())
  109. toggle_button = self.selenium.find_element_by_css_selector('#toggle-nav-sidebar')
  110. # Hidden sidebar is not reachable via keyboard navigation.
  111. for link in self.selenium.find_elements_by_css_selector('#nav-sidebar a'):
  112. self.assertEqual(link.get_attribute('tabIndex'), '-1')
  113. toggle_button.click()
  114. for link in self.selenium.find_elements_by_css_selector('#nav-sidebar a'):
  115. self.assertEqual(link.get_attribute('tabIndex'), '0')
  116. self.assertEqual(
  117. self.selenium.execute_script("return localStorage.getItem('django.admin.navSidebarIsOpen')"),
  118. 'true',
  119. )
  120. self.selenium.get(self.live_server_url + reverse('test_with_sidebar:auth_user_changelist'))
  121. main_element = self.selenium.find_element_by_css_selector('#main')
  122. self.assertIn('shifted', main_element.get_attribute('class').split())
  123. def test_sidebar_filter_persists(self):
  124. self.selenium.get(
  125. self.live_server_url +
  126. reverse('test_with_sidebar:auth_user_changelist')
  127. )
  128. filter_value_script = (
  129. "return localStorage.getItem('django.admin.navSidebarFilterValue')"
  130. )
  131. self.assertIsNone(self.selenium.execute_script(filter_value_script))
  132. filter_input = self.selenium.find_element_by_css_selector('#nav-filter')
  133. filter_input.send_keys('users')
  134. self.assertEqual(self.selenium.execute_script(filter_value_script), 'users')