241 lines
9.1 KiB
Python
241 lines
9.1 KiB
Python
"""
|
|
UI 重设计 BUG 修复验证测试
|
|
|
|
关联文档:docs/BUG/BUG-00001-UI重设计后用户反馈问题清单.md
|
|
测试内容:
|
|
- BUG-002: 选中账号名称显示
|
|
- BUG-003: 设置页面自动加载
|
|
- BUG-004: 弹窗居中
|
|
- BUG-010: 仪表盘统计数据
|
|
- 前端 HTML 结构完整性检查
|
|
"""
|
|
|
|
import re
|
|
import unittest
|
|
|
|
from tests._import_app import import_web_app_module
|
|
|
|
|
|
class TestUIRedesignBugFixes(unittest.TestCase):
|
|
"""UI 重设计 BUG 修复验证测试类"""
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.module = import_web_app_module()
|
|
cls.app = cls.module.app
|
|
|
|
def _login(self, client):
|
|
resp = client.post("/login", json={"password": "testpass123"})
|
|
self.assertEqual(resp.status_code, 200)
|
|
|
|
def _get_client(self):
|
|
"""Get a logged-in test client"""
|
|
client = self.app.test_client()
|
|
self._login(client)
|
|
return client
|
|
|
|
def _get_text(self, client, path):
|
|
"""Read response text and close the underlying file handle promptly."""
|
|
resp = client.get(path)
|
|
try:
|
|
return resp.status_code, resp.data.decode("utf-8")
|
|
finally:
|
|
resp.close()
|
|
|
|
def _get_json(self, client, path):
|
|
"""Read JSON payload and close the response object."""
|
|
resp = client.get(path)
|
|
try:
|
|
return resp.status_code, resp.get_json()
|
|
finally:
|
|
resp.close()
|
|
|
|
# ==================== BUG-002: 账号栏显示 ====================
|
|
|
|
def test_bug002_current_account_bar_exists(self):
|
|
"""BUG-002: index.html 中存在 currentAccountBar 元素"""
|
|
client = self._get_client()
|
|
_, html = self._get_text(client, "/")
|
|
self.assertIn('id="currentAccountBar"', html)
|
|
self.assertIn('id="currentAccountEmail"', html)
|
|
self.assertIn('id="currentAccount"', html)
|
|
|
|
def test_bug002_accounts_js_shows_account_bar(self):
|
|
"""BUG-002: accounts.js 中 selectAccount 应操作 currentAccountBar 而非 currentAccount"""
|
|
client = self._get_client()
|
|
_, js = self._get_text(client, "/static/js/features/accounts.js")
|
|
self.assertIn("currentAccountBar", js, "selectAccount() 应操作 #currentAccountBar 元素")
|
|
|
|
# ==================== BUG-003: 设置页面 ====================
|
|
|
|
def test_bug003_settings_page_has_content(self):
|
|
"""BUG-003: 设置页面应有实质性内容,而非仅占位文字"""
|
|
client = self._get_client()
|
|
_, html = self._get_text(client, "/")
|
|
settings_section = re.search(r'id="page-settings".*?(?=id="page-|$)', html, re.DOTALL)
|
|
self.assertIsNotNone(settings_section, "找不到 page-settings 区域")
|
|
|
|
def test_bug003_navigate_triggers_settings_load(self):
|
|
"""BUG-003: navigate('settings') 应触发设置加载"""
|
|
client = self._get_client()
|
|
_, js = self._get_text(client, "/static/js/main.js")
|
|
self.assertIn("settings", js)
|
|
|
|
# ==================== BUG-004: 弹窗居中 ====================
|
|
|
|
def test_bug004_modal_css_centering(self):
|
|
"""BUG-004: CSS 中 .modal 应有 flex 居中属性"""
|
|
client = self._get_client()
|
|
_, css = self._get_text(client, "/static/css/main.css")
|
|
self.assertIn("align-items: center", css)
|
|
self.assertIn("justify-content: center", css)
|
|
|
|
def test_bug004_modal_content_max_width(self):
|
|
"""BUG-004: .modal-content 应有 max-width 限制"""
|
|
client = self._get_client()
|
|
_, css = self._get_text(client, "/static/css/main.css")
|
|
self.assertIn("max-width: 560px", css)
|
|
|
|
def test_bug004_all_modals_use_modal_class(self):
|
|
"""BUG-004: modals.html 中所有弹窗应使用 class='modal'"""
|
|
client = self._get_client()
|
|
_, html = self._get_text(client, "/")
|
|
modal_ids = re.findall(r'id="(\w+Modal)"', html)
|
|
for modal_id in modal_ids:
|
|
if modal_id == "fullscreenEmailModal":
|
|
continue
|
|
pattern = rf'<div[^>]*id="{modal_id}"[^>]*>'
|
|
match = re.search(pattern, html)
|
|
self.assertIsNotNone(match, f"找不到弹窗 {modal_id}")
|
|
tag = match.group(0)
|
|
self.assertIn(
|
|
'class="modal"',
|
|
tag,
|
|
f"弹窗 {modal_id} 应使用 class='modal',实际: {tag[:80]}",
|
|
)
|
|
|
|
# ==================== BUG-005: 验证码提取 ====================
|
|
|
|
def test_bug005_verification_extract_api_exists(self):
|
|
"""BUG-005: 验证码提取 API 端点存在"""
|
|
client = self._get_client()
|
|
status_code, _ = self._get_json(client, "/api/emails/nonexistent@test.com/extract-verification")
|
|
self.assertIn(status_code, [200, 404], "验证码提取 API 应该返回 200 或 404")
|
|
|
|
def test_bug005_copy_verification_function_exists(self):
|
|
"""BUG-005: JS 中存在 copyVerificationInfo 函数"""
|
|
client = self._get_client()
|
|
_, js = self._get_text(client, "/static/js/features/groups.js")
|
|
self.assertIn("function copyVerificationInfo", js)
|
|
|
|
# ==================== BUG-006: 卡片颜色 ====================
|
|
|
|
def test_bug006_card_color_array_exists(self):
|
|
"""BUG-006: 临时邮箱渲染应有多种颜色"""
|
|
client = self._get_client()
|
|
_, js = self._get_text(client, "/static/js/features/temp_emails.js")
|
|
self.assertIn("renderTempEmailList", js)
|
|
|
|
# ==================== BUG-010: 仪表盘 ====================
|
|
|
|
def test_bug010_dashboard_elements_exist(self):
|
|
"""BUG-010: 仪表盘统计元素存在"""
|
|
client = self._get_client()
|
|
_, html = self._get_text(client, "/")
|
|
for el_id in [
|
|
"statTotalAccounts",
|
|
"statValidTokens",
|
|
"statExpiredTokens",
|
|
"statTempEmails",
|
|
]:
|
|
self.assertIn(f'id="{el_id}"', html, f"仪表盘应包含 #{el_id} 元素")
|
|
|
|
def test_bug010_dashboard_group_list_exists(self):
|
|
"""BUG-010: 仪表盘分组概览列表存在"""
|
|
client = self._get_client()
|
|
_, html = self._get_text(client, "/")
|
|
self.assertIn('id="dashboardGroupList"', html)
|
|
|
|
def test_bug010_load_dashboard_function(self):
|
|
"""BUG-010: loadDashboard 函数存在且调用正确 API"""
|
|
client = self._get_client()
|
|
_, js = self._get_text(client, "/static/js/main.js")
|
|
self.assertIn("function loadDashboard", js)
|
|
self.assertIn("/api/groups", js)
|
|
|
|
def test_bug010_groups_api_returns_data(self):
|
|
"""BUG-010: 分组 API 返回有效数据"""
|
|
client = self._get_client()
|
|
_, data = self._get_json(client, "/api/groups")
|
|
self.assertTrue(data.get("success"), "分组 API 应返回 success=true")
|
|
self.assertIn("groups", data, "分组 API 应包含 groups 字段")
|
|
|
|
# ==================== 结构完整性 ====================
|
|
|
|
def test_all_pages_exist_in_html(self):
|
|
"""所有页面容器存在于 index.html"""
|
|
client = self._get_client()
|
|
_, html = self._get_text(client, "/")
|
|
pages = [
|
|
"page-dashboard",
|
|
"page-mailbox",
|
|
"page-temp-emails",
|
|
"page-refresh-log",
|
|
"page-settings",
|
|
"page-audit",
|
|
]
|
|
for page_id in pages:
|
|
self.assertIn(f'id="{page_id}"', html, f"缺少页面 #{page_id}")
|
|
|
|
def test_sidebar_navigation_items(self):
|
|
"""侧边栏导航项完整"""
|
|
client = self._get_client()
|
|
_, html = self._get_text(client, "/")
|
|
nav_pages = [
|
|
"dashboard",
|
|
"mailbox",
|
|
"temp-emails",
|
|
"refresh-log",
|
|
"settings",
|
|
"audit",
|
|
]
|
|
for page in nav_pages:
|
|
self.assertIn(f'data-page="{page}"', html, f"侧边栏缺少 {page} 导航项")
|
|
|
|
def test_mailbox_three_column_structure(self):
|
|
"""邮箱管理三栏布局结构完整"""
|
|
client = self._get_client()
|
|
_, html = self._get_text(client, "/")
|
|
self.assertIn('class="mailbox-layout"', html)
|
|
self.assertIn('class="groups-column"', html)
|
|
self.assertIn('class="accounts-column"', html)
|
|
self.assertIn('class="emails-column"', html)
|
|
|
|
def test_js_files_load_successfully(self):
|
|
"""所有 JS 文件可正常加载"""
|
|
client = self._get_client()
|
|
js_files = [
|
|
"/static/js/main.js",
|
|
"/static/js/features/groups.js",
|
|
"/static/js/features/accounts.js",
|
|
"/static/js/features/emails.js",
|
|
"/static/js/features/temp_emails.js",
|
|
]
|
|
for js_path in js_files:
|
|
status_code, js = self._get_text(client, js_path)
|
|
self.assertEqual(status_code, 200, f"{js_path} 应返回 200")
|
|
self.assertGreater(len(js), 100, f"{js_path} 内容不应为空")
|
|
|
|
def test_css_loads_successfully(self):
|
|
"""CSS 文件可正常加载"""
|
|
client = self._get_client()
|
|
status_code, css = self._get_text(client, "/static/css/main.css")
|
|
self.assertEqual(status_code, 200)
|
|
self.assertIn("--clr-primary", css)
|
|
self.assertIn("--bg-sidebar", css)
|
|
self.assertIn("--bg-hover", css)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|