mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
6.4 KiB
6.4 KiB
ProxyCast E2E 测试指南
端到端测试验证完整用户流程
概述
E2E 测试模拟真实用户操作,验证从前端到后端的完整流程。ProxyCast 使用 Tauri 框架,E2E 测试需要覆盖:
- 桌面应用启动和初始化
- 用户界面交互
- API 代理完整流程
- 凭证管理流程
测试框架
Tauri E2E 测试
使用 tauri-driver 进行自动化测试:
# 安装依赖
cargo install tauri-driver
# 运行 E2E 测试
npm run test:e2e
测试配置
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
timeout: 30000,
use: {
baseURL: 'tauri://localhost',
},
});
测试场景
1. 应用启动流程
import { test, expect } from '@playwright/test';
test.describe('应用启动', () => {
test('应用正常启动并显示主界面', async ({ page }) => {
// 等待应用加载
await page.waitForSelector('[data-testid="main-layout"]');
// 验证核心组件存在
await expect(page.locator('[data-testid="sidebar"]')).toBeVisible();
await expect(page.locator('[data-testid="content-area"]')).toBeVisible();
});
test('首次启动显示欢迎引导', async ({ page }) => {
// 清除本地存储模拟首次启动
await page.evaluate(() => localStorage.clear());
await page.reload();
await expect(page.locator('[data-testid="welcome-modal"]')).toBeVisible();
});
});
2. 凭证管理流程
test.describe('凭证管理', () => {
test('添加 Kiro 凭证', async ({ page }) => {
// 打开凭证管理
await page.click('[data-testid="credentials-tab"]');
await page.click('[data-testid="add-credential-btn"]');
// 选择 Provider
await page.click('[data-testid="provider-kiro"]');
// 上传凭证文件
const fileInput = page.locator('input[type="file"]');
await fileInput.setInputFiles('./tests/fixtures/test-credential.json');
// 验证凭证添加成功
await expect(page.locator('[data-testid="credential-item"]')).toBeVisible();
await expect(page.locator('text=test@example.com')).toBeVisible();
});
test('删除凭证', async ({ page }) => {
// 假设已有凭证
await page.click('[data-testid="credentials-tab"]');
// 删除凭证
await page.click('[data-testid="credential-menu"]');
await page.click('[data-testid="delete-credential"]');
await page.click('[data-testid="confirm-delete"]');
// 验证凭证已删除
await expect(page.locator('[data-testid="credential-item"]')).not.toBeVisible();
});
});
3. API 代理流程
test.describe('API 代理', () => {
test('启动代理服务器', async ({ page }) => {
await page.click('[data-testid="server-tab"]');
await page.click('[data-testid="start-server-btn"]');
// 等待服务器启动
await expect(page.locator('text=服务器运行中')).toBeVisible();
await expect(page.locator('[data-testid="server-port"]')).toContainText('8080');
});
test('代理请求成功', async ({ page, request }) => {
// 启动服务器
await page.click('[data-testid="start-server-btn"]');
await page.waitForSelector('text=服务器运行中');
// 发送测试请求
const response = await request.post('http://localhost:8080/v1/chat/completions', {
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer test-key',
},
data: {
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }],
},
});
expect(response.ok()).toBeTruthy();
});
});
4. Agent 对话流程
test.describe('Agent 对话', () => {
test('发送消息并接收响应', async ({ page }) => {
await page.click('[data-testid="agent-tab"]');
// 输入消息
await page.fill('[data-testid="message-input"]', '你好,请介绍一下自己');
await page.click('[data-testid="send-btn"]');
// 等待响应
await expect(page.locator('[data-testid="assistant-message"]')).toBeVisible({
timeout: 30000,
});
});
test('流式响应正确显示', async ({ page }) => {
await page.click('[data-testid="agent-tab"]');
await page.fill('[data-testid="message-input"]', '写一首短诗');
await page.click('[data-testid="send-btn"]');
// 验证流式显示(内容逐渐增加)
const messageEl = page.locator('[data-testid="assistant-message"]');
let prevLength = 0;
for (let i = 0; i < 5; i++) {
await page.waitForTimeout(500);
const text = await messageEl.textContent();
expect(text?.length).toBeGreaterThan(prevLength);
prevLength = text?.length || 0;
}
});
});
测试数据管理
Fixtures
tests/
├── fixtures/
│ ├── test-credential.json # 测试凭证
│ ├── mock-responses/ # Mock API 响应
│ │ ├── chat-completion.json
│ │ └── streaming-response.txt
│ └── test-config.json # 测试配置
└── e2e/
└── *.spec.ts
Mock 服务
// tests/mocks/api-server.ts
import { setupServer } from 'msw/node';
import { rest } from 'msw';
export const mockServer = setupServer(
rest.post('*/v1/chat/completions', (req, res, ctx) => {
return res(
ctx.json({
id: 'test-id',
choices: [{
message: { role: 'assistant', content: 'Mock response' },
}],
})
);
})
);
运行 E2E 测试
# 构建应用
npm run build
# 运行 E2E 测试
npm run test:e2e
# 运行特定测试
npm run test:e2e -- --grep "凭证管理"
# 生成测试报告
npm run test:e2e -- --reporter=html
CI/CD 集成
# .github/workflows/e2e.yml
name: E2E Tests
on: [push, pull_request]
jobs:
e2e:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Install dependencies
run: npm ci
- name: Build app
run: npm run build
- name: Run E2E tests
run: npm run test:e2e