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 = """
not in a script tag
""" self.assertTagInTemplateScript('', haystack) self.assertTagInTemplateScript( '
', haystack, count=2 ) with self.assertRaises(AssertionError): self.assertTagInTemplateScript('
', 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("
Event intro
")} ), ) 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( "Dit is onze mooie text in een ferrari
" ), ), ("product", {"name": "pegs", "price": "a pound"}), ] ), } ), ) self.assertCanCreate( self.root, SectionedRichTextPage, nested_form_data( { "title": "Fight Club", "sections": inline_formset( [ { "body": rich_text( "Rule 1: You do not talk about Fight Club
" ) }, { "body": rich_text( "Rule 2: You DO NOT talk about Fight Club
" ) }, ] ), } ), ) 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("para
") 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 allowpara
", 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("para
", editor="custom") self.assertEqual(result, "para
") 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!")