Files
张翔 08ea5fbe98 feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
2026-03-28 14:37:29 +08:00

125 lines
3.7 KiB
Python

"""
异常处理器模块
提供测试异常分类处理功能,区分致命错误和可重试错误。
"""
from typing import Optional, List
from playwright.sync_api import Page
class FatalTestError(Exception):
"""致命测试错误"""
pass
class RetryableError(Exception):
"""可重试错误"""
pass
class TestExceptionHandler:
"""测试异常处理器"""
# 致命错误:立即停止测试
FATAL_ERRORS: List[str] = [
"Browser crashed",
"Connection refused",
"Target page closed",
"Database connection failed",
"Session deleted",
"invalid session id",
]
# 可重试错误:自动重试
RETRYABLE_ERRORS: List[str] = [
"TimeoutError",
"Timeout exceeded",
"Element not found",
"Network error",
"net::ERR",
"Stale element reference",
"element is detached",
"Execution context was destroyed",
"Unable to locate element",
"waiting for locator",
]
# 非致命错误:记录但继续
NON_FATAL_ERRORS: List[str] = [
"Screenshot failed",
"Log write failed",
"Screenshot is not supported",
]
@classmethod
def handle_exception(
cls,
error: Exception,
page: Optional[Page] = None,
test_name: str = "",
screenshot_helper=None,
) -> Optional[Exception]:
"""
处理测试异常
Args:
error: 异常对象
page: Playwright页面对象
test_name: 测试名称
screenshot_helper: 截图辅助工具
Returns:
None: 非致命错误,继续执行
RetryableError: 可重试错误
FatalTestError: 致命错误,停止测试
"""
error_msg = str(error)
error_type = type(error).__name__
# 致命错误
if any(fatal in error_msg for fatal in cls.FATAL_ERRORS):
if screenshot_helper and page:
screenshot_helper.take_screenshot(
page, f"{test_name}_fatal_error" if test_name else "fatal_error"
)
raise FatalTestError(f"测试遇到致命错误 [{error_type}]: {error_msg}")
# 可重试错误
if any(retryable in error_msg for retryable in cls.RETRYABLE_ERRORS):
if screenshot_helper and page:
screenshot_helper.take_screenshot(
page,
f"{test_name}_retryable_error" if test_name else "retryable_error",
)
return RetryableError(f"可重试错误 [{error_type}]: {error_msg}")
# 非致命错误
if any(non_fatal in error_msg for non_fatal in cls.NON_FATAL_ERRORS):
# 仅记录错误,不抛出
return None
# 未知错误 - 根据错误类型判断
if "assert" in error_msg.lower():
# 断言错误通常是测试逻辑问题,不重试
raise error
# 其他错误视为可重试
if screenshot_helper and page:
screenshot_helper.take_screenshot(
page, f"{test_name}_unknown_error" if test_name else "unknown_error"
)
return RetryableError(f"未知错误 [{error_type}]: {error_msg}")
@classmethod
def is_fatal_error(cls, error: Exception) -> bool:
"""判断是否为致命错误"""
error_msg = str(error)
return any(fatal in error_msg for fatal in cls.FATAL_ERRORS)
@classmethod
def is_retryable_error(cls, error: Exception) -> bool:
"""判断是否为可重试错误"""
error_msg = str(error)
return any(retryable in error_msg for retryable in cls.RETRYABLE_ERRORS)