diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71cdc9b --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Python 缓存与编译产物 +__pycache__/ +*.py[cod] +*$py.class + +# 测试与覆盖率产物 +tests/ +.pytest_cache/ +.coverage +.coverage.* +htmlcov/ + +# 类型检查与代码质量工具缓存 +.mypy_cache/ +.pyright/ +.ruff_cache/ + +# Python 虚拟环境 +.venv/ +venv/ +env/ + +# 编辑器与操作系统文件 +.idea/ +.vscode/ +.DS_Store +Thumbs.db + +# 本地日志和临时文件 +*.log +*.tmp +*.temp +*.bak +*.swp +*~ diff --git a/core/jx3box_data.py b/core/jx3box_data.py index 4211632..322c748 100644 --- a/core/jx3box_data.py +++ b/core/jx3box_data.py @@ -134,7 +134,7 @@ class JX3BOXService: params = { "per": "10", "page": "1", - "tags": "", + "tags": tags, "client": "std", "global_level": "130", "mount": mount, diff --git a/tests/test_template_system.py b/tests/test_template_system.py deleted file mode 100644 index 95b0cb5..0000000 --- a/tests/test_template_system.py +++ /dev/null @@ -1,267 +0,0 @@ -import asyncio -import re -import unittest -from pathlib import Path - -from jinja2 import ChainableUndefined, Environment - -from core.template import TemplateRepository - - -ROOT = Path(__file__).parent.parent -TEMPLATE_ROOT = ROOT / "templates" -SPECIAL_PAGE_STYLES = { - "baizhan", - "chengbeng", - "chengjiu", - "fubenjilu", - "helps", - "jiaoyihang", - "juesheliaotian", - "richangyuche", - "wujia", - "xingxiashijian", - "zhanji", - "zili", - "zilipaixing", -} - - -class TemplateRepositoryTests(unittest.TestCase): - def setUp(self): - self.repository = TemplateRepository(TEMPLATE_ROOT) - - def test_all_pages_compose_to_valid_jinja_documents(self): - pages = sorted((TEMPLATE_ROOT / "pages").glob("*.html")) - page_styles = sorted((TEMPLATE_ROOT / "styles" / "pages").glob("*.css")) - self.assertEqual(46, len(pages)) - self.assertEqual( - SPECIAL_PAGE_STYLES, - {style.stem for style in page_styles}, - ) - - environment = Environment(undefined=ChainableUndefined) - empty_context = { - "data": {}, - "icons": {"img": {}, "sect": {}, "serendipity": {}}, - "items": [], - "summary": {}, - } - for page in pages: - with self.subTest(page=page.name): - fragment = page.read_text(encoding="utf-8") - for document_tag in ("!DOCTYPE", "html", "head", "style", "body"): - self.assertIsNone( - re.search(rf"<{document_tag}(?:\s|>)", fragment, re.IGNORECASE) - ) - - template = asyncio.run(self.repository.get(page.name)) - self.assertIn("", template) - self.assertIn("
", template) - self.assertNotIn("", template) - self.assertNotIn("/*__PAGE_CSS__*/", template) - self.assertNotIn("/* @component", template) - self.assertNotIn("/* @endcomponent */", template) - rendered = environment.from_string(template).render(empty_context) - self.assertIn("", rendered) - - def test_repeated_page_patterns_use_shared_components(self): - components = (TEMPLATE_ROOT / "styles" / "components.css").read_text( - encoding="utf-8" - ) - for selector in ( - ".data-table", - ".data-cell--rank", - ".card-grid", - ".ability-card", - ".collection-card", - ".object-card", - ): - self.assertIn(selector, components) - - expected_components = { - "bilei.html": "data-table", - "rank_role.html": "data-cell--rank", - "jineng.html": "ability-card", - "juesheqiyu.html": "collection-card", - "qiwu.html": "object-card", - } - for name, component in expected_components.items(): - with self.subTest(page=name): - fragment = (TEMPLATE_ROOT / "pages" / name).read_text( - encoding="utf-8" - ) - self.assertIn(component, fragment) - page_style = TEMPLATE_ROOT / "styles" / "pages" / ( - f"{Path(name).stem}.css" - ) - self.assertFalse(page_style.exists()) - - def test_image_templates_do_not_define_responsive_breakpoints(self): - for style in sorted((TEMPLATE_ROOT / "styles").rglob("*.css")): - with self.subTest(style=style.relative_to(TEMPLATE_ROOT)): - content = style.read_text(encoding="utf-8") - self.assertIsNone( - re.search(r"@media\s*(?:screen\s+and\s+)?\([^)]*width", content) - ) - - base = (TEMPLATE_ROOT / "styles" / "base.css").read_text(encoding="utf-8") - self.assertIn("min-width: calc(var(--jx3-page-width) + 94px)", base) - self.assertIn("width: var(--jx3-page-width)", base) - self.assertNotIn("100vw", base) - - def test_only_declared_component_blocks_are_injected(self): - table_page = asyncio.run(self.repository.get("bilei.html")) - self.assertIn(".data-table--spaced", table_page) - self.assertNotIn(".ability-card__head", table_page) - self.assertNotIn(".object-card__footer", table_page) - - ability_page = asyncio.run(self.repository.get("jineng.html")) - self.assertIn(".card-grid", ability_page) - self.assertIn(".ability-card__head", ability_page) - self.assertNotIn(".data-table--spaced", ability_page) - self.assertNotIn(".object-card__footer", ability_page) - - object_page = asyncio.run(self.repository.get("qiwu.html")) - self.assertIn(".object-card__footer", object_page) - self.assertNotIn(".ability-card__head", object_page) - - def test_wujia_groups_follow_the_api_names_instead_of_list_positions(self): - """万宝楼分组在真实返回中位于列表末尾,且在售组名为“在售期”。""" - template = asyncio.run(self.repository.get("wujia.html")) - rendered = Environment(undefined=ChainableUndefined).from_string(template).render( - { - "icons": {"img": {}, "sect": {}, "serendipity": {}}, - "name": "浮屠明音礼盒", - "alias": "", - "view": "", - "desc": "", - "category": "外观礼盒", - "date": "2018-08-24", - "retail": 888, - "list": [ - {"name": "电信区", "list": []}, - {"name": "双线区", "list": []}, - {"name": "无界区", "list": []}, - { - "name": "梦江南", - "list": [ - { - "date": "QUERY-MARKER", - "server": "梦江南", - "value": 4700, - "sale": 4, - } - ], - }, - {"name": "公示期", "list": []}, - { - "name": "在售期", - "list": [ - { - "date": "SALE-MARKER", - "zone": "电信区", - "server": "梦江南", - "value": 5188, - } - ], - }, - ], - } - ) - - sale_start = rendered.index('