Files
novalon-website/e2e-tests/tests/test_responsive.py
T
张翔 f5dec95a83 feat: 添加管理后台页面和功能,优化测试和性能配置
refactor: 重构页面导航和滚动逻辑,提升用户体验

test: 更新测试配置和用例,增加覆盖率和稳定性

perf: 优化性能指标和阈值,适应开发环境需求

ci: 添加Lighthouse CI工作流,集成性能测试

docs: 更新API文档和健康检查端点

fix: 修复登录页面和表单提交问题

style: 调整响应式布局和可访问性改进

chore: 更新依赖项和脚本配置
2026-03-24 10:11:30 +08:00

338 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
响应式设计测试模块
测试网站在不同屏幕尺寸下的响应式表现
"""
import pytest
from typing import Dict, Any
from pages.home_page import HomePage
from pages.contact_page import ContactPage
class TestResponsive:
"""响应式设计测试类"""
@pytest.mark.responsive
@pytest.mark.smoke
def test_homepage_mobile_375(self, home_page: HomePage):
"""测试首页在iPhone SE尺寸下的响应式表现"""
home_page.verify_responsive_design(375, 667)
@pytest.mark.responsive
@pytest.mark.smoke
def test_homepage_mobile_414(self, home_page: HomePage):
"""测试首页在iPhone 8 Plus尺寸下的响应式表现"""
home_page.verify_responsive_design(414, 896)
@pytest.mark.responsive
@pytest.mark.smoke
def test_homepage_tablet_768(self, home_page: HomePage):
"""测试首页在iPad尺寸下的响应式表现"""
home_page.verify_responsive_design(768, 1024)
@pytest.mark.responsive
@pytest.mark.smoke
def test_homepage_desktop_1920(self, home_page: HomePage):
"""测试首页在桌面尺寸下的响应式表现"""
home_page.verify_responsive_design(1920, 1080)
@pytest.mark.responsive
def test_contact_page_mobile_375(self, contact_page: ContactPage):
"""测试联系页面在移动端的响应式表现"""
contact_page.verify_responsive_layout(375)
@pytest.mark.responsive
def test_contact_page_tablet_768(self, contact_page: ContactPage):
"""测试联系页面在平板端的响应式表现"""
contact_page.verify_responsive_layout(768)
@pytest.mark.responsive
def test_contact_page_desktop_1920(self, contact_page: ContactPage):
"""测试联系页面在桌面端的响应式表现"""
contact_page.verify_responsive_layout(1920)
@pytest.mark.responsive
def test_header_responsive_mobile(self, home_page: HomePage):
"""测试页头在移动端的响应式表现"""
home_page.page.set_viewport_size({"width": 375, "height": 667})
home_page.navigate()
# 验证页头可见
home_page.assert_element_visible("header", timeout=5000)
# 移动端应该显示汉堡菜单
menu_button = home_page.page.locator(
"button:has-text('菜单'), .mobile-menu, .menu-toggle, button[aria-label*='menu']"
)
if menu_button.count() > 0:
home_page.logger.info("✅ 移动端页头包含汉堡菜单")
else:
home_page.logger.info("️ 移动端页头可能内联显示所有链接")
@pytest.mark.responsive
def test_header_responsive_desktop(self, home_page: HomePage):
"""测试页头在桌面端的响应式表现"""
home_page.page.set_viewport_size({"width": 1920, "height": 1080})
home_page.navigate()
# 验证页头可见
home_page.assert_element_visible("header", timeout=5000)
# 桌面端应该显示完整导航
nav_links = home_page._find_all("nav a")
assert len(nav_links) >= 5, f"桌面端导航链接不足,当前{len(nav_links)}"
@pytest.mark.responsive
def test_navigation_responsive_mobile(self, home_page: HomePage):
"""测试导航在移动端的响应式表现"""
home_page.page.set_viewport_size({"width": 375, "height": 667})
home_page.navigate()
# 检查导航是否可访问 - 移动端可能隐藏导航或使用汉堡菜单
nav_visible = home_page._is_visible("nav")
mobile_menu_visible = home_page._is_visible(".mobile-menu, .menu-toggle, button[aria-label*='menu']")
header_visible = home_page._is_visible("header")
# 只要页头可见,就认为导航可访问(导航可能在页头内)
assert nav_visible or mobile_menu_visible or header_visible, "移动端导航不可访问"
home_page.logger.info("✅ 移动端导航可访问")
@pytest.mark.responsive
def test_hero_section_responsive(self, home_page: HomePage):
"""测试Hero区域在不同尺寸下的表现"""
viewports = [
(375, 667, "移动端"),
(768, 1024, "平板端"),
(1920, 1080, "桌面端")
]
for width, height, name in viewports:
home_page.page.set_viewport_size({"width": width, "height": height})
home_page.navigate()
# 验证Hero区域可见
hero_visible = home_page._is_visible("section:first-of-type, [class*='hero']")
if hero_visible:
home_page.logger.info(f"{name} Hero区域正常显示")
else:
home_page.logger.warning(f"⚠️ {name} Hero区域可能需要滚动才能显示")
@pytest.mark.responsive
def test_services_grid_responsive(self, home_page: HomePage):
"""测试服务卡片网格在不同尺寸下的响应式表现"""
viewports = [
(375, 667, "移动端"),
(768, 1024, "平板端"),
(1920, 1080, "桌面端")
]
for width, height, name in viewports:
home_page.page.set_viewport_size({"width": width, "height": height})
home_page.navigate()
home_page.scroll_to_section("services")
# 检查服务区域可见
home_page.assert_element_visible("#services, section:has(h2:has-text('业务')), section:has(h2:has-text('服务'))", timeout=5000)
home_page.logger.info(f"{name} 服务区域正常显示")
@pytest.mark.responsive
def test_products_grid_responsive(self, home_page: HomePage):
"""测试产品卡片网格在不同尺寸下的响应式表现"""
viewports = [
(375, 667, "移动端"),
(768, 1024, "平板端"),
(1920, 1080, "桌面端")
]
for width, height, name in viewports:
home_page.page.set_viewport_size({"width": width, "height": height})
home_page.navigate()
home_page.scroll_to_section("products")
# 检查产品区域可见
home_page.assert_element_visible("#products, section:has(h2:has-text('产品'))", timeout=5000)
home_page.logger.info(f"{name} 产品区域正常显示")
@pytest.mark.responsive
def test_news_list_responsive(self, home_page: HomePage):
"""测试新闻列表在不同尺寸下的响应式表现"""
viewports = [
(375, 667, "移动端"),
(768, 1024, "平板端"),
(1920, 1080, "桌面端")
]
for width, height, name in viewports:
home_page.page.set_viewport_size({"width": width, "height": height})
home_page.navigate()
home_page.scroll_to_section("news")
# 检查新闻区域可见
home_page.assert_element_visible("#news, section:has(h2:has-text('新闻')), section:has(h2:has-text('动态'))", timeout=5000)
home_page.logger.info(f"{name} 新闻区域正常显示")
@pytest.mark.responsive
def test_contact_form_responsive(self, home_page: HomePage):
"""测试联系表单在不同尺寸下的响应式表现"""
viewports = [
(375, 667, "移动端"),
(768, 1024, "平板端"),
(1920, 1080, "桌面端")
]
for width, height, name in viewports:
home_page.page.set_viewport_size({"width": width, "height": height})
home_page.navigate()
home_page.scroll_to_section("contact")
# 检查表单可见
form_visible = home_page._is_visible("form")
if form_visible:
home_page.logger.info(f"{name} 联系表单正常显示")
else:
home_page.logger.warning(f"⚠️ {name} 联系表单不可见")
@pytest.mark.responsive
def test_footer_responsive(self, home_page: HomePage):
"""测试页脚在不同尺寸下的响应式表现"""
viewports = [
(375, 667, "移动端"),
(768, 1024, "平板端"),
(1920, 1080, "桌面端")
]
for width, height, name in viewports:
home_page.page.set_viewport_size({"width": width, "height": height})
home_page.navigate()
# 检查页脚可见
home_page.assert_element_visible("footer", timeout=5000)
home_page.logger.info(f"{name} 页脚正常显示")
@pytest.mark.responsive
def test_element_stacking_mobile(self, home_page: HomePage):
"""测试移动端元素堆叠"""
home_page.page.set_viewport_size({"width": 375, "height": 667})
home_page.navigate()
# 滚动检查各个区域
sections = [
"#home, section:first-of-type",
"#about, section:has(h2:has-text('关于'))",
"#services, section:has(h2:has-text('业务')), section:has(h2:has-text('服务'))",
"#products, section:has(h2:has-text('产品'))",
"#news, section:has(h2:has-text('新闻')), section:has(h2:has-text('动态'))",
"#contact, section:has(h2:has-text('联系')), section:has(h2:has-text('联系方式'))"
]
visible_sections = 0
for section in sections:
if home_page._is_visible(section):
visible_sections += 1
# 移动端应该显示至少1个区域
assert visible_sections >= 1, f"移动端可见区域不足,当前{visible_sections}"
@pytest.mark.responsive
def test_touch_target_size_mobile(self, home_page: HomePage):
"""测试移动端触摸目标大小"""
home_page.page.set_viewport_size({"width": 375, "height": 667})
home_page.navigate()
# 检查按钮和链接的大小
buttons = home_page._find_all("button, a.button, .btn")
for button in buttons[:5]: # 只检查前5个
if button.count() > 0:
box = button.first.bounding_box()
if box:
# 触摸目标应该至少44x44像素
assert box["width"] >= 24, f"按钮宽度 {box['width']}px 可能太小"
assert box["height"] >= 24, f"按钮高度 {box['height']}px 可能太小"
@pytest.mark.responsive
def test_text_readability_mobile(self, home_page: HomePage):
"""测试移动端文本可读性"""
home_page.page.set_viewport_size({"width": 375, "height": 667})
home_page.navigate()
# 检查段落文本
paragraphs = home_page._find_all("p")
for para in paragraphs[:3]: # 只检查前3个
if para.count() > 0:
font_size = para.evaluate("el => getComputedStyle(el).fontSize")
# 字体大小应该至少12px
font_size_value = float(font_size.replace("px", ""))
assert font_size_value >= 12, \
f"段落字体大小 {font_size} 可能影响可读性"
@pytest.mark.responsive
def test_form_inputs_mobile(self, contact_page: ContactPage):
"""测试移动端表单输入"""
contact_page.page.set_viewport_size({"width": 375, "height": 667})
contact_page.navigate()
# 检查表单输入框
inputs = contact_page._find_all("input, textarea")
for inp in inputs:
if inp.count() > 0:
box = inp.first.bounding_box()
if box:
# 输入框高度应该至少40px
assert box["height"] >= 32, \
f"输入框高度 {box['height']}px 可能太小不便触摸"
@pytest.mark.responsive
def test_landscape_orientation(self, home_page: HomePage):
"""测试横屏模式"""
home_page.page.set_viewport_size({"width": 667, "height": 375})
home_page.navigate()
# 验证基本元素可见
home_page.assert_element_visible("header", timeout=5000)
home_page.assert_element_visible("main", timeout=5000)
home_page.assert_element_visible("footer", timeout=5000)
@pytest.mark.responsive
def test_high_dpi_display(self, home_page: HomePage):
"""测试高DPI显示器"""
# 设置视口大小(Playwright会自动处理高DPI显示)
home_page.page.set_viewport_size({"width": 1920, "height": 1080})
home_page.navigate()
# 验证页面正常显示
home_page.assert_element_visible("header", timeout=5000)
home_page.logger.info("✅ 高DPI显示器测试通过")
@pytest.mark.responsive
def test_print_styles(self, home_page: HomePage):
"""测试打印样式"""
home_page.navigate()
# 模拟打印样式
is_print_media = home_page.execute_js("""
() => window.matchMedia('print').matches
""")
# 设置为打印模式
home_page.execute_js("""
() => {
const style = document.createElement('style');
style.innerHTML = '@media print { body { font-size: 12pt; } }';
document.head.appendChild(style);
}
""")
home_page.logger.info("✅ 打印样式应用完成")