""" Pytest fixtures for UI testing 注意: 此测试套件假设服务已通过 Docker Compose 启动 运行前请确保: docker compose up -d """ import os import time from pathlib import Path import pytest from playwright.sync_api import Browser, Page # 测试服务器配置 - Docker映射端口8888到容器内8080 TEST_SERVER_HOST = os.getenv("TEST_SERVER_HOST", "localhost") TEST_SERVER_PORT = int(os.getenv("TEST_SERVER_PORT", "8888")) BASE_URL = f"http://{TEST_SERVER_HOST}:{TEST_SERVER_PORT}" @pytest.fixture(scope="session") def test_server(): """ 验证测试服务器是否运行 此fixture不启动服务器,而是检查Docker Compose服务是否已启动。 请在运行测试前手动启动: docker compose up -d """ # 检查服务器是否已经在运行 max_retries = 10 for i in range(max_retries): try: import requests response = requests.get(BASE_URL, timeout=3) if response.status_code < 500: print(f"✓ 服务器已在运行: {BASE_URL}") yield BASE_URL return except Exception as e: if i == max_retries - 1: raise RuntimeError( f"无法连接到测试服务器: {BASE_URL}\n" f"请确保已启动 Docker Compose 服务: docker compose up -d\n" f"错误: {e}" ) time.sleep(2) yield BASE_URL @pytest.fixture def browser_context_args(browser_context_args): """配置浏览器上下文""" return { **browser_context_args, "viewport": {"width": 1920, "height": 1080}, "locale": "zh-CN", } @pytest.fixture def page(page: Page, test_server): """ 配置页面并导航到首页 自动导航到测试服务器的首页,并等待页面加载完成。 """ page.goto(test_server) page.wait_for_load_state("networkidle") # 设置默认超时 page.set_default_timeout(10000) # 10 秒 yield page # 测试失败时截图 if page.context.browser.is_connected(): try: screenshots_dir = Path(__file__).parent / "screenshots" screenshots_dir.mkdir(exist_ok=True) test_name = os.environ.get("PYTEST_CURRENT_TEST", "unknown").split(":")[-1].split(" ")[0] screenshot_path = screenshots_dir / f"{test_name}.png" page.screenshot(path=str(screenshot_path)) print(f"截图保存至: {screenshot_path}") except Exception as e: print(f"截图失败: {e}") @pytest.fixture def clean_rules(page: Page): """ 清除所有规则的 fixture 在测试前清除所有现有的正则规则,确保测试从干净状态开始。 """ # 清除所有规则 while page.locator(".rule-row").count() > 0: try: remove_btn = page.locator(".rule-row button[title='删除此规则']").first remove_btn.click() page.wait_for_timeout(50) except: break # 如果没有更多规则可删除 yield # 测试后不清理,让下一个测试自己清理 # 这样可以在浏览器中查看测试结果 @pytest.fixture def sample_rules(): """提供示例规则数据""" return [ {"pattern": r"/old/path/", "replacement": r"/new/path/"}, {"pattern": r"C:\\Music", "replacement": r"D:\\Audio"}, {"pattern": r"\\\\nas\\share", "replacement": r"Z:"}, ] @pytest.fixture def nas_conversion_rules(): """提供 NAS 路径转换规则""" return [ {"pattern": r"\\\\koha9-nas\\koha9-nas\\Music", "replacement": r"N:\\Music"}, {"pattern": r"/music/cache/", "replacement": r"/data/music/"}, {"pattern": r"\\", "replacement": r"/"}, ]