Files
PlexPlaylistSync/tests/UI_TESTING_GUIDE.md
T

7.6 KiB

UI 集成测试指南

📋 概述

UI 集成测试使用 Playwright 框架来测试正则路径替换功能的用户界面交互。

🚀 快速开始

1. 安装依赖

# 安装 Playwright 和浏览器驱动
pip install pytest-playwright
playwright install chromium

# 或安装所有浏览器
playwright install

2. 启动应用服务器

在运行 UI 测试前,需要先启动应用:

# 方式 1: 直接运行
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

# 方式 2: 使用 Docker
docker compose up

3. 运行 UI 测试

# 无头模式(不显示浏览器)
pytest tests/test_ui_regex_rules.py -v

# 有头模式(显示浏览器,便于调试)
pytest tests/test_ui_regex_rules.py -v --headed

# 慢速模式(方便观察)
pytest tests/test_ui_regex_rules.py -v --headed --slowmo=500

# 运行特定测试
pytest tests/test_ui_regex_rules.py::TestRegexRulesUI::test_add_single_rule -v --headed

📊 测试覆盖

基础 UI 交互测试 (TestRegexRulesUI)

测试 描述
test_page_loads_successfully 页面成功加载
test_add_single_rule 添加单个规则
test_add_multiple_rules 添加多个规则
test_remove_rule 删除规则
test_save_rules 保存规则
test_rules_persist_after_save 规则持久化验证
test_empty_pattern_validation 空模式验证
test_rule_order_preserved 规则顺序保持

复杂场景测试 (TestComplexScenarios)

测试 描述
test_windows_to_linux_path_conversion Windows → Linux 路径转换
test_nas_path_normalization NAS 路径规范化

性能测试 (TestPerformance)

测试 描述
test_add_many_rules_performance 添加大量规则性能

🎯 测试场景示例

场景 1: 添加单个规则

# 1. 点击"添加规则"按钮
# 2. 填写正则表达式: /old/path/
# 3. 填写替换文本: /new/path/
# 4. 验证输入框内容正确

场景 2: NAS 路径规范化

# 添加三条规则:
# 1. \\koha9-nas\koha9-nas\Music → N:\Music
# 2. /music/cache/ → /data/music/
# 3. \ → /
# 
# 保存并验证规则持久化

场景 3: 规则持久化验证

# 1. 添加规则
# 2. 保存
# 3. 刷新页面
# 4. 验证规则仍然存在

🔧 配置选项

pytest.ini 配置

[pytest]
# Playwright 配置
addopts = 
    --browser=chromium
    --headed
    --slowmo=100

环境变量

# 设置测试服务器地址
export TEST_SERVER_URL="http://localhost:8000"

# 设置浏览器类型
export BROWSER=chromium  # 或 firefox, webkit

🐛 调试技巧

1. 使用有头模式

pytest tests/test_ui_regex_rules.py --headed

2. 使用慢速模式

pytest tests/test_ui_regex_rules.py --headed --slowmo=1000

3. 截图调试

在测试中添加截图:

def test_something(page: Page):
    page.screenshot(path="debug_screenshot.png")

4. 使用 Playwright Inspector

# 启动调试模式
PWDEBUG=1 pytest tests/test_ui_regex_rules.py::test_add_single_rule

5. 查看追踪

# 在 conftest.py 中添加
@pytest.fixture
def context(browser):
    context = browser.new_context()
    context.tracing.start(screenshots=True, snapshots=True)
    yield context
    context.tracing.stop(path="trace.zip")

然后查看:

playwright show-trace trace.zip

📝 编写新的 UI 测试

基本模板

def test_my_feature(page: Page):
    """测试我的功能"""
    # 1. 导航到页面
    page.goto("http://localhost:8000")
    
    # 2. 与元素交互
    button = page.locator("#myButton")
    button.click()
    
    # 3. 验证结果
    expect(page.locator("#result")).to_have_text("Success")

等待策略

# 等待元素可见
page.wait_for_selector("#element", state="visible")

# 等待网络空闲
page.wait_for_load_state("networkidle")

# 等待特定时间(尽量避免)
page.wait_for_timeout(1000)  # 1 秒

选择器策略

# 推荐: 使用 data-testid
page.locator("[data-testid='add-rule-btn']")

# 通过文本
page.locator("button:has-text('保存规则')")

# 通过 ID
page.locator("#addRuleBtn")

# 通过 CSS 类
page.locator(".rule-row")

# 组合选择器
page.locator(".rule-row input[name='pattern']")

🎨 最佳实践

1. 使用 Page Object 模式

class RulesPage:
    def __init__(self, page: Page):
        self.page = page
        self.add_button = page.locator("#addRuleBtn")
        self.save_button = page.locator("button:has-text('保存规则')")
    
    def add_rule(self, pattern: str, replacement: str):
        self.add_button.click()
        self.page.wait_for_timeout(100)
        
        patterns = self.page.locator("input[name='pattern']")
        replacements = self.page.locator("input[name='replacement']")
        
        patterns.last.fill(pattern)
        replacements.last.fill(replacement)
    
    def save(self):
        self.save_button.click()
        self.page.wait_for_load_state("networkidle")

# 使用
def test_with_page_object(page: Page):
    rules_page = RulesPage(page)
    rules_page.add_rule(r"/old/", r"/new/")
    rules_page.save()

2. 使用 Fixtures 清理状态

@pytest.fixture
def clean_rules(page: Page):
    """清除所有规则"""
    page.goto("http://localhost:8000")
    while page.locator(".rule-row").count() > 0:
        page.locator(".rule-row button[title='删除此规则']").first.click()
        page.wait_for_timeout(50)
    yield

3. 避免硬编码等待时间

# ❌ 不好
page.wait_for_timeout(2000)

# ✅ 好
page.wait_for_selector("#element", state="visible")
page.wait_for_load_state("networkidle")

4. 使用断言而非 if 判断

# ❌ 不好
assert page.locator("#element").count() > 0

# ✅ 好
expect(page.locator("#element")).to_be_visible()

🔄 CI/CD 集成

GitHub Actions 示例

name: UI Tests

on: [push, pull_request]

jobs:
  ui-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      
      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.10'
      
      - name: Install dependencies
        run: |
          pip install -r requirements.txt
          pip install pytest-playwright
          playwright install --with-deps chromium
      
      - name: Start application
        run: |
          uvicorn app.main:app --host 0.0.0.0 --port 8000 &
          sleep 5
      
      - name: Run UI tests
        run: pytest tests/test_ui_regex_rules.py -v
      
      - name: Upload screenshots on failure
        if: failure()
        uses: actions/upload-artifact@v2
        with:
          name: screenshots
          path: screenshots/

📚 参考资料

🆘 常见问题

Q: 测试运行时找不到浏览器?

A: 运行 playwright install chromium

Q: 测试失败,如何调试?

A: 使用 --headed --slowmo=500 参数可视化执行过程

Q: 如何在测试中等待异步操作?

A: 使用 page.wait_for_load_state("networkidle")page.wait_for_selector()

Q: 如何处理动态加载的内容?

A: 使用 expect().to_be_visible() 会自动等待元素出现

Q: 测试很慢怎么办?

A: 减少不必要的 wait_for_timeout(),使用事件驱动的等待方法