79 lines
2.6 KiB
Python
79 lines
2.6 KiB
Python
import os
|
||
import allure
|
||
from playwright.sync_api import Page, Locator, expect
|
||
|
||
|
||
class BasePage:
|
||
"""公共页面基类:封装稳定等待、截图、候选定位器选择等通用能力。"""
|
||
|
||
def __init__(self, page: Page, screenshot_dir: str):
|
||
self.page = page
|
||
self.screenshot_dir = screenshot_dir
|
||
os.makedirs(self.screenshot_dir, exist_ok=True)
|
||
|
||
def goto(self, url: str):
|
||
self.page.goto(url, wait_until="domcontentloaded")
|
||
try:
|
||
self.page.wait_for_load_state("networkidle", timeout=5000)
|
||
except Exception:
|
||
pass
|
||
|
||
def screenshot(self, name: str) -> str:
|
||
path = os.path.join(self.screenshot_dir, name)
|
||
self.page.screenshot(path=path, full_page=True)
|
||
allure.attach.file(path, name=name, attachment_type=allure.attachment_type.PNG)
|
||
return path
|
||
|
||
def first_visible_locator(
|
||
self,
|
||
selectors: list[str],
|
||
timeout: int = 5000,
|
||
description: str = "元素",
|
||
) -> Locator:
|
||
"""
|
||
从候选 CSS/XPath/Text selector 中返回第一个可见元素。
|
||
注意:页面侦察结果为空时,候选 selector 需在项目落地时根据真实 DOM 调整。
|
||
"""
|
||
last_error = None
|
||
for selector in selectors:
|
||
try:
|
||
locator = self.page.locator(selector).first
|
||
locator.wait_for(state="visible", timeout=timeout)
|
||
return locator
|
||
except Exception as exc:
|
||
last_error = exc
|
||
|
||
self.screenshot(f"not_found_{description}.png")
|
||
raise AssertionError(f"未找到可见{description},请根据真实页面 DOM 更新 selector。候选:{selectors}") from last_error
|
||
|
||
def click_first_visible(
|
||
self,
|
||
selectors: list[str],
|
||
timeout: int = 5000,
|
||
description: str = "按钮",
|
||
):
|
||
locator = self.first_visible_locator(selectors, timeout=timeout, description=description)
|
||
locator.click()
|
||
|
||
def fill_first_visible(
|
||
self,
|
||
selectors: list[str],
|
||
value: str,
|
||
timeout: int = 5000,
|
||
description: str = "输入框",
|
||
):
|
||
locator = self.first_visible_locator(selectors, timeout=timeout, description=description)
|
||
locator.fill(value)
|
||
|
||
def wait_network_idle(self):
|
||
try:
|
||
self.page.wait_for_load_state("networkidle", timeout=5000)
|
||
except Exception:
|
||
pass
|
||
|
||
def assert_url_contains(self, expected_part: str):
|
||
expect(self.page).to_have_url(lambda url: expected_part in url)
|
||
|
||
def wait_for_timeout(self, ms: int):
|
||
self.page.wait_for_timeout(ms)
|