Files
AppAutoTest/core/base_page.py
CNWei 4de84039cb refactor: 优化代码
- 优化 部分核心功能实现。
- 新增 详细的文档字符串(Docstrings)和注释。
- 移除 代码中的冗余注释和无效代码。
2026-02-02 17:48:30 +08:00

149 lines
5.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# coding=utf-8
"""
@author: CNWei,ChenWei
@Software: PyCharm
@contact: t6g888@163.com
@file: base_page
@date: 2026/1/26 17:33
@desc:
"""
import logging
from pathlib import Path
from typing import Type, TypeVar, Optional
import allure
from appium import webdriver
from core.driver import CoreDriver
# 定义一个泛型,用于类型推断
T = TypeVar('T', bound='BasePage')
logger = logging.getLogger(__name__)
class BasePage(CoreDriver):
# --- 全局通用的属性 ---
def __init__(self, driver: webdriver.Remote):
"""
初始化 BasePage。
:param driver: Appium WebDriver 实例
"""
super().__init__(driver)
# --- 所有页面通用的元动作 ---
def go_to(self, page_cls: Type[T]) -> T:
"""
通用的页面跳转/实例化方法 (Page Factory)。
:param page_cls: 目标页面类 (BasePage 的子类)
:return: 目标页面的实例
"""
logger.info(f"跳转到页面: {page_cls.__name__}")
return page_cls(self.driver)
def handle_permission_popups(self):
"""
处理通用的系统权限弹窗。
遍历预定义的黑名单,尝试关闭出现的系统级弹窗(如权限申请、安装确认等)。
"""
# 普适性黑名单
popup_blacklist = [
("id", "com.android.packageinstaller:id/permission_allow_button"),
("xpath", "//*[@text='始终允许']"),
("xpath", "//*[@text='稍后提醒']"),
("xpath", "//*[@text='以后再说']"),
("id", "com.app:id/iv_close_global_ad"),
("accessibility id", "Close"), # iOS 常用
]
self.clear_popups(popup_blacklist)
def handle_business_ads(self):
"""
处理全 App 通用的业务广告弹窗。
针对应用启动后可能出现的全局广告进行关闭处理。
"""
ads_blacklist = [("id", "com.app:id/global_ad_close")]
return self.clear_popups(ads_blacklist)
def save_and_attach_screenshot(self, label: str = "日志截图") -> None:
"""
保存截图到本地并附加到 Allure 报告。
:param label: 截图在报告中显示的名称
"""
path_str = self.full_screen_screenshot(name=label)
if path_str:
img_path = Path(path_str)
if img_path.exists():
allure.attach.file(
img_path,
name=label,
attachment_type=allure.attachment_type.PNG
)
def attach_screenshot_bytes(self, label: str = "日志截图") -> None:
"""
直接获取内存中的截图数据并附加到 Allure 报告(不存本地文件)。
:param label: 截图在报告中显示的名称
"""
screenshot_bytes: bytes = self.driver.get_screenshot_as_png()
allure.attach(
screenshot_bytes,
name=label,
attachment_type=allure.attachment_type.PNG
)
# --- 常用断言逻辑 ---
def assert_text(self, by: str, value: str, expected_text: str, timeout: Optional[float] = None) -> 'BasePage':
"""
断言元素的文本内容是否符合预期。
:param by: 定位策略。
:param value: 定位值。
:param expected_text: 期望的文本。
:param timeout: 等待元素可见的超时时间。
:return: self支持链式调用。
:raises AssertionError: 如果文本不匹配。
"""
# 1. 增强报告展示:将断言动作包装为一个清晰的步骤
step_name = f"断言校验 | 预期结果: '{expected_text}'"
with allure.step(step_name):
actual = self.get_text(by, value, timeout)
# 2. 动态附件:在报告中直观对比,方便后期排查
allure.attach(
f"预期值: {expected_text}\n实际值: {actual}",
name="文本对比结果",
attachment_type=allure.attachment_type.TEXT
)
# 3. 执行核心断言
# 如果断言失败,抛出的 AssertionError 会被 conftest.py 中的 Hook 捕获并截图
assert actual == expected_text, f"断言失败: 期望 {expected_text}, 实际 {actual}"
logger.info(f"断言通过: 文本匹配 '{actual}'")
return self
def assert_visible(self, by: str, value: str, msg: str = "元素可见性校验") -> 'BasePage':
"""
断言元素是否可见。
:param by: 定位策略
:param value: 定位值
:param msg: 断言描述信息
:return: self支持链式调用
"""
with allure.step(f"断言检查: {msg}"):
element = self.find_element(by, value)
is_displayed = element.is_displayed()
if is_displayed:
logger.info(f"断言通过: 元素 [{value}] 可见")
assert is_displayed, f"断言失败: 元素 [{value}] 不可见"
return self