Files
novalon-website/e2e-tests/pages/contact_page.py
T
张翔 f14002559e feat(e2e-tests): 添加端到端测试框架及测试用例
refactor(components): 调整头部和页脚布局样式
style(hero-section): 更新徽章动画效果

docs: 添加测试框架README文档
test: 实现首页、导航和联系表单的测试用例
ci: 添加CI测试脚本和配置
2026-02-02 19:36:33 +08:00

389 lines
13 KiB
Python

"""
联系页面测试模块
提供联系页面功能测试
"""
from typing import Any, Dict, List, Optional
from playwright.sync_api import Page, Locator, expect
from pages.base_page import BasePage
from config.settings import get_settings
from utils.logger import get_logger
from utils.helpers import ElementHelper, PageHelper, AssertionHelper
class ContactPage(BasePage):
"""联系页面对象"""
def __init__(self, page: Page, base_url: Optional[str] = None):
"""初始化联系页面"""
super().__init__(page, base_url)
self.path = "/contact"
self.title = "联系我们"
self.selectors = {
# 页面标题
"page_badge": "[class*='badge']",
"page_title": "h1",
"page_description": "p.text-gray-600",
# 联系信息卡片 - 根据实际页面结构
"contact_info_card": "div.grid > div:first-child",
"company_address": "text=公司地址 >> xpath=../following-sibling::p",
"company_phone": "text=联系电话 >> xpath=../following-sibling::p",
"company_email": "text=电子邮箱 >> xpath=../following-sibling::p",
"working_hours": "text=工作时间",
# 联系表单 - 使用ID选择器
"contact_form": "form",
"form_name_input": "#name",
"form_phone_input": "#phone",
"form_email_input": "#email",
"form_subject_input": "#subject",
"form_message_textarea": "#message",
"form_submit_button": "button[type='submit']",
# 表单字段标签
"name_label": "label[for='name']",
"phone_label": "label[for='phone']",
"email_label": "label[for='email']",
"subject_label": "label[for='subject']",
"message_label": "label[for='message']",
# 成功状态
"success_message": "text=消息已发送",
"success_icon": "svg[class*='text-green']",
# 加载状态
"submitting_loader": "text=发送中",
# 返回链接
"back_link": "a:has-text('返回'), a.back"
}
self.logger = get_logger()
def navigate(self, **kwargs) -> 'ContactPage':
"""导航到联系页面"""
super().navigate(**kwargs)
self.wait_for_load()
return self
def verify_page_loaded(self) -> 'ContactPage':
"""验证页面加载完成"""
self.logger.section("验证联系页面加载")
self.assert_element_visible("page_title", timeout=15000)
self.assert_element_visible("contact_form", timeout=15000)
self.logger.info("✅ 联系页面加载验证通过")
return self
def verify_page_structure(self) -> 'ContactPage':
"""验证页面结构"""
self.logger.section("验证页面结构")
# 检查页面标题区域
self.assert_element_visible("page_title")
# 检查联系信息 - 使用更通用的选择器
self._verify_contact_info_exists()
# 检查表单
self.assert_element_visible("contact_form")
self.logger.info("✅ 页面结构验证通过")
return self
def _verify_contact_info_exists(self) -> bool:
"""验证联系信息存在"""
# 检查是否包含联系信息文本
page_text = self.page.content()
has_address = "公司地址" in page_text
has_phone = "联系电话" in page_text
has_email = "电子邮箱" in page_text
assert has_address, "未找到公司地址信息"
assert has_phone, "未找到联系电话信息"
assert has_email, "未找到电子邮箱信息"
return True
def verify_company_info(self) -> 'ContactPage':
"""验证公司信息"""
self.logger.section("验证公司信息")
# 获取页面内容
page_content = self.page.content()
# 验证信息存在
assert "公司地址" in page_content, "未找到公司地址"
assert "联系电话" in page_content, "未找到联系电话"
assert "电子邮箱" in page_content, "未找到电子邮箱"
self.logger.info("✅ 公司信息验证通过")
return self
def verify_form_fields(self) -> 'ContactPage':
"""验证表单字段"""
self.logger.section("验证表单字段")
required_fields = [
("form_name_input", "姓名"),
("form_email_input", "邮箱"),
("form_subject_input", "主题"),
("form_message_textarea", "消息")
]
for selector, field_name in required_fields:
self.assert_element_visible(selector, timeout=5000)
# 检查必填标记
label = self.page.locator(f"label[for='{selector.replace('#', '')}']")
if label.count() > 0:
label_text = label.text_content()
if "*" in (label_text or ""):
self.logger.info(f"{field_name} 为必填项")
# 检查可选字段
self.assert_element_visible("form_phone_input")
self.logger.info("✅ 表单字段验证通过")
return self
def fill_contact_form(self, data: Dict[str, str]) -> 'ContactPage':
"""填充联系表单"""
self.logger.section("填充联系表单")
# 姓名
if "name" in data:
self._fill("form_name_input", data["name"])
self.logger.log_action(f"填写姓名: {data['name']}")
# 电话
if "phone" in data:
self._fill("form_phone_input", data["phone"])
self.logger.log_action(f"填写电话: {data['phone']}")
# 邮箱
if "email" in data:
self._fill("form_email_input", data["email"])
self.logger.log_action(f"填写邮箱: {data['email']}")
# 主题
if "subject" in data:
self._fill("form_subject_input", data["subject"])
self.logger.log_action(f"填写主题: {data['subject']}")
# 消息
if "message" in data:
self._fill("form_message_textarea", data["message"])
self.logger.log_action(f"填写消息: {data['message'][:50]}...")
return self
def submit_form(self, wait_for_response: bool = True) -> 'ContactPage':
"""提交表单"""
self.logger.log_action("提交联系表单")
# 等待表单按钮可用
submit_button = self._find("form_submit_button")
# 点击提交
submit_button.click()
if wait_for_response:
# 等待加载完成
self.page.wait_for_load_state("networkidle")
# 检查是否显示成功消息
try:
self.assert_element_visible("success_message", timeout=10000)
self.logger.info("表单提交成功")
except Exception:
self.logger.warning("未检测到成功消息,可能提交失败或无反馈")
return self
def verify_form_submission_success(self) -> 'ContactPage':
"""验证表单提交成功"""
self.logger.section("验证表单提交成功")
# 检查成功消息
self.assert_element_visible("success_message")
# 验证成功消息文本
success_text = self._get_text("success_message")
assert "已发送" in success_text or "成功" in success_text, \
f"成功消息不正确: {success_text}"
self.logger.info("✅ 表单提交成功验证通过")
return self
def verify_form_validation(self) -> 'ContactPage':
"""验证表单验证"""
self.logger.section("验证表单验证")
# 尝试提交空表单
self._click("form_submit_button")
# 检查浏览器原生验证
name_input = self._find("form_name_input")
is_required = name_input.evaluate("el => el.required")
if is_required:
self.logger.info("姓名字段为必填项")
# 验证邮箱格式
self._fill("form_email_input", "invalid-email")
self._click("form_subject_input")
# 检查HTML5验证
email_input = self._find("form_email_input")
validity = email_input.evaluate("""
el => ({
valid: el.validity.valid,
typeMismatch: el.validity.typeMismatch,
valueMissing: el.validity.valueMissing
})
""")
if not validity["valid"] and validity["typeMismatch"]:
self.logger.info("邮箱格式验证正常工作")
self.logger.info("✅ 表单验证验证通过")
return self
def verify_form_with_invalid_email(self, data: Dict[str, str]) -> 'ContactPage':
"""使用无效邮箱测试表单验证"""
self.logger.section("测试无效邮箱")
# 填写表单(使用无效邮箱)
data["email"] = "invalid-email"
self.fill_contact_form(data)
# 尝试提交
self._click("form_submit_button")
# 检查是否被HTML5验证阻止
email_input = self._find("form_email_input")
is_valid = email_input.evaluate("el => el.validity.valid")
if not is_valid:
self.logger.info("无效邮箱被正确阻止")
else:
self.logger.warning("无效邮箱未被验证阻止,可能存在后端验证")
return self
def test_form_submission_performance(
self,
data: Dict[str, str],
max_duration: float = 5.0
) -> Dict[str, Any]:
"""测试表单提交性能"""
self.logger.section("表单提交性能测试")
import time
# 填充表单
self.fill_contact_form(data)
# 记录开始时间
start_time = time.time()
# 提交表单
self._click("form_submit_button")
# 等待成功消息
try:
self.assert_element_visible("success_message", timeout=10000)
except Exception:
pass
# 记录结束时间
end_time = time.time()
duration = end_time - start_time
# 验证性能
if duration <= max_duration:
self.logger.info(f"✅ 表单提交耗时 {duration:.2f}s,在阈值 {max_duration}s 内")
else:
self.logger.warning(f"⚠️ 表单提交耗时 {duration:.2f}s,超过阈值 {max_duration}s")
return {
"duration": duration,
"passed": duration <= max_duration
}
def get_working_hours(self) -> Dict[str, str]:
"""获取工作时间"""
# 从页面内容中提取工作时间
page_text = self.page.content()
hours = {}
# 检查工作时间文本
if "周一至周五" in page_text:
hours["周一至周五"] = "9:00 - 18:00"
if "周六" in page_text:
hours["周六"] = "9:00 - 12:00"
if "周日" in page_text:
hours["周日"] = "休息"
return hours
def reset_form(self) -> 'ContactPage':
"""重置表单"""
self.logger.log_action("重置表单")
# 刷新页面
self.reload()
self.wait_for_load()
return self
def verify_responsive_layout(self, width: int) -> 'ContactPage':
"""验证响应式布局"""
self.logger.section(f"响应式测试 ({width}px)")
# 设置视口
self.page.set_viewport_size({"width": width, "height": 800})
self.wait_for_load()
# 验证布局
self.assert_element_visible("contact_form", timeout=5000)
# 检查布局变化
if width < 768:
self.logger.info("移动端布局:单列布局")
elif width < 1024:
self.logger.info("平板端布局:双列布局")
else:
self.logger.info("桌面端布局:完整布局")
self.logger.info(f"{width}px 响应式测试通过")
return self
def extract_contact_details(self) -> Dict[str, str]:
"""提取联系详情"""
details = {}
# 从页面内容中提取
page_content = self.page.content()
# 公司地址
if "公司地址" in page_content:
details["address"] = "已找到地址信息"
# 联系电话
if "联系电话" in page_content:
details["phone"] = "已找到电话信息"
# 电子邮箱
if "电子邮箱" in page_content:
details["email"] = "已找到邮箱信息"
return details