"""apps.core 基础单元测试:SEOablePage 抽象基类字段与公共 Block。""" import pytest from rest_framework.test import APIClient from apps.core.blocks import FormBlock from apps.core.models import ( NavigationMenu, NavigationMenuItem, Partner, SimpleContentPage, SiteSettings, TeamMember, Testimonial, ) from apps.forms.models import FormDefinition, FormDefinitionField pytestmark = pytest.mark.django_db def test_seoable_page_fields_available_on_subclass(home_page): """SEOablePage 是抽象基类,其 SEO 字段应出现在具体子类(HomePage)上。""" home_page.seo_title_override = "自定义标题" home_page.seo_description_override = "自定义描述" home_page.canonical_url = "https://example.com/" home_page.schema_json = {"@type": "Organization"} home_page.save() home_page.refresh_from_db() assert home_page.seo_title_override == "自定义标题" assert home_page.seo_description_override == "自定义描述" assert home_page.canonical_url == "https://example.com/" assert home_page.schema_json == {"@type": "Organization"} def test_form_block_api_representation_expands_fields(): """FormBlock.get_api_representation 应展开 FormDefinition 及其子字段, 而不是仅返回 SnippetChooserBlock 默认的主键。""" form_def = FormDefinition.objects.create( name="联系我们", submit_button_text="立即提交", success_message="已收到您的信息", ) FormDefinitionField.objects.create( form=form_def, label="姓名", field_key="name", field_type="text", required=True, ) FormDefinitionField.objects.create( form=form_def, label="意向", field_key="interest", field_type="select", required=False, choices="产品咨询, 合作洽谈", ) block = FormBlock() result = block.get_api_representation({"form": form_def}) assert result["form"]["id"] == form_def.pk assert result["form"]["name"] == "联系我们" assert result["form"]["submit_button_text"] == "立即提交" assert len(result["form"]["fields"]) == 2 assert result["form"]["fields"][1]["choices"] == ["产品咨询", "合作洽谈"] def test_form_block_api_representation_handles_empty_form(): block = FormBlock() result = block.get_api_representation({"form": None}) assert result == {"form": None} def test_simple_content_page_can_be_created_under_home(home_page): """隐私政策等法务页面应可作为 HomePage 的子页面创建,并保留富文本内容。""" page = SimpleContentPage( title="隐私政策", slug="privacy-policy", body="

我们重视您的个人信息保护。

", ) home_page.add_child(instance=page) page.refresh_from_db() assert SimpleContentPage.objects.live().descendant_of(home_page).count() == 1 assert "个人信息保护" in page.body def test_team_member_default_ordering(): """团队成员应按 order 字段升序排列。""" TeamMember.objects.create(name="李四", order=2) TeamMember.objects.create(name="张三", order=1) names = list(TeamMember.objects.values_list("name", flat=True)) assert names == ["张三", "李四"] def test_testimonial_str_includes_author_and_quote(): testimonial = Testimonial.objects.create( quote="非常专业的服务,效果超出预期。", author_name="王经理" ) assert "王经理" in str(testimonial) def test_partner_str_returns_name(): partner = Partner.objects.create(name="示例合作伙伴") assert str(partner) == "示例合作伙伴" def test_navigation_menu_item_url_prefers_external_link_over_page(home_page): menu = NavigationMenu.objects.create(name="main") item = NavigationMenuItem.objects.create( menu=menu, label="首页", link_page=home_page, link_url="https://example.com" ) assert item.url == "https://example.com" def test_navigation_menu_item_url_falls_back_to_page_url(home_page): menu = NavigationMenu.objects.create(name="main") item = NavigationMenuItem.objects.create(menu=menu, label="首页", link_page=home_page) assert item.url == home_page.url def test_navigation_menu_item_url_defaults_to_hash_when_empty(): menu = NavigationMenu.objects.create(name="main") item = NavigationMenuItem.objects.create(menu=menu, label="占位") assert item.url == "#" def test_site_settings_for_site_creates_singleton_with_defaults(): from wagtail.models import Site site = Site.objects.get(is_default_site=True) settings_obj = SiteSettings.for_site(site) assert settings_obj.icp_url == "https://beian.miit.gov.cn/" # 再次获取应复用同一条记录而非重复创建 assert SiteSettings.for_site(site).pk == settings_obj.pk def test_team_api_returns_ordered_members(): TeamMember.objects.create(name="李四", role="工程师", order=2) TeamMember.objects.create(name="张三", role="总经理", order=1) client = APIClient() response = client.get("/api/v1/custom/core/team/") assert response.status_code == 200 items = response.data["items"] assert [item["name"] for item in items] == ["张三", "李四"] assert items[0]["role"] == "总经理" def test_testimonial_api_returns_list(): Testimonial.objects.create(quote="效果很好", author_name="客户A") client = APIClient() response = client.get("/api/v1/custom/core/testimonials/") assert response.status_code == 200 assert response.data["items"][0]["author_name"] == "客户A" def test_partner_api_returns_list(): Partner.objects.create(name="伙伴A", website_url="https://partner-a.example.com") client = APIClient() response = client.get("/api/v1/custom/core/partners/") assert response.status_code == 200 assert response.data["items"][0]["name"] == "伙伴A" def test_navigation_menu_api_returns_items_by_name(home_page): menu = NavigationMenu.objects.create(name="main") NavigationMenuItem.objects.create(menu=menu, label="首页", link_page=home_page, sort_order=0) NavigationMenuItem.objects.create(menu=menu, label="外部链接", link_url="https://example.com", sort_order=1) client = APIClient() response = client.get("/api/v1/custom/core/navigation/?name=main") assert response.status_code == 200 assert response.data["name"] == "main" assert len(response.data["items"]) == 2 assert response.data["items"][1]["url"] == "https://example.com" def test_navigation_menu_api_404_when_missing(): client = APIClient() response = client.get("/api/v1/custom/core/navigation/?name=does-not-exist") assert response.status_code == 404 def test_site_settings_api_returns_defaults(): client = APIClient() response = client.get("/api/v1/custom/core/site-settings/") assert response.status_code == 200 assert response.data["icp_url"] == "https://beian.miit.gov.cn/"