6f5668b7ec
Add tests/cross_end/ directory with dual-driver architecture:
- conftest.py: Playwright admin_page + Appium app_driver fixtures
- Admin Page Objects: FreightSourcePage, WaybillManagementPage, SettlementPage
- App Page Objects: DriverOrderListPage, DriverTransportPage, DriverHomePage (re-export)
- test_freight_full_flow.py: 8-step end-to-end test (publish → accept → load → unload → accounting → review → shipper pay → platform pay)
- Shared context dict for cross-step data passing
- Graceful skip when either Playwright or Appium is unavailable
- All selectors marked with ⚠️ placeholders for discovery against real environments
Add cross_end marker to pytest.ini for selective execution.
116 lines
4.2 KiB
Python
116 lines
4.2 KiB
Python
"""管理端 — 货源管理 — 发布货源 Page Object。
|
|
|
|
Usage:
|
|
freight_page = FreightSourcePage(page)
|
|
freight_page.fill_freight_form(...)
|
|
freight_page.submit()
|
|
order_no = freight_page.get_published_order_no()
|
|
"""
|
|
|
|
from playwright.sync_api import Page
|
|
|
|
from tests.web.admin.pages.base_page import BasePage
|
|
|
|
|
|
class FreightSourcePage(BasePage):
|
|
"""管理端 - 货源管理 - 发布货源。"""
|
|
|
|
def __init__(self, page: Page):
|
|
super().__init__(page)
|
|
# ⚠️ 以下定位器需要根据实际 DOM 调整
|
|
# 通过 Playwright Inspector 或浏览器 DevTools 获取真实选择器
|
|
|
|
# ── 货源表单字段 ──
|
|
self.goods_name_input = page.get_by_placeholder("请输入货物名称") # ⚠️
|
|
self.weight_input = page.get_by_placeholder("请输入重量") # ⚠️
|
|
self.load_address_input = page.get_by_placeholder("请选择装货地") # ⚠️
|
|
self.unload_address_input = page.get_by_placeholder("请选择卸货地") # ⚠️
|
|
self.price_input = page.get_by_placeholder("请输入运费") # ⚠️
|
|
|
|
# ── 操作按钮 ──
|
|
self.submit_btn = page.get_by_role("button", name="发布") # ⚠️
|
|
self.confirm_btn = page.get_by_role("button", name="确认") # ⚠️
|
|
|
|
# ── 结果元素 ──
|
|
self.success_toast = page.locator(".el-message--success") # ⚠️
|
|
self.order_no_text = page.locator(".order-no, .freight-no") # ⚠️ 发布成功后显示订单号的位置
|
|
|
|
def fill_freight_form(
|
|
self,
|
|
goods_name: str,
|
|
weight: float,
|
|
load_addr: str,
|
|
unload_addr: str,
|
|
) -> None:
|
|
"""填写货源发布表单。
|
|
|
|
Args:
|
|
goods_name: 货物名称
|
|
weight: 货物重量 (吨)
|
|
load_addr: 装货地址
|
|
unload_addr: 卸货地址
|
|
"""
|
|
# ⚠️ 具体字段依赖实际表单结构,以下为通用模式
|
|
self.fill_field(self.goods_name_input, goods_name)
|
|
self.fill_field(self.weight_input, str(weight))
|
|
self.fill_field(self.load_address_input, load_addr)
|
|
self.fill_field(self.unload_address_input, unload_addr)
|
|
# 如有运费字段:
|
|
# self.fill_field(self.price_input, "1000")
|
|
|
|
def submit(self) -> None:
|
|
"""点击发布按钮。"""
|
|
self.click_when_ready(self.submit_btn)
|
|
self.page.wait_for_timeout(1000)
|
|
|
|
def confirm_publish(self) -> None:
|
|
"""确认发布弹窗(如果有二次确认)。"""
|
|
# ⚠️ 如果发布时有确认弹窗
|
|
try:
|
|
self.click_when_ready(self.confirm_btn)
|
|
self.page.wait_for_timeout(500)
|
|
except Exception:
|
|
pass # 无确认弹窗则跳过
|
|
|
|
def get_published_order_no(self) -> str:
|
|
"""发布成功后获取生成的订单号。
|
|
|
|
策略 (按优先级尝试):
|
|
1. 从成功提示文本中提取
|
|
2. 从跳转后的详情页 URL 中提取
|
|
3. 从列表页第一条提取
|
|
|
|
Returns:
|
|
订单号字符串
|
|
|
|
Raises:
|
|
RuntimeError: 无法获取订单号
|
|
"""
|
|
# ⚠️ 策略取决于系统实际行为
|
|
# 策略1: 等待成功 toast
|
|
self.wait_visible(self.success_toast, timeout_ms=10_000)
|
|
toast_text = self.success_toast.inner_text()
|
|
self.page.wait_for_timeout(500)
|
|
|
|
# 策略2: 从当前页面提取订单号文本
|
|
if self.order_no_text.is_visible():
|
|
return self.order_no_text.inner_text().strip()
|
|
|
|
# 策略3: 从 URL 提取
|
|
import re
|
|
match = re.search(r"orderNo=(\w+)", self.page.url)
|
|
if match:
|
|
return match.group(1)
|
|
|
|
# 策略4: 从成功 toast 文本中提取数字编号
|
|
match = re.search(r"[A-Z]{2,6}\d{10,20}", toast_text)
|
|
if match:
|
|
return match.group(0)
|
|
|
|
raise RuntimeError(
|
|
f"无法获取发布的订单号。\n"
|
|
f"当前 URL: {self.page.url}\n"
|
|
f"Toast 文本: {toast_text}\n"
|
|
f"请更新 get_published_order_no() 中的选择器。"
|
|
)
|