Update UI automation test files
This commit is contained in:
194
zhyy/test_case/Resource/UI/contract_manage_page.py
Normal file
194
zhyy/test_case/Resource/UI/contract_manage_page.py
Normal file
@@ -0,0 +1,194 @@
|
||||
import re
|
||||
from playwright.sync_api import expect
|
||||
from zhyy.test_case.Resource.UI.base_page import BasePage
|
||||
|
||||
|
||||
class SmartManagementLoginPage(BasePage):
|
||||
"""
|
||||
智慧运营登录页对象。
|
||||
|
||||
TODO:
|
||||
当前未提供登录页侦察结果,以下 selector 为常见候选。
|
||||
落地时请优先使用真实 DOM 中稳定属性,例如 data-testid、id、name。
|
||||
"""
|
||||
|
||||
USERNAME_INPUT_SELECTORS = [
|
||||
"input[name='username']",
|
||||
"input[name='userName']",
|
||||
"input[id*='username']",
|
||||
"input[placeholder*='用户名']",
|
||||
"input[placeholder*='账号']",
|
||||
]
|
||||
|
||||
PASSWORD_INPUT_SELECTORS = [
|
||||
"input[name='password']",
|
||||
"input[type='password']",
|
||||
"input[placeholder*='密码']",
|
||||
]
|
||||
|
||||
LOGIN_BUTTON_SELECTORS = [
|
||||
"button:has-text('登录')",
|
||||
"button:has-text('登 录')",
|
||||
"[role='button']:has-text('登录')",
|
||||
]
|
||||
|
||||
def login_if_needed(self, username: str, password: str):
|
||||
"""
|
||||
如果当前页面出现登录表单则登录;如果已登录或 SSO 已生效则跳过。
|
||||
"""
|
||||
username_input = self.page.locator(",".join(self.USERNAME_INPUT_SELECTORS)).first
|
||||
try:
|
||||
username_input.wait_for(state="visible", timeout=5000)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
self.fill_first_visible(self.USERNAME_INPUT_SELECTORS, username, description="用户名输入框")
|
||||
self.fill_first_visible(self.PASSWORD_INPUT_SELECTORS, password, description="密码输入框")
|
||||
self.click_first_visible(self.LOGIN_BUTTON_SELECTORS, description="登录按钮")
|
||||
self.wait_network_idle()
|
||||
self.screenshot("after_login.png")
|
||||
|
||||
|
||||
class ContractManagePage(BasePage):
|
||||
"""
|
||||
合同管理页面对象。
|
||||
|
||||
被测页面:
|
||||
https://smart-management-web-st.best-envision.com/SZPurchase/PurchaseManage/PurchaseOrderManage
|
||||
|
||||
TODO:
|
||||
reconnaissanceResult 为空,缺少真实 DOM。
|
||||
以下 selector 采用“清晰候选 + TODO”方式,落地执行前需通过页面侦察结果替换为真实稳定 selector。
|
||||
"""
|
||||
|
||||
CONTRACT_MENU_SELECTORS = [
|
||||
# TODO: 使用真实菜单 DOM 替换,例如 [data-testid='contract-menu']
|
||||
"text=合同管理",
|
||||
"a:has-text('合同管理')",
|
||||
"li:has-text('合同管理')",
|
||||
"[role='menuitem']:has-text('合同管理')",
|
||||
]
|
||||
|
||||
CONTRACT_NO_INPUT_SELECTORS = [
|
||||
# TODO: 使用真实合同编号输入框 selector 替换
|
||||
"input[placeholder*='合同编号']",
|
||||
"input[aria-label*='合同编号']",
|
||||
".ant-form-item:has-text('合同编号') input",
|
||||
".el-form-item:has-text('合同编号') input",
|
||||
"label:has-text('合同编号') + div input",
|
||||
]
|
||||
|
||||
QUERY_BUTTON_SELECTORS = [
|
||||
"button:has-text('查询')",
|
||||
"button:has-text('搜索')",
|
||||
"[role='button']:has-text('查询')",
|
||||
"[role='button']:has-text('搜索')",
|
||||
]
|
||||
|
||||
TABLE_ROW_SELECTORS = [
|
||||
# Ant Design Table
|
||||
".ant-table-tbody > tr:not(.ant-table-placeholder)",
|
||||
# Element Plus / Element UI Table
|
||||
".el-table__body tbody tr",
|
||||
# 原生 table
|
||||
"table tbody tr",
|
||||
]
|
||||
|
||||
EMPTY_SELECTORS = [
|
||||
".ant-empty",
|
||||
".el-empty",
|
||||
"text=暂无数据",
|
||||
"text=无数据",
|
||||
"text=No Data",
|
||||
]
|
||||
|
||||
def open(self, url: str):
|
||||
self.goto(url)
|
||||
self.screenshot("contract_manage_opened.png")
|
||||
|
||||
def open_contract_menu_if_visible(self):
|
||||
"""
|
||||
用户步骤要求“找到合同菜单”。
|
||||
如果当前 URL 已直达合同管理页,则菜单可能无需点击。
|
||||
若菜单可见则点击;不可见不强制失败,避免直达 URL 场景误报。
|
||||
"""
|
||||
for selector in self.CONTRACT_MENU_SELECTORS:
|
||||
locator = self.page.locator(selector).first
|
||||
try:
|
||||
locator.wait_for(state="visible", timeout=2000)
|
||||
locator.click()
|
||||
self.wait_network_idle()
|
||||
self.screenshot("contract_menu_clicked.png")
|
||||
return
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
def search_by_contract_no_keyword(self, keyword: str):
|
||||
self.fill_first_visible(
|
||||
self.CONTRACT_NO_INPUT_SELECTORS,
|
||||
keyword,
|
||||
description="合同编号搜索框",
|
||||
)
|
||||
self.click_first_visible(
|
||||
self.QUERY_BUTTON_SELECTORS,
|
||||
description="查询按钮",
|
||||
)
|
||||
self.wait_network_idle()
|
||||
self.wait_for_timeout(1000)
|
||||
self.screenshot("contract_no_search_result.png")
|
||||
|
||||
def _table_rows_locator(self):
|
||||
for selector in self.TABLE_ROW_SELECTORS:
|
||||
rows = self.page.locator(selector)
|
||||
try:
|
||||
if rows.count() > 0 and rows.first.is_visible(timeout=2000):
|
||||
return rows
|
||||
except Exception:
|
||||
continue
|
||||
return None
|
||||
|
||||
def has_empty_result(self) -> bool:
|
||||
for selector in self.EMPTY_SELECTORS:
|
||||
try:
|
||||
locator = self.page.locator(selector).first
|
||||
if locator.is_visible(timeout=1000):
|
||||
return True
|
||||
except Exception:
|
||||
continue
|
||||
return False
|
||||
|
||||
def get_result_row_texts(self) -> list[str]:
|
||||
rows = self._table_rows_locator()
|
||||
if rows is None:
|
||||
return []
|
||||
|
||||
row_texts = []
|
||||
count = rows.count()
|
||||
for index in range(count):
|
||||
row = rows.nth(index)
|
||||
text = re.sub(r"\s+", " ", row.inner_text()).strip()
|
||||
if text:
|
||||
row_texts.append(text)
|
||||
return row_texts
|
||||
|
||||
def assert_contract_no_fuzzy_match(self, keyword: str):
|
||||
"""
|
||||
断言查询结果与合同编号模糊匹配条件一致。
|
||||
|
||||
说明:
|
||||
由于缺少真实表格列 selector,当前按整行文本包含 keyword 断言。
|
||||
落地后建议替换为“合同编号列单元格”精确读取:
|
||||
- AntD: 根据 th 文本定位列 index,再读取 tbody tr td[index]
|
||||
- Element: 使用列 prop 或 class 定位
|
||||
"""
|
||||
row_texts = self.get_result_row_texts()
|
||||
|
||||
assert row_texts, (
|
||||
f"合同编号关键字【{keyword}】查询后未获取到表格数据。"
|
||||
f"若业务允许无结果,请调整测试数据为存在的合同编号片段。"
|
||||
)
|
||||
|
||||
unmatched_rows = [text for text in row_texts if keyword not in text]
|
||||
assert not unmatched_rows, (
|
||||
f"存在与合同编号关键字【{keyword}】不匹配的查询结果:{unmatched_rows}"
|
||||
)
|
||||
Reference in New Issue
Block a user