import pytest from wagtail.models import Site from apps.blog.models import AboutPage, ArticleIndexPage from apps.core.models import NavigationMenuItem, SiteSettings, SocialMediaLink @pytest.fixture def site_with_nav(home_page): """Create SiteSettings with nav items and social links for testing.""" site = Site.objects.get(is_default_site=True) settings, _ = SiteSettings.objects.get_or_create(site=site) # Clear any items seeded by the data migration settings.navigation_items.all().delete() settings.social_links.all().delete() # Create article index and about page article_index = ArticleIndexPage(title="Articles", slug="articles") home_page.add_child(instance=article_index) article_index.save_revision().publish() about = AboutPage( title="About", slug="about", mission_statement="Test mission", body="
About page
", ) home_page.add_child(instance=about) about.save_revision().publish() # Create nav items NavigationMenuItem.objects.create( settings=settings, link_page=home_page, link_title="Home", show_in_header=True, show_in_footer=True, sort_order=0, ) NavigationMenuItem.objects.create( settings=settings, link_page=article_index, link_title="Articles", show_in_header=True, show_in_footer=True, sort_order=1, ) NavigationMenuItem.objects.create( settings=settings, link_page=about, link_title="About", show_in_header=True, show_in_footer=False, sort_order=2, ) # Social links SocialMediaLink.objects.create( settings=settings, platform="twitter", url="https://twitter.com/nohypeai", label="Twitter (X)", sort_order=0, ) SocialMediaLink.objects.create( settings=settings, platform="rss", url="/feed/", label="RSS Feed", sort_order=1, ) return settings @pytest.mark.django_db class TestNavigationMenuItem: def test_live_page_is_rendered(self, site_with_nav): items = [i for i in site_with_nav.navigation_items.all() if i.is_live] assert len(items) == 3 def test_unpublished_page_excluded(self, site_with_nav): about_item = site_with_nav.navigation_items.get(link_title="About") about_item.link_page.unpublish() items = [i for i in site_with_nav.navigation_items.all() if i.is_live] assert len(items) == 2 assert all(i.link_title != "About" for i in items) def test_external_url_item(self, site_with_nav): NavigationMenuItem.objects.create( settings=site_with_nav, link_url="https://example.com", link_title="External", sort_order=10, ) item = site_with_nav.navigation_items.get(link_title="External") assert item.is_live is True assert item.url == "https://example.com" assert item.title == "External" def test_title_falls_back_to_page_title(self, site_with_nav): item = site_with_nav.navigation_items.get(sort_order=0) item.link_title = "" item.save() assert item.title == item.link_page.title def test_header_footer_filtering(self, site_with_nav): header_items = site_with_nav.navigation_items.filter(show_in_header=True) footer_items = site_with_nav.navigation_items.filter(show_in_footer=True) assert header_items.count() == 3 assert footer_items.count() == 2 # About excluded from footer def test_sort_order_respected(self, site_with_nav): items = list(site_with_nav.navigation_items.all().order_by("sort_order")) assert [i.link_title for i in items] == ["Home", "Articles", "About"] @pytest.mark.django_db class TestSocialMediaLink: def test_display_label_from_field(self, site_with_nav): link = site_with_nav.social_links.get(platform="twitter") assert link.display_label == "Twitter (X)" def test_display_label_fallback(self, site_with_nav): link = site_with_nav.social_links.get(platform="twitter") link.label = "" assert link.display_label == "Twitter / X" def test_icon_template_path(self, site_with_nav): link = site_with_nav.social_links.get(platform="rss") assert link.icon_template == "components/icons/rss.html" def test_ordering(self, site_with_nav): links = list(site_with_nav.social_links.all().order_by("sort_order")) assert [link.platform for link in links] == ["twitter", "rss"] @pytest.mark.django_db class TestSiteSettingsDefaults: def test_default_site_name(self, home_page): site = Site.objects.get(is_default_site=True) settings, _ = SiteSettings.objects.get_or_create(site=site) assert settings.site_name == "NO HYPE AI" def test_default_copyright(self, home_page): site = Site.objects.get(is_default_site=True) settings, _ = SiteSettings.objects.get_or_create(site=site) assert settings.copyright_text == "No Hype AI. All rights reserved." def test_default_tagline(self, home_page): site = Site.objects.get(is_default_site=True) settings, _ = SiteSettings.objects.get_or_create(site=site) assert settings.tagline == "Honest AI tool reviews for developers." @pytest.mark.django_db class TestNavRendering: def test_header_shows_nav_items(self, client, site_with_nav): resp = client.get("/") content = resp.content.decode() assert "Home" in content assert "Articles" in content assert "About" in content def test_unpublished_page_not_in_header(self, client, site_with_nav): about_item = site_with_nav.navigation_items.get(link_title="About") about_item.link_page.unpublish() resp = client.get("/") content = resp.content.decode() # About should not appear as a nav link (but might appear elsewhere on page) assert 'href="/about/"' not in content def test_footer_shows_nav_items(self, client, site_with_nav): resp = client.get("/") content = resp.content.decode() # Footer should have social links assert "Twitter (X)" in content assert "RSS Feed" in content def test_footer_shows_branding(self, client, site_with_nav): site_with_nav.site_name = "TEST SITE" site_with_nav.save() resp = client.get("/") content = resp.content.decode() assert "TEST SITE" in content def test_footer_shows_copyright(self, client, site_with_nav): resp = client.get("/") content = resp.content.decode() assert "No Hype AI. All rights reserved." in content