08ea5fbe98
添加用户管理视图、API和状态管理文件
125 lines
3.7 KiB
Python
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)
|