angrybeanie_wagtail/env/lib/python3.12/site-packages/wagtail/tests/test_tests.py

489 lines
18 KiB
Python
Raw Permalink Normal View History

2025-07-25 21:32:16 +10:00
import json
import unittest
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.files.uploadedfile import SimpleUploadedFile
from django.template import Context, Template
from django.test import TestCase
from wagtail.admin.tests.test_contentstate import content_state_equal
from wagtail.models import PAGE_MODEL_CLASSES, Page, Site
from wagtail.test.dummy_external_storage import DummyExternalStorage
from wagtail.test.testapp.models import (
BusinessChild,
BusinessIndex,
BusinessNowherePage,
BusinessSubIndex,
EventIndex,
EventPage,
NoCreatableSubpageTypesPage,
NoSubpageTypesPage,
SectionedRichTextPage,
SimpleChildPage,
SimplePage,
SimpleParentPage,
StreamPage,
)
from wagtail.test.utils import WagtailPageTests, WagtailTestUtils
from wagtail.test.utils.form_data import (
inline_formset,
nested_form_data,
rich_text,
streamfield,
)
class TestAssertTagInHTML(WagtailTestUtils, TestCase):
def test_assert_tag_in_html(self):
haystack = """<ul>
<li class="normal">hugh</li>
<li class="normal">pugh</li>
<li class="really important" lang="en"><em>barney</em> mcgrew</li>
</ul>"""
self.assertTagInHTML('<li lang="en" class="important really">', haystack)
self.assertTagInHTML('<li class="normal">', haystack, count=2)
with self.assertRaises(AssertionError):
self.assertTagInHTML('<div lang="en" class="important really">', haystack)
with self.assertRaises(AssertionError):
self.assertTagInHTML(
'<li lang="en" class="important really">', haystack, count=2
)
with self.assertRaises(AssertionError):
self.assertTagInHTML('<li lang="en" class="important">', haystack)
with self.assertRaises(AssertionError):
self.assertTagInHTML(
'<li lang="en" class="important really" data-extra="boom">', haystack
)
def test_assert_tag_in_html_with_extra_attrs(self):
haystack = """<ul>
<li class="normal">hugh</li>
<li class="normal">pugh</li>
<li class="really important" lang="en"><em>barney</em> mcgrew</li>
</ul>"""
self.assertTagInHTML(
'<li class="important really">', haystack, allow_extra_attrs=True
)
self.assertTagInHTML("<li>", haystack, count=3, allow_extra_attrs=True)
with self.assertRaises(AssertionError):
self.assertTagInHTML(
'<li class="normal" lang="en">', haystack, allow_extra_attrs=True
)
with self.assertRaises(AssertionError):
self.assertTagInHTML(
'<li class="important really">',
haystack,
count=2,
allow_extra_attrs=True,
)
def test_assert_tag_in_template_script(self):
haystack = """<html>
<script type="text/template">
<p class="really important">first template block</p>
</script>
<script type="text/template">
<p class="really important">second template block</p>
</script>
<p class="normal">not in a script tag</p>
</html>"""
self.assertTagInTemplateScript('<p class="important really">', haystack)
self.assertTagInTemplateScript(
'<p class="important really">', haystack, count=2
)
with self.assertRaises(AssertionError):
self.assertTagInTemplateScript('<p class="normal">', haystack)
class TestWagtailPageTests(WagtailPageTests):
def setUp(self):
super().setUp()
site = Site.objects.get(is_default_site=True)
self.root = site.root_page.specific
def test_assert_can_create_at(self):
# It should be possible to create an EventPage under an EventIndex,
self.assertCanCreateAt(EventIndex, EventPage)
self.assertCanCreateAt(Page, EventIndex)
# It should not be possible to create a SimplePage under a BusinessChild
self.assertCanNotCreateAt(SimplePage, BusinessChild)
# This should raise, as it *is not* possible
with self.assertRaises(AssertionError):
self.assertCanCreateAt(SimplePage, BusinessChild)
# This should raise, as it *is* possible
with self.assertRaises(AssertionError):
self.assertCanNotCreateAt(EventIndex, EventPage)
def test_assert_can_create(self):
self.assertFalse(EventIndex.objects.exists())
self.assertCanCreate(
self.root,
EventIndex,
{
"title": "Event Index",
"intro": """{"entityMap": {},"blocks": [
{"inlineStyleRanges": [], "text": "Event intro", "depth": 0, "type": "unstyled", "key": "00000", "entityRanges": []}
]}""",
},
)
self.assertTrue(EventIndex.objects.exists())
self.assertTrue(EventIndex.objects.get().live)
self.assertCanCreate(
self.root,
StreamPage,
{
"title": "Flierp",
"body-0-type": "text",
"body-0-value": "Dit is onze mooie text",
"body-0-order": "0",
"body-0-deleted": "",
"body-1-type": "rich_text",
"body-1-value": """{"entityMap": {},"blocks": [
{"inlineStyleRanges": [], "text": "Dit is onze mooie text in een ferrari", "depth": 0, "type": "unstyled", "key": "00000", "entityRanges": []}
]}""",
"body-1-order": "1",
"body-1-deleted": "",
"body-2-type": "product",
"body-2-value-name": "pegs",
"body-2-value-price": "a pound",
"body-2-order": "2",
"body-2-deleted": "",
"body-count": "3",
},
)
self.assertCanCreate(
self.root,
SectionedRichTextPage,
{
"title": "Fight Club",
"sections-TOTAL_FORMS": "2",
"sections-INITIAL_FORMS": "0",
"sections-MIN_NUM_FORMS": "0",
"sections-MAX_NUM_FORMS": "1000",
"sections-0-body": """{"entityMap": {},"blocks": [
{"inlineStyleRanges": [], "text": "Rule 1: You do not talk about Fight Club", "depth": 0, "type": "unstyled", "key": "00000", "entityRanges": []}
]}""",
"sections-0-ORDER": "0",
"sections-0-DELETE": "",
"sections-1-body": """{"entityMap": {},"blocks": [
{"inlineStyleRanges": [], "text": "Rule 2: You DO NOT talk about Fight Club", "depth": 0, "type": "unstyled", "key": "00000", "entityRanges": []}
]}""",
"sections-1-ORDER": "0",
"sections-1-DELETE": "",
},
)
def test_assert_can_create_for_page_without_publish(self):
self.assertCanCreate(
self.root,
SimplePage,
{"title": "Simple Lorem Page", "content": "Lorem ipsum dolor sit amet"},
publish=False,
)
created_page = Page.objects.get(title="Simple Lorem Page")
self.assertFalse(created_page.live)
def test_assert_can_create_with_form_helpers(self):
# same as test_assert_can_create, but using the helpers from wagtail.test.utils.form_data
# as an end-to-end test
self.assertFalse(EventIndex.objects.exists())
self.assertCanCreate(
self.root,
EventIndex,
nested_form_data(
{"title": "Event Index", "intro": rich_text("<p>Event intro</p>")}
),
)
self.assertTrue(EventIndex.objects.exists())
self.assertCanCreate(
self.root,
StreamPage,
nested_form_data(
{
"title": "Flierp",
"body": streamfield(
[
("text", "Dit is onze mooie text"),
(
"rich_text",
rich_text(
"<p>Dit is onze mooie text in een ferrari</p>"
),
),
("product", {"name": "pegs", "price": "a pound"}),
]
),
}
),
)
self.assertCanCreate(
self.root,
SectionedRichTextPage,
nested_form_data(
{
"title": "Fight Club",
"sections": inline_formset(
[
{
"body": rich_text(
"<p>Rule 1: You do not talk about Fight Club</p>"
)
},
{
"body": rich_text(
"<p>Rule 2: You DO NOT talk about Fight Club</p>"
)
},
]
),
}
),
)
def test_assert_can_create_subpage_rules(self):
simple_page = SimplePage(title="Simple Page", slug="simple", content="hello")
self.root.add_child(instance=simple_page)
# This should raise an error, as a BusinessChild can not be created under a SimplePage
with self.assertRaisesRegex(
AssertionError,
r"Can not create a tests.businesschild under a tests.simplepage",
):
self.assertCanCreate(simple_page, BusinessChild, {})
def test_assert_can_create_validation_error(self):
# This should raise some validation errors, complaining about missing
# title and slug fields
with self.assertRaisesRegex(AssertionError, r"\bslug:\n[\s\S]*\btitle:\n"):
self.assertCanCreate(self.root, SimplePage, {})
def test_assert_allowed_subpage_types(self):
self.assertAllowedSubpageTypes(BusinessIndex, {BusinessChild, BusinessSubIndex})
self.assertAllowedSubpageTypes(BusinessChild, {})
# All page types can be created under the Page model, except those with a parent_page_types
# rule excluding it
all_but_business = set(PAGE_MODEL_CLASSES) - {
BusinessSubIndex,
BusinessChild,
BusinessNowherePage,
SimpleChildPage,
}
self.assertAllowedSubpageTypes(Page, all_but_business)
with self.assertRaises(AssertionError):
self.assertAllowedSubpageTypes(
BusinessSubIndex, {BusinessSubIndex, BusinessChild}
)
def test_assert_allowed_parent_page_types(self):
self.assertAllowedParentPageTypes(
BusinessChild, {BusinessIndex, BusinessSubIndex}
)
self.assertAllowedParentPageTypes(BusinessSubIndex, {BusinessIndex})
# BusinessIndex can be created under all page types that do not have a subpage_types rule
all_but_business = set(PAGE_MODEL_CLASSES) - {
BusinessSubIndex,
BusinessChild,
BusinessIndex,
NoCreatableSubpageTypesPage,
NoSubpageTypesPage,
SimpleParentPage,
}
self.assertAllowedParentPageTypes(BusinessIndex, all_but_business)
with self.assertRaises(AssertionError):
self.assertAllowedParentPageTypes(
BusinessSubIndex, {BusinessSubIndex, BusinessIndex}
)
class TestFormDataHelpers(TestCase):
def test_nested_form_data(self):
result = nested_form_data(
{
"foo": "bar",
"parent": {
"child": "field",
},
}
)
self.assertEqual(result, {"foo": "bar", "parent-child": "field"})
def test_streamfield(self):
result = nested_form_data(
{
"content": streamfield(
[
("text", "Hello, world"),
("text", "Goodbye, world"),
("coffee", {"type": "latte", "milk": "soya"}),
]
)
}
)
self.assertEqual(
result,
{
"content-count": "3",
"content-0-type": "text",
"content-0-value": "Hello, world",
"content-0-order": "0",
"content-0-deleted": "",
"content-1-type": "text",
"content-1-value": "Goodbye, world",
"content-1-order": "1",
"content-1-deleted": "",
"content-2-type": "coffee",
"content-2-value-type": "latte",
"content-2-value-milk": "soya",
"content-2-order": "2",
"content-2-deleted": "",
},
)
def test_inline_formset(self):
result = nested_form_data(
{
"lines": inline_formset(
[
{"text": "Hello"},
{"text": "World"},
]
)
}
)
self.assertEqual(
result,
{
"lines-TOTAL_FORMS": "2",
"lines-INITIAL_FORMS": "0",
"lines-MIN_NUM_FORMS": "0",
"lines-MAX_NUM_FORMS": "1000",
"lines-0-text": "Hello",
"lines-0-ORDER": "0",
"lines-0-DELETE": "",
"lines-1-text": "World",
"lines-1-ORDER": "1",
"lines-1-DELETE": "",
},
)
def test_default_rich_text(self):
result = rich_text("<h2>title</h2><p>para</p>")
self.assertTrue(
content_state_equal(
json.loads(result),
{
"entityMap": {},
"blocks": [
{
"inlineStyleRanges": [],
"text": "title",
"depth": 0,
"type": "header-two",
"key": "00000",
"entityRanges": [],
},
{
"inlineStyleRanges": [],
"text": "para",
"depth": 0,
"type": "unstyled",
"key": "00000",
"entityRanges": [],
},
],
},
)
)
def test_rich_text_with_custom_features(self):
# feature list doesn't allow <h2>, so it should become an unstyled paragraph block
result = rich_text("<h2>title</h2><p>para</p>", features=["p"])
self.assertTrue(
content_state_equal(
json.loads(result),
{
"entityMap": {},
"blocks": [
{
"inlineStyleRanges": [],
"text": "title",
"depth": 0,
"type": "unstyled",
"key": "00000",
"entityRanges": [],
},
{
"inlineStyleRanges": [],
"text": "para",
"depth": 0,
"type": "unstyled",
"key": "00000",
"entityRanges": [],
},
],
},
)
)
def test_rich_text_with_alternative_editor(self):
result = rich_text("<h2>title</h2><p>para</p>", editor="custom")
self.assertEqual(result, "<h2>title</h2><p>para</p>")
class TestDummyExternalStorage(WagtailTestUtils, TestCase):
def test_save_with_incorrect_file_object_position(self):
"""
Test that DummyExternalStorage correctly warns about attempts
to write files that are not rewound to the start
"""
# This is a 1x1 black png
png = (
b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00"
b"\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00"
b"\x1f\x15\xc4\x89\x00\x00\x00\rIDATx\x9cc````"
b"\x00\x00\x00\x05\x00\x01\xa5\xf6E@\x00\x00"
b"\x00\x00IEND\xaeB`\x82"
)
simple_png = SimpleUploadedFile(
name="test.png", content=png, content_type="image/png"
)
simple_png.read()
with self.assertRaisesMessage(
ValueError,
"Content file pointer should be at 0 - got 70 instead",
):
DummyExternalStorage().save("test.png", simple_png)
@unittest.skipUnless(
settings.WAGTAIL_CHECK_TEMPLATE_NUMBER_FORMAT,
"Number formatting functions have not been patched",
)
class TestPatchedNumberFormat(TestCase):
def test_outputting_number_directly_is_disallowed(self):
context = Context({"num": 42})
template = Template("the answer is {{ num }}")
with self.assertRaises(ImproperlyConfigured):
template.render(context)
def test_outputting_number_via_intcomma(self):
context = Context({"num": 9000})
template = Template("{% load wagtailadmin_tags %}It's over {{ num|intcomma }}!")
self.assertEqual(template.render(context), "It's over 9,000!")
def test_outputting_number_via_unlocalize(self):
context = Context({"num": 9000})
template = Template("{% load l10n %}It's over {{ num|unlocalize }}!")
self.assertEqual(template.render(context), "It's over 9000!")