baseline: 批次A-D 成果 + membership 半成品(测试红)
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
"""批次 C3 · 营销官网测试。
|
||||
|
||||
覆盖:页面可达、SEO meta/结构化数据、价格页数据与 Plan 同源、行业页只写已实现特性
|
||||
("不写纸面功能")、移动端 viewport。
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from django.test import Client
|
||||
|
||||
from apps.billing.models import Plan, seed_plans
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def site(db):
|
||||
seed_plans()
|
||||
return Client()
|
||||
|
||||
|
||||
PAGES = [
|
||||
("/site/", "AI 开单"),
|
||||
("/site/pricing/", "价格与功能对比"),
|
||||
("/site/industry/food/", "食品饮料"),
|
||||
("/site/industry/hardware/", "五金建材"),
|
||||
("/site/industry/autoparts/", "汽配"),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("url,needle", PAGES)
|
||||
def test_pages_reachable(site, url, needle):
|
||||
resp = site.get(url)
|
||||
assert resp.status_code == 200, url
|
||||
html = resp.content.decode("utf-8")
|
||||
assert needle in html
|
||||
|
||||
|
||||
@pytest.mark.parametrize("url,_needle", PAGES)
|
||||
def test_pages_have_seo_meta(site, url, _needle):
|
||||
"""每页都要有 title / description / canonical / 结构化数据 / viewport。"""
|
||||
html = site.get(url).content.decode("utf-8")
|
||||
assert "<title>" in html
|
||||
assert 'name="description"' in html
|
||||
assert 'rel="canonical"' in html
|
||||
assert 'application/ld+json' in html
|
||||
assert 'name="viewport"' in html
|
||||
assert "width=device-width" in html
|
||||
|
||||
|
||||
def test_pricing_reads_plan_limits(site):
|
||||
"""价格页的额度数字必须来自 Plan.limits(与系统校验同源)。"""
|
||||
html = site.get("/site/pricing/").content.decode("utf-8")
|
||||
free = Plan.objects.get(code="free")
|
||||
basic = Plan.objects.get(code="basic")
|
||||
pro = Plan.objects.get(code="pro")
|
||||
|
||||
assert free.name in html and basic.name in html and pro.name in html
|
||||
assert "998" in html and "4800" in html
|
||||
# 免费版 100 商品 / 基础版 3000 商品
|
||||
assert f"{free.limits['products']:,}" in html
|
||||
assert f"{basic.limits['products']:,}" in html
|
||||
# 专业版不限项展示为"不限"
|
||||
assert "不限" in html
|
||||
|
||||
|
||||
def test_pricing_flag_row_uses_checkmark(site):
|
||||
html = site.get("/site/pricing/").content.decode("utf-8")
|
||||
assert "✓" in html # 支持的项打勾
|
||||
assert "—" in html # 不支持的项破折号(free 无订货商城)
|
||||
|
||||
|
||||
def test_home_lists_three_ai_sellpoints(site):
|
||||
html = site.get("/site/").content.decode("utf-8")
|
||||
assert "AI 应收风险预警" in html
|
||||
assert "AI 录单" in html
|
||||
assert "AI 经营问答" in html
|
||||
# 独家卖点有标注
|
||||
assert "独家" in html
|
||||
|
||||
|
||||
def test_home_lists_six_roles(site):
|
||||
html = site.get("/site/").content.decode("utf-8")
|
||||
for role in ["老板", "财务", "销售", "仓管", "采购", "运营"]:
|
||||
assert role in html, role
|
||||
|
||||
|
||||
def test_food_page_claims_only_shipped_features(site):
|
||||
"""食品页卖点必须都是已交付的:批次/FEFO/临期预警/多单位/信用额度。"""
|
||||
html = site.get("/site/industry/food/").content.decode("utf-8")
|
||||
for kw in ["批次账", "FEFO", "临期自动预警", "多单位换算", "信用额度"]:
|
||||
assert kw in html, kw
|
||||
|
||||
|
||||
def test_hardware_page_claims_only_shipped_features(site):
|
||||
html = site.get("/site/industry/hardware/").content.decode("utf-8")
|
||||
for kw in ["换算率", "三档抹零", "最低售价管控", "价格历史参考"]:
|
||||
assert kw in html, kw
|
||||
|
||||
|
||||
def test_autoparts_page_marks_unshipped_as_planned(site):
|
||||
"""未交付的 SN 追溯必须明确标注"规划中",不得写成已有功能。"""
|
||||
html = site.get("/site/industry/autoparts/").content.decode("utf-8")
|
||||
assert "规划中" in html
|
||||
assert "序列号" in html
|
||||
# 明确说明尚未交付
|
||||
assert "尚未交付" in html or "路线图" in html
|
||||
|
||||
|
||||
def test_demo_cta_links_present(site):
|
||||
"""每页都要有试用入口(转化路径)。"""
|
||||
for url, _ in PAGES:
|
||||
html = site.get(url).content.decode("utf-8")
|
||||
assert "免费试用" in html or "免注册体验" in html, url
|
||||
|
||||
|
||||
def test_site_does_not_shadow_spa(site):
|
||||
"""官网挂在 /site/ 下,不能抢掉 SPA 的根路径。"""
|
||||
resp = site.get("/")
|
||||
assert resp.status_code == 200
|
||||
# 根路径返回 SPA(FileResponse 流式返回 index.html),不含官网导航
|
||||
body = b"".join(resp.streaming_content).decode("utf-8", errors="ignore")
|
||||
assert "site/pricing" not in body
|
||||
Reference in New Issue
Block a user