mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
fix: resolve Windows compilation errors and warnings
- Add Manager trait import for windows_startup_cmd.rs - Add explicit type annotations for PathBuf in windows_startup_cmd.rs - Fix unused import warning in screenshot_capture_service.rs - Prefix unused variables with underscore in runner.rs and aster_agent_cmd.rs - Update package.json with Node.js engine requirement
This commit is contained in:
@@ -13,12 +13,12 @@ navigation:
|
||||
|
||||
### 前置要求
|
||||
|
||||
| 工具 | 版本 |
|
||||
|------|------|
|
||||
| Node.js | >= 18 |
|
||||
| pnpm | >= 8 |
|
||||
| Rust | >= 1.70 |
|
||||
| Tauri CLI | >= 2.0 |
|
||||
| 工具 | 版本 |
|
||||
| --------- | ------- |
|
||||
| Node.js | >= 22 |
|
||||
| pnpm | >= 8 |
|
||||
| Rust | >= 1.70 |
|
||||
| Tauri CLI | >= 2.0 |
|
||||
|
||||
### 安装依赖
|
||||
|
||||
|
||||
@@ -17,10 +17,12 @@ navigation:
|
||||
|
||||
```bash
|
||||
# 使用 nvm 安装
|
||||
nvm install 18
|
||||
nvm use 18
|
||||
nvm install 22
|
||||
nvm use 22
|
||||
```
|
||||
|
||||
Windows 用户请使用 Node.js 官方安装器安装 22.x,并重新打开终端后通过 `node -v` 确认版本。
|
||||
|
||||
2. **安装 pnpm**
|
||||
|
||||
```bash
|
||||
@@ -40,15 +42,18 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
4. **安装 Tauri 依赖**
|
||||
|
||||
**macOS:**
|
||||
|
||||
```bash
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
|
||||
- 安装 Visual Studio Build Tools
|
||||
- 安装 WebView2(开发模式必需;对外分发时建议使用带离线 WebView2 的 NSIS 安装器)
|
||||
|
||||
**Linux:**
|
||||
|
||||
```bash
|
||||
sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file libssl-dev libayatana-appindicator3-dev librsvg2-dev
|
||||
```
|
||||
@@ -64,6 +69,7 @@ pnpm tauri dev
|
||||
```
|
||||
|
||||
开发模式特性:
|
||||
|
||||
- 前端热重载
|
||||
- Rust 代码变更自动重新编译
|
||||
- 开发者工具可用
|
||||
@@ -111,11 +117,11 @@ pnpm tauri build --debug
|
||||
|
||||
### 构建产物
|
||||
|
||||
| 平台 | 产物位置 |
|
||||
|------|----------|
|
||||
| macOS | `src-tauri/target/release/bundle/dmg/` |
|
||||
| 平台 | 产物位置 |
|
||||
| ------- | --------------------------------------- |
|
||||
| macOS | `src-tauri/target/release/bundle/dmg/` |
|
||||
| Windows | `src-tauri/target/release/bundle/nsis/` |
|
||||
| Linux | `src-tauri/target/release/bundle/deb/` |
|
||||
| Linux | `src-tauri/target/release/bundle/deb/` |
|
||||
|
||||
### 跨平台构建
|
||||
|
||||
@@ -141,7 +147,6 @@ pnpm tauri build --target x86_64-pc-windows-msvc --config src-tauri/tauri.window
|
||||
|
||||
> 建议对外分发 `-setup.exe`,不要把默认 `.msi` 作为首选下载项。
|
||||
|
||||
|
||||
#### Linux 构建
|
||||
|
||||
```bash
|
||||
@@ -195,12 +200,12 @@ git push origin v1.0.1
|
||||
|
||||
### 构建矩阵
|
||||
|
||||
| 平台 | 架构 | Runner |
|
||||
|------|------|--------|
|
||||
| macOS | arm64 | macos-latest |
|
||||
| macOS | x64 | macos-13 |
|
||||
| Windows | x64 | windows-2022 |
|
||||
| Linux | x64 | ubuntu-latest |
|
||||
| 平台 | 架构 | Runner |
|
||||
| ------- | ----- | ------------- |
|
||||
| macOS | arm64 | macos-latest |
|
||||
| macOS | x64 | macos-13 |
|
||||
| Windows | x64 | windows-2022 |
|
||||
| Linux | x64 | ubuntu-latest |
|
||||
|
||||
## 调试
|
||||
|
||||
@@ -217,11 +222,11 @@ RUST_LOG=debug pnpm tauri dev
|
||||
|
||||
### 日志位置
|
||||
|
||||
| 平台 | 路径 |
|
||||
|------|------|
|
||||
| macOS | `~/Library/Logs/ProxyCast/` |
|
||||
| Windows | `%APPDATA%\ProxyCast\logs\` |
|
||||
| Linux | `~/.local/share/proxycast/logs/` |
|
||||
| 平台 | 路径 |
|
||||
| ------- | -------------------------------- |
|
||||
| macOS | `~/Library/Logs/ProxyCast/` |
|
||||
| Windows | `%APPDATA%\ProxyCast\logs\` |
|
||||
| Linux | `~/.local/share/proxycast/logs/` |
|
||||
|
||||
## 常见问题
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
{
|
||||
"name": "proxycast-docs",
|
||||
"engines": {
|
||||
"node": ">=22.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "nuxt dev --extends docus",
|
||||
"build": "nuxt build --extends docus",
|
||||
|
||||
+77
-65
@@ -5,6 +5,7 @@
|
||||
## 概述
|
||||
|
||||
E2E 测试模拟真实用户操作,验证从前端到后端的完整流程。ProxyCast 使用 Tauri 框架,E2E 测试需要覆盖:
|
||||
|
||||
- 桌面应用启动和初始化
|
||||
- 用户界面交互
|
||||
- API 代理完整流程
|
||||
@@ -28,13 +29,13 @@ npm run test:e2e
|
||||
|
||||
```javascript
|
||||
// playwright.config.ts
|
||||
import { defineConfig } from '@playwright/test';
|
||||
import { defineConfig } from "@playwright/test";
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './tests/e2e',
|
||||
testDir: "./tests/e2e",
|
||||
timeout: 30000,
|
||||
use: {
|
||||
baseURL: 'tauri://localhost',
|
||||
baseURL: "tauri://localhost",
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -44,23 +45,23 @@ export default defineConfig({
|
||||
### 1. 应用启动流程
|
||||
|
||||
```typescript
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
test.describe('应用启动', () => {
|
||||
test('应用正常启动并显示主界面', async ({ page }) => {
|
||||
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 }) => {
|
||||
test("首次启动显示欢迎引导", async ({ page }) => {
|
||||
// 清除本地存储模拟首次启动
|
||||
await page.evaluate(() => localStorage.clear());
|
||||
await page.reload();
|
||||
|
||||
|
||||
await expect(page.locator('[data-testid="welcome-modal"]')).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -69,35 +70,37 @@ test.describe('应用启动', () => {
|
||||
### 2. 凭证管理流程
|
||||
|
||||
```typescript
|
||||
test.describe('凭证管理', () => {
|
||||
test('添加 Kiro 凭证', async ({ page }) => {
|
||||
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 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();
|
||||
await expect(page.locator("text=test@example.com")).toBeVisible();
|
||||
});
|
||||
|
||||
test('删除凭证', async ({ page }) => {
|
||||
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();
|
||||
await expect(
|
||||
page.locator('[data-testid="credential-item"]'),
|
||||
).not.toBeVisible();
|
||||
});
|
||||
});
|
||||
```
|
||||
@@ -105,33 +108,38 @@ test.describe('凭证管理', () => {
|
||||
### 3. API 代理流程
|
||||
|
||||
```typescript
|
||||
test.describe('API 代理', () => {
|
||||
test('启动代理服务器', async ({ page }) => {
|
||||
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');
|
||||
await expect(page.locator("text=服务器运行中")).toBeVisible();
|
||||
await expect(page.locator('[data-testid="server-port"]')).toContainText(
|
||||
"8080",
|
||||
);
|
||||
});
|
||||
|
||||
test('代理请求成功', async ({ page, request }) => {
|
||||
test("代理请求成功", async ({ page, request }) => {
|
||||
// 启动服务器
|
||||
await page.click('[data-testid="start-server-btn"]');
|
||||
await page.waitForSelector('text=服务器运行中');
|
||||
|
||||
await page.waitForSelector("text=服务器运行中");
|
||||
|
||||
// 发送测试请求
|
||||
const response = await request.post('http://localhost:8080/v1/chat/completions', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer test-key',
|
||||
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" }],
|
||||
},
|
||||
},
|
||||
data: {
|
||||
model: 'gpt-4',
|
||||
messages: [{ role: 'user', content: 'Hello' }],
|
||||
},
|
||||
});
|
||||
|
||||
);
|
||||
|
||||
expect(response.ok()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -140,28 +148,30 @@ test.describe('API 代理', () => {
|
||||
### 4. Agent 对话流程
|
||||
|
||||
```typescript
|
||||
test.describe('Agent 对话', () => {
|
||||
test('发送消息并接收响应', async ({ page }) => {
|
||||
test.describe("Agent 对话", () => {
|
||||
test("发送消息并接收响应", async ({ page }) => {
|
||||
await page.click('[data-testid="agent-tab"]');
|
||||
|
||||
|
||||
// 输入消息
|
||||
await page.fill('[data-testid="message-input"]', '你好,请介绍一下自己');
|
||||
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,
|
||||
});
|
||||
await expect(page.locator('[data-testid="assistant-message"]')).toBeVisible(
|
||||
{
|
||||
timeout: 30000,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('流式响应正确显示', async ({ page }) => {
|
||||
test("流式响应正确显示", async ({ page }) => {
|
||||
await page.click('[data-testid="agent-tab"]');
|
||||
await page.fill('[data-testid="message-input"]', '写一首短诗');
|
||||
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);
|
||||
@@ -193,20 +203,22 @@ tests/
|
||||
|
||||
```typescript
|
||||
// tests/mocks/api-server.ts
|
||||
import { setupServer } from 'msw/node';
|
||||
import { rest } from 'msw';
|
||||
import { setupServer } from "msw/node";
|
||||
import { rest } from "msw";
|
||||
|
||||
export const mockServer = setupServer(
|
||||
rest.post('*/v1/chat/completions', (req, res, ctx) => {
|
||||
rest.post("*/v1/chat/completions", (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.json({
|
||||
id: 'test-id',
|
||||
choices: [{
|
||||
message: { role: 'assistant', content: 'Mock response' },
|
||||
}],
|
||||
})
|
||||
id: "test-id",
|
||||
choices: [
|
||||
{
|
||||
message: { role: "assistant", content: "Mock response" },
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
})
|
||||
}),
|
||||
);
|
||||
```
|
||||
|
||||
@@ -239,21 +251,21 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
node-version: "22"
|
||||
|
||||
- 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
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user