kopia lustrzana https://github.com/wagtail/wagtail
431 wiersze
16 KiB
Python
431 wiersze
16 KiB
Python
import json
|
|
|
|
from django.contrib.auth.models import AnonymousUser, Permission
|
|
from django.template import Context, Template
|
|
from django.test import TestCase
|
|
from django.urls import reverse
|
|
|
|
from wagtail import hooks
|
|
from wagtail.admin.userbar import AccessibilityItem
|
|
from wagtail.coreutils import get_dummy_request
|
|
from wagtail.models import PAGE_TEMPLATE_VAR, Page, Site
|
|
from wagtail.test.testapp.models import BusinessChild, BusinessIndex, SimplePage
|
|
from wagtail.test.utils import WagtailTestUtils
|
|
|
|
|
|
class TestUserbarTag(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
self.user = self.create_superuser(
|
|
username="test", email="test@email.com", password="password"
|
|
)
|
|
self.homepage = Page.objects.get(id=2)
|
|
|
|
def dummy_request(
|
|
self,
|
|
user=None,
|
|
*,
|
|
is_preview=False,
|
|
in_preview_panel=False,
|
|
revision_id=None,
|
|
is_editing=False,
|
|
):
|
|
request = get_dummy_request()
|
|
request.user = user or AnonymousUser()
|
|
request.is_preview = is_preview
|
|
request.is_editing = is_editing
|
|
request.in_preview_panel = in_preview_panel
|
|
if revision_id:
|
|
request.revision_id = revision_id
|
|
return request
|
|
|
|
def test_userbar_tag(self):
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}")
|
|
context = Context(
|
|
{
|
|
PAGE_TEMPLATE_VAR: self.homepage,
|
|
"request": self.dummy_request(self.user),
|
|
}
|
|
)
|
|
with self.assertNumQueries(5):
|
|
content = template.render(context)
|
|
|
|
self.assertIn("<!-- Wagtail user bar embed code -->", content)
|
|
|
|
def test_userbar_does_not_break_without_request(self):
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}boom")
|
|
content = template.render(Context({}))
|
|
|
|
self.assertEqual("boom", content)
|
|
|
|
def test_userbar_tag_self(self):
|
|
"""
|
|
Ensure the userbar renders with `self` instead of `PAGE_TEMPLATE_VAR`
|
|
"""
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}")
|
|
content = template.render(
|
|
Context(
|
|
{
|
|
"self": self.homepage,
|
|
"request": self.dummy_request(self.user),
|
|
}
|
|
)
|
|
)
|
|
|
|
self.assertIn("<!-- Wagtail user bar embed code -->", content)
|
|
|
|
def test_userbar_tag_anonymous_user(self):
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}")
|
|
content = template.render(
|
|
Context(
|
|
{
|
|
PAGE_TEMPLATE_VAR: self.homepage,
|
|
"request": self.dummy_request(),
|
|
}
|
|
)
|
|
)
|
|
|
|
# Make sure nothing was rendered
|
|
self.assertEqual(content, "")
|
|
|
|
def test_userbar_tag_no_page(self):
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}")
|
|
content = template.render(
|
|
Context(
|
|
{
|
|
"request": self.dummy_request(self.user),
|
|
}
|
|
)
|
|
)
|
|
|
|
self.assertIn("<!-- Wagtail user bar embed code -->", content)
|
|
|
|
def test_edit_link(self):
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}")
|
|
content = template.render(
|
|
Context(
|
|
{
|
|
PAGE_TEMPLATE_VAR: self.homepage,
|
|
"request": self.dummy_request(self.user, is_preview=False),
|
|
}
|
|
)
|
|
)
|
|
self.assertIn("<!-- Wagtail user bar embed code -->", content)
|
|
self.assertIn("Edit this page", content)
|
|
|
|
def test_userbar_edit_menu_in_previews(self):
|
|
# The edit link should be visible on draft, revision, and workflow previews.
|
|
# https://github.com/wagtail/wagtail/issues/10002
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}")
|
|
content = template.render(
|
|
Context(
|
|
{
|
|
PAGE_TEMPLATE_VAR: self.homepage,
|
|
"request": self.dummy_request(self.user, is_preview=True),
|
|
}
|
|
)
|
|
)
|
|
self.assertIn("<!-- Wagtail user bar embed code -->", content)
|
|
self.assertIn("Edit this page", content)
|
|
self.assertIn(
|
|
reverse("wagtailadmin_pages:edit", args=(self.homepage.id,)), content
|
|
)
|
|
|
|
def test_userbar_edit_menu_not_in_preview(self):
|
|
# The edit link should not be visible on PreviewOnEdit/Create views.
|
|
# https://github.com/wagtail/wagtail/issues/8765
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}")
|
|
content = template.render(
|
|
Context(
|
|
{
|
|
PAGE_TEMPLATE_VAR: self.homepage,
|
|
"request": self.dummy_request(
|
|
self.user, is_preview=True, is_editing=True
|
|
),
|
|
}
|
|
)
|
|
)
|
|
self.assertIn("<!-- Wagtail user bar embed code -->", content)
|
|
self.assertNotIn("Edit this page", content)
|
|
self.assertNotIn(
|
|
reverse("wagtailadmin_pages:edit", args=(self.homepage.id,)), content
|
|
)
|
|
|
|
def test_userbar_hidden_in_preview_panel(self):
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}")
|
|
content = template.render(
|
|
Context(
|
|
{
|
|
PAGE_TEMPLATE_VAR: self.homepage,
|
|
"request": self.dummy_request(
|
|
self.user, is_preview=True, in_preview_panel=True
|
|
),
|
|
}
|
|
)
|
|
)
|
|
|
|
self.assertIn("<aside hidden>", content)
|
|
|
|
def test_userbar_dialog_position_left(self):
|
|
template = Template(
|
|
"{% load wagtailuserbar %}{% wagtailuserbar 'bottom-left' %}"
|
|
)
|
|
content = template.render(Context({"request": self.dummy_request(self.user)}))
|
|
self.assertIn("w-dialog--userbar-left", content)
|
|
|
|
def test_userbar_dialog_position_right(self):
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar 'top-right' %}")
|
|
content = template.render(Context({"request": self.dummy_request(self.user)}))
|
|
self.assertIn("w-dialog--userbar-right", content)
|
|
|
|
|
|
class TestAccessibilityCheckerConfig(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
self.request = get_dummy_request()
|
|
self.request.user = self.user
|
|
|
|
def get_script(self):
|
|
template = Template("{% load wagtailuserbar %}{% wagtailuserbar %}")
|
|
content = template.render(Context({"request": self.request}))
|
|
soup = self.get_soup(content)
|
|
|
|
# Should include the configuration as a JSON script with the specific id
|
|
return soup.find("script", id="accessibility-axe-configuration")
|
|
|
|
def get_config(self):
|
|
return json.loads(self.get_script().string)
|
|
|
|
def get_hook(self, item_class):
|
|
def customise_accessibility_checker(request, items):
|
|
items[:] = [
|
|
item_class() if isinstance(item, AccessibilityItem) else item
|
|
for item in items
|
|
]
|
|
|
|
return customise_accessibility_checker
|
|
|
|
def test_config_json(self):
|
|
script = self.get_script()
|
|
# The configuration should be a valid non-empty JSON script
|
|
self.assertIsNotNone(script)
|
|
self.assertEqual(script.attrs["type"], "application/json")
|
|
config_string = script.string.strip()
|
|
self.assertGreater(len(config_string), 0)
|
|
config = json.loads(config_string)
|
|
self.assertIsInstance(config, dict)
|
|
self.assertGreater(len(config.keys()), 0)
|
|
|
|
def test_messages(self):
|
|
# Should include Wagtail's error messages
|
|
config = self.get_config()
|
|
self.assertIsInstance(config.get("messages"), dict)
|
|
self.assertEqual(
|
|
config["messages"]["empty-heading"],
|
|
"Empty heading found. Use meaningful text for screen reader users.",
|
|
)
|
|
|
|
def test_custom_message(self):
|
|
class CustomMessageAccessibilityItem(AccessibilityItem):
|
|
# Override via class attribute
|
|
axe_messages = {
|
|
"empty-heading": "Headings should not be empty!",
|
|
}
|
|
|
|
# Override via method
|
|
def get_axe_messages(self, request):
|
|
return {
|
|
**super().get_axe_messages(request),
|
|
"color-contrast-enhanced": "Increase colour contrast!",
|
|
}
|
|
|
|
with hooks.register_temporarily(
|
|
"construct_wagtail_userbar",
|
|
self.get_hook(CustomMessageAccessibilityItem),
|
|
):
|
|
config = self.get_config()
|
|
self.assertEqual(
|
|
config["messages"],
|
|
{
|
|
"empty-heading": "Headings should not be empty!",
|
|
"color-contrast-enhanced": "Increase colour contrast!",
|
|
},
|
|
)
|
|
|
|
def test_unset_run_only(self):
|
|
class UnsetRunOnlyAccessibilityItem(AccessibilityItem):
|
|
# Example config that unsets the runOnly property so that all
|
|
# non-experimental rules are run, but the experimental
|
|
# focus-order-semantics rule is explicitly enabled
|
|
axe_run_only = None
|
|
axe_rules = {"focus-order-semantics": {"enabled": True}}
|
|
|
|
with hooks.register_temporarily(
|
|
"construct_wagtail_userbar",
|
|
self.get_hook(UnsetRunOnlyAccessibilityItem),
|
|
):
|
|
config = self.get_config()
|
|
self.assertEqual(
|
|
config["options"],
|
|
# Should not include the runOnly property, but should include
|
|
# the focus-order-semantics rule
|
|
{"rules": {"focus-order-semantics": {"enabled": True}}},
|
|
)
|
|
|
|
def test_custom_context(self):
|
|
class CustomContextAccessibilityItem(AccessibilityItem):
|
|
axe_include = ["article", "section"]
|
|
axe_exclude = [".sr-only"]
|
|
|
|
def get_axe_exclude(self, request):
|
|
return [*super().get_axe_exclude(request), "[data-please-ignore]"]
|
|
|
|
with hooks.register_temporarily(
|
|
"construct_wagtail_userbar",
|
|
self.get_hook(CustomContextAccessibilityItem),
|
|
):
|
|
config = self.get_config()
|
|
self.assertEqual(
|
|
config["context"],
|
|
{
|
|
# Override via class attribute
|
|
"include": ["article", "section"],
|
|
"exclude": [
|
|
# Override via class attribute
|
|
".sr-only",
|
|
# Should include the default exclude selectors
|
|
{"fromShadowDOM": ["wagtail-userbar"]},
|
|
# Override via method
|
|
"[data-please-ignore]",
|
|
],
|
|
},
|
|
)
|
|
|
|
def test_custom_run_only_and_rules_per_request(self):
|
|
class CustomRunOnlyAccessibilityItem(AccessibilityItem):
|
|
# Enable all rules within these tags
|
|
axe_run_only = [
|
|
"wcag2a",
|
|
"wcag2aa",
|
|
"wcag2aaa",
|
|
"wcag21a",
|
|
"wcag21aa",
|
|
"wcag22aa",
|
|
"best-practice",
|
|
]
|
|
# Turn off the color-contrast-enhanced rule
|
|
axe_rules = {
|
|
"color-contrast-enhanced": {"enabled": False},
|
|
}
|
|
|
|
def get_axe_rules(self, request):
|
|
# Do not turn off any rules for superusers
|
|
if request.user.is_superuser:
|
|
return {}
|
|
return super().get_axe_rules(request)
|
|
|
|
with hooks.register_temporarily(
|
|
"construct_wagtail_userbar",
|
|
self.get_hook(CustomRunOnlyAccessibilityItem),
|
|
):
|
|
config = self.get_config()
|
|
self.assertEqual(
|
|
config["options"],
|
|
{
|
|
"runOnly": CustomRunOnlyAccessibilityItem.axe_run_only,
|
|
"rules": {},
|
|
},
|
|
)
|
|
|
|
self.user.is_superuser = False
|
|
self.user.user_permissions.add(
|
|
Permission.objects.get(
|
|
content_type__app_label="wagtailadmin", codename="access_admin"
|
|
)
|
|
)
|
|
self.user.save()
|
|
|
|
config = self.get_config()
|
|
self.assertEqual(
|
|
config["options"],
|
|
{
|
|
"runOnly": CustomRunOnlyAccessibilityItem.axe_run_only,
|
|
"rules": CustomRunOnlyAccessibilityItem.axe_rules,
|
|
},
|
|
)
|
|
|
|
|
|
class TestUserbarInPageServe(WagtailTestUtils, TestCase):
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
self.request = get_dummy_request(site=Site.objects.first())
|
|
self.request.user = self.user
|
|
self.homepage = Page.objects.get(id=2).specific
|
|
# Use a specific page model to use our template that has {% wagtailuserbar %}
|
|
self.page = SimplePage(title="Rendang", content="Enak", live=True)
|
|
self.homepage.add_child(instance=self.page)
|
|
|
|
def test_userbar_rendered(self):
|
|
response = self.page.serve(self.request)
|
|
response.render()
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, '<template id="wagtail-userbar-template">')
|
|
|
|
def test_userbar_anonymous_user_cannot_see(self):
|
|
self.request.user = AnonymousUser()
|
|
response = self.page.serve(self.request)
|
|
response.render()
|
|
|
|
# Check that the userbar is not rendered
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertNotContains(response, '<template id="wagtail-userbar-template">')
|
|
|
|
|
|
class TestUserbarAddLink(WagtailTestUtils, TestCase):
|
|
fixtures = ["test.json"]
|
|
|
|
def setUp(self):
|
|
self.user = self.login()
|
|
self.request = get_dummy_request(site=Site.objects.first())
|
|
self.request.user = self.user
|
|
self.homepage = Page.objects.get(url_path="/home/")
|
|
self.event_index = Page.objects.get(url_path="/home/events/").specific
|
|
|
|
self.business_index = BusinessIndex(title="Business", live=True)
|
|
self.homepage.add_child(instance=self.business_index)
|
|
|
|
self.business_child = BusinessChild(title="Business Child", live=True)
|
|
self.business_index.add_child(instance=self.business_child)
|
|
|
|
def test_page_allowing_subpages(self):
|
|
response = self.event_index.serve(self.request)
|
|
response.render()
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# page allows subpages, so the 'add page' button should show
|
|
expected_url = reverse(
|
|
"wagtailadmin_pages:add_subpage", args=(self.event_index.id,)
|
|
)
|
|
needle = f"""
|
|
<a href="{expected_url}" target="_parent" role="menuitem">
|
|
<svg class="icon icon-plus w-action-icon" aria-hidden="true">
|
|
<use href="#icon-plus"></use>
|
|
</svg>
|
|
Add a child page
|
|
</a>
|
|
"""
|
|
self.assertTagInHTML(needle, response.content.decode())
|
|
|
|
def test_page_disallowing_subpages(self):
|
|
response = self.business_child.serve(self.request)
|
|
response.render()
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# page disallows subpages, so the 'add page' button shouldn't show
|
|
expected_url = reverse(
|
|
"wagtailadmin_pages:add_subpage", args=(self.business_index.id,)
|
|
)
|
|
soup = self.get_soup(response.content)
|
|
link = soup.find("a", attrs={"href": expected_url})
|
|
self.assertIsNone(link)
|