Files
old-saburly-wagtail-web/env/lib/python3.10/site-packages/wagtail/admin/tests/test_menu.py

427 lines
15 KiB
Python
Raw Normal View History

2024-08-27 20:33:44 +02:00
from django.test import RequestFactory, TestCase
from django.urls import reverse
from django.utils import translation
from wagtail import hooks
from wagtail.admin.menu import (
AdminOnlyMenuItem,
DismissibleMenuItem,
DismissibleSubmenuMenuItem,
Menu,
MenuItem,
SubmenuMenuItem,
admin_menu,
)
from wagtail.admin.ui import sidebar
from wagtail.test.utils import WagtailTestUtils
from wagtail.users.models import UserProfile
def menu_item_hook(*args, cls=MenuItem, **kwargs):
def hook_fn():
return cls(*args, **kwargs)
return hook_fn
class TestMenuRendering(WagtailTestUtils, TestCase):
def setUp(self):
self.request = RequestFactory().get("/admin")
self.request.user = self.create_superuser(username="admin")
self.profile = UserProfile.get_for_user(self.request.user)
self.user = self.login()
def test_remember_collapsed(self):
"""Sidebar should render with collapsed class applied."""
# Sidebar should not be collapsed
self.client.cookies["wagtail_sidebar_collapsed"] = "0"
response = self.client.get(reverse("wagtailadmin_home"))
self.assertNotContains(response, "sidebar-collapsed")
# Sidebar should be collapsed
self.client.cookies["wagtail_sidebar_collapsed"] = "1"
response = self.client.get(reverse("wagtailadmin_home"))
self.assertContains(response, "sidebar-collapsed")
def test_simple_menu(self):
# Note: initialise the menu before registering hooks as this is what happens in reality.
# (the real menus are initialised at the module level in admin/menu.py)
menu = Menu(register_hook_name="register_menu_item")
with hooks.register_temporarily(
[
("register_menu_item", menu_item_hook("Pages", "/pages/")),
("register_menu_item", menu_item_hook("Images", "/images/")),
]
):
rendered = menu.render_component(self.request)
self.assertIsInstance(rendered, list)
self.assertListEqual(
rendered,
[
sidebar.LinkMenuItem("pages", "Pages", "/pages/"),
sidebar.LinkMenuItem("images", "Images", "/images/"),
],
)
def test_menu_with_construct_hook(self):
menu = Menu(
register_hook_name="register_menu_item",
construct_hook_name="construct_menu",
)
def remove_images(request, items):
items[:] = [item for item in items if not item.name == "images"]
with hooks.register_temporarily(
[
("register_menu_item", menu_item_hook("Pages", "/pages/")),
("register_menu_item", menu_item_hook("Images", "/images/")),
("construct_menu", remove_images),
]
):
rendered = menu.render_component(self.request)
self.assertEqual(
rendered,
[
sidebar.LinkMenuItem("pages", "Pages", "/pages/"),
],
)
def test_submenu(self):
menu = Menu(register_hook_name="register_menu_item")
submenu = Menu(register_hook_name="register_submenu_item")
with hooks.register_temporarily(
[
(
"register_menu_item",
menu_item_hook("My lovely submenu", submenu, cls=SubmenuMenuItem),
),
("register_submenu_item", menu_item_hook("Pages", "/pages/")),
]
):
rendered = menu.render_component(self.request)
self.assertIsInstance(rendered, list)
self.assertEqual(len(rendered), 1)
self.assertIsInstance(rendered[0], sidebar.SubMenuItem)
self.assertEqual(rendered[0].name, "my-lovely-submenu")
self.assertEqual(rendered[0].label, "My lovely submenu")
self.assertListEqual(
rendered[0].menu_items,
[
sidebar.LinkMenuItem("pages", "Pages", "/pages/"),
],
)
def test_dismissible_initial(self):
menu = Menu(register_hook_name="register_menu_item")
submenu = Menu(register_hook_name="register_submenu_item")
with hooks.register_temporarily(
[
(
"register_menu_item",
menu_item_hook(
"My dismissible submenu",
submenu,
cls=DismissibleSubmenuMenuItem,
name="dismissible-submenu-menu-item",
),
),
(
"register_submenu_item",
menu_item_hook(
"Pages",
"/pages/",
cls=DismissibleMenuItem,
name="dismissible-menu-item",
),
),
]
):
rendered = menu.render_component(self.request)
self.assertIsInstance(rendered, list)
self.assertEqual(len(rendered), 1)
self.assertIsInstance(rendered[0], sidebar.SubMenuItem)
self.assertEqual(rendered[0].name, "dismissible-submenu-menu-item")
self.assertEqual(rendered[0].label, "My dismissible submenu")
self.assertEqual(
rendered[0].attrs,
# Should not be dismissed
{
"data-controller": "w-dismissible",
"data-w-dismissible-dismissed-class": "w-dismissible--dismissed",
"data-w-dismissible-id-value": "dismissible-submenu-menu-item",
},
)
self.assertListEqual(
rendered[0].menu_items,
[
sidebar.LinkMenuItem(
"dismissible-menu-item",
"Pages",
"/pages/",
# Should not be dismissed
attrs={
"data-controller": "w-dismissible",
"data-w-dismissible-dismissed-class": "w-dismissible--dismissed",
"data-w-dismissible-id-value": "dismissible-menu-item",
},
),
],
)
def test_dismissible_dismissed(self):
self.profile.dismissibles = {
"dismissible-submenu-menu-item": True,
"dismissible-menu-item": True,
}
self.profile.save()
self.request.user.refresh_from_db()
menu = Menu(register_hook_name="register_menu_item")
submenu = Menu(register_hook_name="register_submenu_item")
with hooks.register_temporarily(
[
(
"register_menu_item",
menu_item_hook(
"My dismissible submenu",
submenu,
cls=DismissibleSubmenuMenuItem,
name="dismissible-submenu-menu-item",
),
),
(
"register_submenu_item",
menu_item_hook(
"Pages",
"/pages/",
cls=DismissibleMenuItem,
name="dismissible-menu-item",
),
),
]
):
rendered = menu.render_component(self.request)
self.assertIsInstance(rendered, list)
self.assertEqual(len(rendered), 1)
self.assertIsInstance(rendered[0], sidebar.SubMenuItem)
self.assertEqual(rendered[0].name, "dismissible-submenu-menu-item")
self.assertEqual(rendered[0].label, "My dismissible submenu")
self.assertEqual(
rendered[0].attrs,
{
"data-controller": "w-dismissible",
"data-w-dismissible-dismissed-class": "w-dismissible--dismissed",
"data-w-dismissible-id-value": "dismissible-submenu-menu-item",
# Should be dismissed
"data-w-dismissible-dismissed-value": "true",
},
)
self.assertListEqual(
rendered[0].menu_items,
[
sidebar.LinkMenuItem(
"dismissible-menu-item",
"Pages",
"/pages/",
# Should be dismissed
attrs={
"data-controller": "w-dismissible",
"data-w-dismissible-dismissed-class": "w-dismissible--dismissed",
"data-w-dismissible-id-value": "dismissible-menu-item",
"data-w-dismissible-dismissed-value": "true",
},
),
],
)
def test_dismissible_no_userprofile(self):
# Without a user profile, dismissible menu items should not be dismissed
self.profile.delete()
self.request.user.refresh_from_db()
menu = Menu(register_hook_name="register_menu_item")
submenu = Menu(register_hook_name="register_submenu_item")
with hooks.register_temporarily(
[
(
"register_menu_item",
menu_item_hook(
"My dismissible submenu",
submenu,
cls=DismissibleSubmenuMenuItem,
name="dismissible-submenu-menu-item",
),
),
(
"register_submenu_item",
menu_item_hook(
"Pages",
"/pages/",
cls=DismissibleMenuItem,
name="dismissible-menu-item",
),
),
]
):
rendered = menu.render_component(self.request)
self.assertIsInstance(rendered, list)
self.assertEqual(len(rendered), 1)
self.assertIsInstance(rendered[0], sidebar.SubMenuItem)
self.assertEqual(rendered[0].name, "dismissible-submenu-menu-item")
self.assertEqual(rendered[0].label, "My dismissible submenu")
self.assertEqual(
rendered[0].attrs,
{
"data-controller": "w-dismissible",
"data-w-dismissible-dismissed-class": "w-dismissible--dismissed",
"data-w-dismissible-id-value": "dismissible-submenu-menu-item",
},
)
self.assertListEqual(
rendered[0].menu_items,
[
sidebar.LinkMenuItem(
"dismissible-menu-item",
"Pages",
"/pages/",
attrs={
"data-controller": "w-dismissible",
"data-w-dismissible-dismissed-class": "w-dismissible--dismissed",
"data-w-dismissible-id-value": "dismissible-menu-item",
},
),
],
)
def test_admin_only_menuitem(self):
menu = Menu(register_hook_name="register_menu_item")
with hooks.register_temporarily(
[
("register_menu_item", menu_item_hook("Pages", "/pages/")),
(
"register_menu_item",
menu_item_hook(
"Secret pages", "/pages/secret/", cls=AdminOnlyMenuItem
),
),
]
):
rendered = menu.render_component(self.request)
self.request.user = self.create_user(username="non-admin")
rendered_non_admin = menu.render_component(self.request)
self.assertListEqual(
rendered,
[
sidebar.LinkMenuItem("pages", "Pages", "/pages/"),
sidebar.LinkMenuItem("secret-pages", "Secret pages", "/pages/secret/"),
],
)
self.assertListEqual(
rendered_non_admin,
[
sidebar.LinkMenuItem("pages", "Pages", "/pages/"),
],
)
def test_menu_items_have_names(self):
# Delete the registered_menu_items cache
try:
del admin_menu.registered_menu_items
# The cache may not be created yet if the test is run in isolation
except AttributeError:
pass
# Generate the menu items using a different language
with translation.override("fr"):
names = {item.name for item in admin_menu.registered_menu_items}
# Default menu items
expected = {
"explorer",
"images",
"documents",
"snippets",
"forms",
"reports",
"settings",
"help",
}
# If some of the above items do not have a name, they will be
# automatically generated from the label, which is translatable.
# We want the name to be consistent across languages, so this test will
# fail if the label is translated.
self.assertFalse(expected - names)
def test_submenu_items_have_names(self):
names = set()
# Generate the submenu items using a different language
with translation.override("fr"):
# Getting only the submenu items
for item in admin_menu.registered_menu_items:
if not hasattr(item, "menu"):
continue
# Delete the registered_menu_items cache
try:
del item.menu.registered_menu_items
# The cache may not be created yet if the test is run in isolation
except AttributeError:
pass
for subitem in item.menu.registered_menu_items:
names.add(subitem.name)
# Default submenu items
expected = {
"site-history",
"workflows",
"users",
"revisable-child-models",
"groups",
"aging-pages",
"editor-guide",
"sites",
"publishables",
"locked-pages",
"workflow-tasks",
"icon-site-setting",
"revisable-models",
"collections",
"locales",
"styleguide",
"test-generic-setting",
"test-site-setting",
"important-pages-generic-setting",
"redirects",
"important-pages-site-setting",
"workflow-tasks",
"promoted-search-results",
"icon-generic-setting",
"file-site-setting",
"workflows",
"file-generic-setting",
}
# If some of the above subitems do not have a name, they will be
# automatically generated from the label, which is translatable.
# We want the name to be consistent across languages, so this test will
# fail if the label is translated.
self.assertFalse(expected - names)