Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
重构所有代码和文档中的项目名称,将OpenFang统一更新为ZCLAW。包括: - 配置文件中的项目名称 - 代码注释和文档引用 - 环境变量和路径 - 类型定义和接口名称 - 测试用例和模拟数据 同时优化部分代码结构,移除未使用的模块,并更新相关依赖项。
244 lines
8.0 KiB
TypeScript
244 lines
8.0 KiB
TypeScript
/**
|
|
* ZCLAW API 端点兼容性测试
|
|
*
|
|
* 验证 ZCLAW 前端与 ZCLAW 后端的 REST API 兼容性。
|
|
*/
|
|
|
|
import { test, expect, Page } from '@playwright/test';
|
|
import { zclawResponses } from '../fixtures/zclaw-responses';
|
|
|
|
const BASE_URL = 'http://localhost:1420';
|
|
|
|
async function setupMockAPI(page: Page) {
|
|
await page.route('**/api/health', async route => {
|
|
await route.fulfill({ json: zclawResponses.health });
|
|
});
|
|
|
|
await page.route('**/api/status', async route => {
|
|
await route.fulfill({ json: zclawResponses.status });
|
|
});
|
|
|
|
await page.route('**/api/agents', async route => {
|
|
if (route.request().method() === 'GET') {
|
|
await route.fulfill({ json: zclawResponses.agents });
|
|
} else if (route.request().method() === 'POST') {
|
|
await route.fulfill({ json: { clone: { id: 'new-agent-001', name: 'New Agent' } } });
|
|
}
|
|
});
|
|
|
|
await page.route('**/api/agents/*', async route => {
|
|
await route.fulfill({ json: zclawResponses.agent });
|
|
});
|
|
|
|
await page.route('**/api/models', async route => {
|
|
await route.fulfill({ json: zclawResponses.models });
|
|
});
|
|
|
|
await page.route('**/api/hands', async route => {
|
|
await route.fulfill({ json: zclawResponses.hands });
|
|
});
|
|
|
|
await page.route('**/api/hands/*', async route => {
|
|
if (route.request().method() === 'GET') {
|
|
await route.fulfill({ json: zclawResponses.hand });
|
|
} else if (route.request().url().includes('/activate')) {
|
|
await route.fulfill({ json: zclawResponses.handActivation });
|
|
}
|
|
});
|
|
|
|
await page.route('**/api/workflows', async route => {
|
|
await route.fulfill({ json: zclawResponses.workflows });
|
|
});
|
|
|
|
await page.route('**/api/workflows/*', async route => {
|
|
await route.fulfill({ json: zclawResponses.workflow });
|
|
});
|
|
|
|
await page.route('**/api/sessions', async route => {
|
|
await route.fulfill({ json: zclawResponses.sessions });
|
|
});
|
|
|
|
await page.route('**/api/config', async route => {
|
|
await route.fulfill({ json: zclawResponses.config });
|
|
});
|
|
|
|
await page.route('**/api/channels', async route => {
|
|
await route.fulfill({ json: zclawResponses.channels });
|
|
});
|
|
|
|
await page.route('**/api/skills', async route => {
|
|
await route.fulfill({ json: zclawResponses.skills });
|
|
});
|
|
}
|
|
|
|
test.describe('ZCLAW API 端点兼容性测试', () => {
|
|
|
|
test.describe('API-01: Health 端点', () => {
|
|
test('应返回正确的健康状态', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/health');
|
|
return res.json();
|
|
});
|
|
expect(response.status).toBe('ok');
|
|
expect(response.version).toBeDefined();
|
|
});
|
|
});
|
|
|
|
test.describe('API-02: Agents 端点', () => {
|
|
test('应返回 Agent 列表', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/agents');
|
|
return res.json();
|
|
});
|
|
expect(Array.isArray(response)).toBe(true);
|
|
expect(response[0]).toHaveProperty('id');
|
|
expect(response[0]).toHaveProperty('name');
|
|
expect(response[0]).toHaveProperty('state');
|
|
});
|
|
});
|
|
|
|
test.describe('API-03: Create Agent 端点', () => {
|
|
test('应创建新 Agent', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/agents', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ name: 'Test Agent', model: 'qwen3.5-plus' }),
|
|
});
|
|
return res.json();
|
|
});
|
|
expect(response.clone).toHaveProperty('id');
|
|
expect(response.clone).toHaveProperty('name');
|
|
});
|
|
});
|
|
|
|
test.describe('API-04: Hands 端点', () => {
|
|
test('应返回 Hands 列表', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/hands');
|
|
return res.json();
|
|
});
|
|
expect(response).toHaveProperty('hands');
|
|
expect(Array.isArray(response.hands)).toBe(true);
|
|
});
|
|
});
|
|
|
|
test.describe('API-05: Hand Activation 端点', () => {
|
|
test('应激活 Hand 并返回 instance_id', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/hands/Browser/activate', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({}),
|
|
});
|
|
return res.json();
|
|
});
|
|
expect(response).toHaveProperty('instance_id');
|
|
expect(response).toHaveProperty('status');
|
|
});
|
|
});
|
|
|
|
test.describe('API-06: Workflows 端点', () => {
|
|
test('应返回工作流列表', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/workflows');
|
|
return res.json();
|
|
});
|
|
expect(response).toHaveProperty('workflows');
|
|
expect(Array.isArray(response.workflows)).toBe(true);
|
|
});
|
|
});
|
|
|
|
test.describe('API-07: Sessions 端点', () => {
|
|
test('应返回会话列表', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/sessions');
|
|
return res.json();
|
|
});
|
|
expect(response).toHaveProperty('sessions');
|
|
expect(Array.isArray(response.sessions)).toBe(true);
|
|
});
|
|
});
|
|
|
|
test.describe('API-08: Models 端点', () => {
|
|
test('应返回模型列表', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/models');
|
|
return res.json();
|
|
});
|
|
expect(Array.isArray(response)).toBe(true);
|
|
expect(response[0]).toHaveProperty('id');
|
|
expect(response[0]).toHaveProperty('name');
|
|
expect(response[0]).toHaveProperty('provider');
|
|
});
|
|
});
|
|
|
|
test.describe('API-09: Config 端点', () => {
|
|
test('应返回配置信息', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/config');
|
|
return res.json();
|
|
});
|
|
expect(response).toHaveProperty('data_dir');
|
|
expect(response).toHaveProperty('default_model');
|
|
});
|
|
});
|
|
|
|
test.describe('API-10: Channels 端点', () => {
|
|
test('应返回通道列表', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/channels');
|
|
return res.json();
|
|
});
|
|
expect(response).toHaveProperty('channels');
|
|
expect(Array.isArray(response.channels)).toBe(true);
|
|
});
|
|
});
|
|
|
|
test.describe('API-11: Skills 端点', () => {
|
|
test('应返回技能列表', async ({ page }) => {
|
|
await setupMockAPI(page);
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/skills');
|
|
return res.json();
|
|
});
|
|
expect(response).toHaveProperty('skills');
|
|
expect(Array.isArray(response.skills)).toBe(true);
|
|
});
|
|
});
|
|
|
|
test.describe('API-12: Error Handling', () => {
|
|
test('应正确处理 404 错误', async ({ page }) => {
|
|
await page.route('**/api/nonexistent', async route => {
|
|
await route.fulfill({ status: 404, json: { error: 'Not found' } });
|
|
});
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/nonexistent');
|
|
return { status: res.status, body: await res.json() };
|
|
});
|
|
expect(response.status).toBe(404);
|
|
});
|
|
|
|
test('应正确处理 500 错误', async ({ page }) => {
|
|
await page.route('**/api/error', async route => {
|
|
await route.fulfill({ status: 500, json: { error: 'Internal server error' } });
|
|
});
|
|
const response = await page.evaluate(async () => {
|
|
const res = await fetch('/api/error');
|
|
return { status: res.status, body: await res.json() };
|
|
});
|
|
expect(response.status).toBe(500);
|
|
});
|
|
});
|
|
});
|