1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
from django.contrib.admin.tests import AdminSeleniumTestCase
from django.contrib.auth.models import User
from django.test import override_settings
from django.urls import reverse
from .models import Podcast
@override_settings(ROOT_URLCONF="admin_views.urls")
class SeleniumTests(AdminSeleniumTestCase):
available_apps = ["admin_views"] + AdminSeleniumTestCase.available_apps
def setUp(self):
self.superuser = User.objects.create_superuser(
username="super",
password="secret",
email="super@example.com",
)
def test_use_skip_link_to_content(self):
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
self.admin_login(
username="super",
password="secret",
login_url=reverse("admin:index"),
)
# `Skip link` is not present.
skip_link = self.selenium.find_element(By.CLASS_NAME, "skip-to-content-link")
self.assertFalse(skip_link.is_displayed())
# 1st TAB is pressed, `skip link` is shown.
body = self.selenium.find_element(By.TAG_NAME, "body")
body.send_keys(Keys.TAB)
self.assertTrue(skip_link.is_displayed())
# Press RETURN to skip the navbar links (view site / documentation /
# change password / log out) and focus first model in the admin_views
# list.
skip_link.send_keys(Keys.RETURN)
self.assertFalse(skip_link.is_displayed()) # `skip link` disappear.
keys = [Keys.TAB, Keys.TAB] # The 1st TAB is the section title.
if self.browser == "firefox":
# For some reason Firefox doesn't focus the section title
# ('ADMIN_VIEWS').
keys.remove(Keys.TAB)
body.send_keys(keys)
actors_a_tag = self.selenium.find_element(By.LINK_TEXT, "Actors")
self.assertEqual(self.selenium.switch_to.active_element, actors_a_tag)
# Go to Actors changelist, skip sidebar and focus "Add actor +".
with self.wait_page_loaded():
actors_a_tag.send_keys(Keys.RETURN)
body = self.selenium.find_element(By.TAG_NAME, "body")
body.send_keys(Keys.TAB)
skip_link = self.selenium.find_element(By.CLASS_NAME, "skip-to-content-link")
self.assertTrue(skip_link.is_displayed())
ActionChains(self.selenium).send_keys(Keys.RETURN, Keys.TAB).perform()
actors_add_url = reverse("admin:admin_views_actor_add")
actors_a_tag = self.selenium.find_element(
By.CSS_SELECTOR, f"#content [href='{actors_add_url}']"
)
self.assertEqual(self.selenium.switch_to.active_element, actors_a_tag)
# Go to the Actor form and the first input will be focused
# automatically.
with self.wait_page_loaded():
actors_a_tag.send_keys(Keys.RETURN)
first_input = self.selenium.find_element(By.ID, "id_name")
self.assertEqual(self.selenium.switch_to.active_element, first_input)
def test_dont_use_skip_link_to_content(self):
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
self.admin_login(
username="super",
password="secret",
login_url=reverse("admin:index"),
)
# `Skip link` is not present.
skip_link = self.selenium.find_element(By.CLASS_NAME, "skip-to-content-link")
self.assertFalse(skip_link.is_displayed())
# 1st TAB is pressed, `skip link` is shown.
body = self.selenium.find_element(By.TAG_NAME, "body")
body.send_keys(Keys.TAB)
self.assertTrue(skip_link.is_displayed())
# The 2nd TAB will focus the page title.
body.send_keys(Keys.TAB)
django_administration_title = self.selenium.find_element(
By.LINK_TEXT, "Django administration"
)
self.assertFalse(skip_link.is_displayed()) # `skip link` disappear.
self.assertEqual(
self.selenium.switch_to.active_element, django_administration_title
)
def test_skip_link_with_RTL_language_doesnt_create_horizontal_scrolling(self):
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
with override_settings(LANGUAGE_CODE="ar"):
self.admin_login(
username="super",
password="secret",
login_url=reverse("admin:index"),
)
skip_link = self.selenium.find_element(
By.CLASS_NAME, "skip-to-content-link"
)
body = self.selenium.find_element(By.TAG_NAME, "body")
body.send_keys(Keys.TAB)
self.assertTrue(skip_link.is_displayed())
is_vertical_scrolleable = self.selenium.execute_script(
"return arguments[0].scrollHeight > arguments[0].offsetHeight;", body
)
is_horizontal_scrolleable = self.selenium.execute_script(
"return arguments[0].scrollWeight > arguments[0].offsetWeight;", body
)
self.assertTrue(is_vertical_scrolleable)
self.assertFalse(is_horizontal_scrolleable)
def test_skip_link_keyboard_navigation_in_changelist(self):
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
Podcast.objects.create(name="apple", release_date="2000-09-19")
self.admin_login(
username="super", password="secret", login_url=reverse("admin:index")
)
self.selenium.get(
self.live_server_url + reverse("admin:admin_views_podcast_changelist")
)
selectors = [
"ul.object-tools", # object_tools.
"search#changelist-filter", # list_filter.
"form#changelist-search", # search_fields.
"nav.toplinks", # date_hierarchy.
"form#changelist-form div.actions", # action.
"table#result_list", # table.
"div.changelist-footer", # footer.
]
content = self.selenium.find_element(By.ID, "content-start")
content.send_keys(Keys.TAB)
for selector in selectors:
with self.subTest(selector=selector):
# Currently focused element.
focused_element = self.selenium.switch_to.active_element
expected_element = self.selenium.find_element(By.CSS_SELECTOR, selector)
element_points = self.selenium.find_elements(
By.CSS_SELECTOR,
f"{selector} a, {selector} input, {selector} button",
)
self.assertIn(
focused_element.get_attribute("outerHTML"),
expected_element.get_attribute("innerHTML"),
)
# Move to the next container element via TAB.
for point in element_points[::-1]:
if point.is_displayed():
point.send_keys(Keys.TAB)
break
|