Files
Yb-QaAutomationHub/tests/web/conftest.py
T
xst aade9e39d0 feat: 基于 UI 自动化最佳实践的测试框架骨架搭建
- tests/config: 环境配置 (.yaml) + 配置加载器
- tests/utils: 日志工具 + 测试数据生成器
- tests/web: Playwright conftest + Page Object 基类 + 登录页 + 导航栏组件 + 登录用例(6条)
- tests/app: Appium conftest + Page Object 基类 + 司机端首页 + 登录用例(3条)
- pytest.ini: markers(p0/p1/p2/smoke/web/app) + 运行配置
- 所有用例按最佳实践采用 Page Object 模式 + data-testid 优先定位 + 失败自动截图
2026-07-15 10:24:22 +08:00

110 lines
3.6 KiB
Python

"""
Web 端根级 fixture:浏览器实例 + 失败自动截图。
提供:
browser_name — 参数化 fixture,每个浏览器执行一轮
page — Playwright Page 对象(每个用例独立)
login — 可复用的登录 helper
Usage:
def test_something(page, browser_name):
page.goto("/admin")
...
def test_admin_flow(page, login):
login("super_admin") # 以管理员身份登录
...
"""
from datetime import datetime
from pathlib import Path
import pytest
from playwright.sync_api import sync_playwright
# 截图根目录
SCREENSHOTS_DIR = Path("output/screenshots")
@pytest.fixture(scope="session")
def web_config(config):
"""session 级:Web 配置段。"""
return config["web"]
@pytest.fixture(params=["chromium", "firefox"])
def browser_name(request):
"""每个浏览器执行一次同一套用例。"""
return request.param
@pytest.fixture
def page(web_config, browser_name, request):
"""每个用例独立的 Playwright Page,失败自动截图。"""
viewport = web_config.get("viewport", {"width": 1920, "height": 1080})
timeout = web_config.get("timeout_seconds", 120) * 1000
screenshot_on_failure = web_config.get("screenshot_on_failure", True)
with sync_playwright() as p:
browser_launcher = getattr(p, browser_name)
browser = browser_launcher.launch(headless=True)
context = browser.new_context(
viewport={"width": viewport["width"], "height": viewport["height"]},
locale="zh-CN",
)
page = context.new_page()
page.set_default_timeout(timeout)
yield page
# ── 失败自动截图 ──
if screenshot_on_failure and hasattr(request.node, "rep_call") and request.node.rep_call.failed:
scenario_dir = SCREENSHOTS_DIR / request.node.name
scenario_dir.mkdir(parents=True, exist_ok=True)
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
path = str(scenario_dir / f"FAIL_{browser_name}_{ts}.png")
page.screenshot(path=path, full_page=True)
context.close()
browser.close()
@pytest.fixture
def login(page, web_config, config):
"""返回一个登录 helper 函数,按角色名自动填入账号并等待登录完成。
Usage:
def test_admin(page, login):
login("super_admin")
page.getByTestId("nav-dashboard").click()
"""
def _login(role: str = "super_admin") -> None:
account = config["accounts"].get(role)
if not account:
raise ValueError(f"未知角色 '{role}',可用: {list(config['accounts'].keys())}")
base_url = web_config["base_url"]
# 如果已经打开某个页面且未过期,直接返回
if page.url and not page.url.startswith("about:") and "/login" not in page.url:
return
page.goto(f"{base_url}/login")
page.getByPlaceholder("请输入用户名").fill(account["phone"])
page.getByPlaceholder("请输入密码").fill(account["password"])
page.getByRole("button", name="登录").click()
# 等待登录成功跳转(10 秒超时)
page.wait_for_url(f"{base_url}/**", timeout=10_000)
return _login
# ── pytest 报告 hook:记录每个用例的失败状态 ──
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
"""在每个用例执行后记录结果,供 fixture 中的失败截图逻辑使用。"""
outcome = yield
rep = outcome.get_result()
setattr(item, f"rep_{rep.when}", rep)