""" 响应式设计测试模块 测试网站在不同屏幕尺寸下的响应式表现 """ 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("✅ 打印样式应用完成")