@@ -704,3 +704,211 @@ def test_groups_link(self):
704704 def test_admin_search (self ):
705705 response = self .client .get ('/admin/pages/search/?q=openstax' )
706706 self .assertEqual (response .status_code , 302 )
707+
708+
709+ class TemplateTagTests (WagtailPageTestCase ):
710+ """Test cases for custom template tags in pages app"""
711+
712+ def setUp (self ):
713+ """Set up test data"""
714+ mock_user_login ()
715+
716+ # Get root page
717+ root_page = Page .objects .get (title = "Root" )
718+
719+ # Create a test page with various field types
720+ self .test_page = page_models .HomePage (
721+ title = "Test HomePage" ,
722+ slug = "test-home" ,
723+ banner_headline = "Test Headline" ,
724+ banner_description = "Test description text" ,
725+ features_headline = "Features Test" ,
726+ )
727+ root_page .add_child (instance = self .test_page )
728+
729+ def test_get_page_content_extracts_char_field (self ):
730+ """Test that get_page_content extracts CharField values"""
731+ from django .template import Context , Template
732+
733+ template = Template ('{% load pages_tags %}{% get_page_content page as content %}{{ content|length }}' )
734+ context = Context ({'page' : self .test_page })
735+ result = template .render (context )
736+
737+ # Should extract multiple fields
738+ self .assertGreater (int (result ), 0 )
739+
740+ # Test actual content extraction
741+ template = Template ('{% load pages_tags %}{% get_page_content page as content %}{% for item in content %}{{ item.name }}:{{ item.value }}|{% endfor %}' )
742+ context = Context ({'page' : self .test_page })
743+ result = template .render (context )
744+
745+ # Should contain our test data
746+ self .assertIn ('banner_headline:Test Headline' , result )
747+ self .assertIn ('banner_description:Test description text' , result )
748+
749+ def test_get_page_content_extracts_text_field (self ):
750+ """Test that get_page_content extracts TextField values"""
751+ from django .template import Context , Template
752+
753+ template = Template ('{% load pages_tags %}{% get_page_content page as content %}{% for item in content %}{% if item.name == "banner_description" %}{{ item.value }}{% endif %}{% endfor %}' )
754+ context = Context ({'page' : self .test_page })
755+ result = template .render (context )
756+
757+ self .assertEqual (result .strip (), 'Test description text' )
758+
759+ def test_get_page_content_extracts_stream_field (self ):
760+ """Test that get_page_content extracts StreamField values"""
761+ from django .template import Context , Template
762+
763+ # Update the test page with StreamField data
764+ self .test_page .features_tab1_features = [
765+ ('feature_text' , 'Feature One' ),
766+ ('feature_text' , 'Feature Two' ),
767+ ]
768+ self .test_page .save ()
769+
770+ template = Template ('{% load pages_tags %}{% get_page_content page as content %}{% for item in content %}{% if item.name == "features_tab1_features" %}{{ item.value }}{% endif %}{% endfor %}' )
771+ context = Context ({'page' : self .test_page })
772+ result = template .render (context )
773+
774+ # Should contain the StreamField content
775+ self .assertIn ('Feature One' , result )
776+ self .assertIn ('Feature Two' , result )
777+
778+ def test_get_page_content_filters_system_fields (self ):
779+ """Test that get_page_content filters out internal/system fields"""
780+ from django .template import Context , Template
781+
782+ template = Template ('{% load pages_tags %}{% get_page_content page as content %}{% for item in content %}{{ item.name }}|{% endfor %}' )
783+ context = Context ({'page' : self .test_page })
784+ result = template .render (context )
785+
786+ # Should NOT contain system fields
787+ self .assertNotIn ('id|' , result )
788+ self .assertNotIn ('path|' , result )
789+ self .assertNotIn ('depth|' , result )
790+ self .assertNotIn ('slug|' , result )
791+ self .assertNotIn ('seo_title|' , result )
792+ self .assertNotIn ('content_type|' , result )
793+
794+ def test_get_page_content_handles_none_values (self ):
795+ """Test that get_page_content handles None values gracefully"""
796+ from django .template import Context , Template
797+
798+ # Create a page with minimal data
799+ root_page = Page .objects .get (title = "Root" )
800+ minimal_page = page_models .HomePage (
801+ title = "Minimal Page" ,
802+ slug = "minimal" ,
803+ )
804+ root_page .add_child (instance = minimal_page )
805+
806+ template = Template ('{% load pages_tags %}{% get_page_content page as content %}{{ content|length }}' )
807+ context = Context ({'page' : minimal_page })
808+ result = template .render (context )
809+
810+ # Should not crash and should return a number
811+ result_int = int (result )
812+ self .assertGreaterEqual (result_int , 0 )
813+
814+ def test_get_page_content_handles_empty_values (self ):
815+ """Test that get_page_content filters out empty values"""
816+ from django .template import Context , Template
817+ from pages .templatetags .pages_tags import get_page_content
818+
819+ # Get content directly using the template tag function
820+ context = Context ({'page' : self .test_page })
821+ content = get_page_content (context , self .test_page )
822+
823+ # All returned items should have non-empty values
824+ for item in content :
825+ self .assertIn ('name' , item , "Item missing 'name' key" )
826+ self .assertIn ('value' , item , "Item missing 'value' key" )
827+ self .assertTrue (item .get ('value' , '' ).strip (),
828+ f"Item { item .get ('name' , 'unknown' )} has empty value" )
829+
830+ def test_get_page_content_with_none_page (self ):
831+ """Test that get_page_content handles None page gracefully"""
832+ from django .template import Context , Template
833+
834+ template = Template ('{% load pages_tags %}{% get_page_content page as content %}{{ content|length }}' )
835+ context = Context ({'page' : None })
836+ result = template .render (context )
837+
838+ self .assertEqual (result .strip (), '0' )
839+
840+ def test_extract_content_handles_primitives (self ):
841+ """Test that extract_content handles primitive types"""
842+ from pages .templatetags .pages_tags import extract_content
843+
844+ self .assertEqual (extract_content ("test string" ), "test string" )
845+ self .assertEqual (extract_content (123 ), "123" )
846+ self .assertEqual (extract_content (45.67 ), "45.67" )
847+ self .assertEqual (extract_content (None ), "" )
848+
849+ def test_extract_content_handles_richtext (self ):
850+ """Test that extract_content handles RichText objects"""
851+ from pages .templatetags .pages_tags import extract_content
852+ from wagtail .rich_text import RichText
853+
854+ rich = RichText ("<p>Rich text content</p>" )
855+ result = extract_content (rich )
856+
857+ self .assertIn ("Rich text content" , result )
858+
859+ def test_extract_content_handles_lists (self ):
860+ """Test that extract_content handles list values"""
861+ from pages .templatetags .pages_tags import extract_content
862+
863+ test_list = ["item1" , "item2" , "item3" ]
864+ result = extract_content (test_list )
865+
866+ self .assertIn ("item1" , result )
867+ self .assertIn ("item2" , result )
868+ self .assertIn ("item3" , result )
869+
870+ def test_extract_content_handles_nested_structures (self ):
871+ """Test that extract_content recursively extracts from nested structures"""
872+ from pages .templatetags .pages_tags import extract_content
873+
874+ # Test with nested list
875+ nested = [["inner1" , "inner2" ], "outer" ]
876+ result = extract_content (nested )
877+
878+ self .assertIn ("inner1" , result )
879+ self .assertIn ("inner2" , result )
880+ self .assertIn ("outer" , result )
881+
882+ def test_extract_content_handles_dict_like_objects (self ):
883+ """Test that extract_content handles dict-like objects with values() method"""
884+ from pages .templatetags .pages_tags import extract_content
885+
886+ # Create a mock object with values() method
887+ class MockStructValue :
888+ def values (self ):
889+ return ["value1" , "value2" ]
890+
891+ mock = MockStructValue ()
892+ result = extract_content (mock )
893+
894+ self .assertIn ("value1" , result )
895+ self .assertIn ("value2" , result )
896+
897+ def test_get_page_content_returns_proper_structure (self ):
898+ """Test that get_page_content returns items with correct structure"""
899+ from django .template import Context , Template
900+ from pages .templatetags .pages_tags import get_page_content
901+
902+ # Get content directly to check structure
903+ context = Context ({'page' : self .test_page })
904+ content = get_page_content (context , self .test_page )
905+
906+ # Each item should be a dict with required keys
907+ for item in content :
908+ self .assertIsInstance (item , dict , "Content item should be a dictionary" )
909+ self .assertIn ('name' , item , "Item missing 'name' key" )
910+ self .assertIn ('type' , item , "Item missing 'type' key" )
911+ self .assertIn ('value' , item , "Item missing 'value' key" )
912+ self .assertIsInstance (item ['name' ], str , "Item name should be a string" )
913+ self .assertIsInstance (item ['type' ], str , "Item type should be a string" )
914+ self .assertIsInstance (item ['value' ], str , "Item value should be a string" )
0 commit comments