#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 本地测试驱动运行器 (Local TDD Test Runner) 与各 PHP 单元测试断言 100% 对齐,提供极速本地验证反馈 """ import os import re import sys import unittest BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if BASE_DIR not in sys.path: sys.path.insert(0, BASE_DIR) class TestResult: def __init__(self, name): self.name = name self.passed = 0 self.failed = 0 self.messages = [] def assert_true(self, condition, message): if condition: self.passed += 1 self.messages.append(f" [PASS] {message}") else: self.failed += 1 self.messages.append(f" [FAIL] {message}") def summary(self): print(f"\n=== {self.name} 测试结果: {self.passed} 通过, {self.failed} 失败 ===") for msg in self.messages: print(msg) return self.failed == 0 def test_cases_page(): res = TestResult("案例独立页 (CasesPage)") list_html_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_case_show', 'list.html') list_e_html_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_case_show', 'list_e.html') css_path = os.path.join(BASE_DIR, 'public', 'assets', 'addons', 'official', 'css', 'modern_nhc.css') html = open(list_html_path, 'r', encoding='utf-8').read() if os.path.exists(list_html_path) else '' mobile_html = open(list_e_html_path, 'r', encoding='utf-8').read() if os.path.exists(list_e_html_path) else '' css = open(css_path, 'r', encoding='utf-8').read() if os.path.exists(css_path) else '' res.assert_true('纳海川' in html, "PC 案例页必须明确包含品牌名称【纳海川】") res.assert_true(not re.search(r'纳川(?!海)', html), "PC 案例页严禁错误简称为【纳川】") has_filter = 'nhc-case-filter' in html or '全部案例' in html res.assert_true(has_filter, "PC 案例页必须包含【筛选】板块") has_chal = '业务挑战' in html or 'CHALLENGE' in html has_sol = '技术方案' in html or 'SOLUTION' in html has_res = '成果验证' in html or 'RESULT' in html res.assert_true(has_chal and has_sol and has_res, "PC 案例页必须包含【挑战、方案、结果】档案") res.assert_true('nhc-case-metrics' in html or '数据验证' in html, "PC 案例页必须包含【数据】板块") has_metrics = '%' in html and ('10W+' in html or '300+' in html or 'ms' in html or '50' in html) res.assert_true(has_metrics, "去AI味道:具备真实可信的量化业务指标数据") has_emoji = bool(re.search(r'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF\u2600-\u26FF\u2700-\u27BF]', html)) res.assert_true(not has_emoji, "案例页严禁使用任何 emoji 表情符号") res.assert_true('#2563EB' in css or '#2563eb' in css, "沿用科技蓝 #2563EB 主色规范") res.assert_true('SimSun' in css or 'Songti' in css or 'Noto Serif SC' in css, "沿用宋体标题规范") res.assert_true(bool(mobile_html), "移动端案例模板 list_e.html 必须存在") if mobile_html: res.assert_true('纳海川' in mobile_html, "移动端模板必须包含品牌名【纳海川】") res.assert_true('nhc-case-filter' in mobile_html, "移动端模板必须包含多维案例筛选器") res.assert_true('CHALLENGE' in mobile_html or '业务挑战' in mobile_html, "移动端模板必须包含标杆案例挑战/方案/结果") res.assert_true('nhc-case-metrics' in mobile_html, "移动端模板必须包含数据指标墙") return res.summary() def test_services_page(): res = TestResult("服务独立页 (ServicesPage)") svc_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_product', 'service_page.html') list_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_product', 'list.html') css_path = os.path.join(BASE_DIR, 'public', 'assets', 'addons', 'official', 'css', 'modern_nhc.css') html = '' if os.path.exists(svc_path): html += open(svc_path, 'r', encoding='utf-8').read() + '\n' if os.path.exists(list_path): html += open(list_path, 'r', encoding='utf-8').read() + '\n' css = open(css_path, 'r', encoding='utf-8').read() if os.path.exists(css_path) else '' res.assert_true('纳海川' in html, "服务页必须明确包含品牌名称【纳海川】") res.assert_true(not re.search(r'纳川(?!海)', html), "服务页严禁错误简称为【纳川】") res.assert_true('软件开发' in html and 'APP' in html and '智能体' in html, "服务页必须涵盖软件开发、APP定制、智能体开发") has_cat = 'nhc-services-categories' in html or '服务分类' in html or '服务矩阵' in html res.assert_true(has_cat, "包含【分类】板块") has_cap = 'nhc-tech-capabilities' in html or '技术能力' in html or '技术底座' in html res.assert_true(has_cap, "包含【能力】板块") has_proc = 'nhc-delivery-process' in html or '交付流程' in html or '研发流程' in html res.assert_true(has_proc, "包含【流程】板块") has_deliv = 'nhc-deliverables' in html or '交付物' in html or '交付标准' in html res.assert_true(has_deliv, "包含【交付】清单") has_faq = 'nhc-faq' in html or '常见问答' in html or '技术问答' in html res.assert_true(has_faq, "包含【FAQ】板块") return res.summary() def test_products_page(): res = TestResult("产品独立页 (ProductsPage)") prd_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_product', 'product_page.html') list_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_product', 'list.html') html = '' if os.path.exists(prd_path): html += open(prd_path, 'r', encoding='utf-8').read() + '\n' if os.path.exists(list_path): html += open(list_path, 'r', encoding='utf-8').read() + '\n' res.assert_true('纳海川' in html, "产品页必须明确包含品牌名称【纳海川】") res.assert_true(not re.search(r'纳川(?!海)', html), "产品页严禁错误简称为【纳川】") res.assert_true('商城' in html and '收银' in html and '进销存' in html and 'SaaS' in html, "产品页必须涵盖商城、收银、进销存、SaaS版本") has_matrix = 'nhc-product-matrix' in html or '产品矩阵' in html or '商业矩阵' in html res.assert_true(has_matrix, "包含【矩阵】板块") has_features = 'nhc-product-features' in html or '功能架构' in html or '核心功能' in html res.assert_true(has_features, "包含【功能】板块") has_editions = 'nhc-product-editions' in html or '版本对比' in html or '版本选型' in html res.assert_true(has_editions, "包含【版本】板块") has_pricing = 'nhc-product-pricing' in html or '定价' in html or '部署模式' in html or '商业授权' in html res.assert_true(has_pricing, "包含【定价】板块") has_demo = 'nhc-product-demo' in html or '在线演示' in html or '预约演示' in html or '申请演示' in html res.assert_true(has_demo, "包含【演示】板块") return res.summary() def test_nav_megamenu(): res = TestResult("导航二级卡片面板 (NavMegaMenu)") nav_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_common', 'pc', 'nav.html') css_path = os.path.join(BASE_DIR, 'public', 'assets', 'addons', 'official', 'css', 'modern_nhc.css') html = open(nav_path, 'r', encoding='utf-8').read() if os.path.exists(nav_path) else '' css = open(css_path, 'r', encoding='utf-8').read() if os.path.exists(css_path) else '' res.assert_true('nhc-has-dropdown' in html, "导航栏必须具备 nhc-has-dropdown 下拉菜单触发类") res.assert_true('nhc-mega-panel' in html, "导航栏必须具备 nhc-mega-panel 二级卡片面板容器") res.assert_true('软件开发' in html and '智能体开发' in html, "服务二级面板包含核心服务") res.assert_true('商城' in html and '收银' in html and '进销存' in html and 'SaaS' in html, "产品二级面板包含核心产品") res.assert_true('.nhc-mega-panel' in css, "CSS 包含 .nhc-mega-panel 卡片面板样式") res.assert_true('.nhc-has-dropdown:hover' in css, "CSS 包含鼠标悬停触发规则") return res.summary() def test_about_page(): res = TestResult("关于我们独立页 (AboutPage)") single_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_home', 'single.html') single_e_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_home', 'single_e.html') css_path = os.path.join(BASE_DIR, 'public', 'assets', 'addons', 'official', 'css', 'modern_nhc.css') html = open(single_path, 'r', encoding='utf-8').read() if os.path.exists(single_path) else '' mobile_html = open(single_e_path, 'r', encoding='utf-8').read() if os.path.exists(single_e_path) else '' css = open(css_path, 'r', encoding='utf-8').read() if os.path.exists(css_path) else '' res.assert_true('纳海川' in html, "PC 关于我们页必须明确包含品牌名称【纳海川】") res.assert_true(not re.search(r'纳川(?!海)', html), "PC 关于我们页严禁错误简称为【纳川】") has_brand = 'nhc-about-brand' in html or '工程哲学' in html or '品牌' in html res.assert_true(has_brand, "必须包含【品牌】(品牌渊源与东方工程哲学)板块") has_team = 'nhc-about-team' in html or '技术委员会' in html or '核心团队' in html res.assert_true(has_team, "必须包含【团队】(技术委员会专家与核心团队)板块") has_certs = 'nhc-about-qualifications' in html or '软件著作权' in html or '合规体系' in html res.assert_true(has_certs, "必须包含【资质】(权威资质、软著资产与安全合规体系)板块") has_milestones = '2016' in html or '2019' in html or '2024' in html or '发展历程' in html res.assert_true(has_milestones, "去AI味道:展示具体发展历程或里程碑") has_tech = '架构师' in html or '全栈' in html or '智能体' in html res.assert_true(has_tech, "去AI味道:展示严谨技术职称与专业领域") has_certs_concrete = 'ISO' in html or '著作权' in html or '等保' in html res.assert_true(has_certs_concrete, "去AI味道:展示具体行业认证体系与软著资产") has_emoji = bool(re.search(r'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF\u2600-\u26FF\u2700-\u27BF]', html)) res.assert_true(not has_emoji, "严禁使用任何 emoji 表情符号") res.assert_true(bool(mobile_html), "移动端关于我们模板 single_e.html 必须存在") if mobile_html: res.assert_true('纳海川' in mobile_html, "移动端模板包含品牌名【纳海川】") res.assert_true('团队' in mobile_html or '专家' in mobile_html, "移动端模板包含核心团队介绍") res.assert_true('资质' in mobile_html or '著作权' in mobile_html, "移动端模板包含资质认证板块") return res.summary() def test_contact_page(): res = TestResult("联系我们独立页 (ContactPage)") contact_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_online_message', 'list.html') contact_e_path = os.path.join(BASE_DIR, 'addons', 'official', 'view', 'web', 'official_online_message', 'list_e.html') css_path = os.path.join(BASE_DIR, 'public', 'assets', 'addons', 'official', 'css', 'modern_nhc.css') html = open(contact_path, 'r', encoding='utf-8').read() if os.path.exists(contact_path) else '' mobile_html = open(contact_e_path, 'r', encoding='utf-8').read() if os.path.exists(contact_e_path) else '' css = open(css_path, 'r', encoding='utf-8').read() if os.path.exists(css_path) else '' res.assert_true('纳海川' in html, "PC 联系我们页必须明确包含品牌名称【纳海川】") res.assert_true(not re.search(r'纳川(?!海)', html), "PC 联系我们页严禁错误简称为【纳川】") has_form = '