docs(guide): rewrite CLAUDE.md with ZCLAW-first perspective
Major changes: - Shift from "OpenFang desktop client" to "independent AI Agent desktop app" - Add decision principle: "Is this useful for ZCLAW? Does it affect ZCLAW?" - Simplify project structure and tech stack sections - Replace OpenClaw vs OpenFang comparison with unified backend approach - Consolidate troubleshooting from scattered sections into organized FAQ - Update Hands system documentation with 8 capabilities and status - Stream
This commit is contained in:
459
desktop/tests/e2e/fixtures/test-data.ts
Normal file
459
desktop/tests/e2e/fixtures/test-data.ts
Normal file
@@ -0,0 +1,459 @@
|
||||
/**
|
||||
* 测试数据工厂
|
||||
* 生成一致的测试数据,确保测试可重复性
|
||||
*/
|
||||
|
||||
/**
|
||||
* 生成唯一 ID
|
||||
*/
|
||||
export function generateId(prefix = 'id'): string {
|
||||
return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成时间戳
|
||||
*/
|
||||
export function generateTimestamp(): string {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试消息工厂
|
||||
*/
|
||||
export const messageFactory = {
|
||||
/**
|
||||
* 创建用户消息
|
||||
*/
|
||||
createUser(content: string, options?: { id?: string; timestamp?: string }) {
|
||||
return {
|
||||
id: options?.id ?? generateId('msg'),
|
||||
role: 'user' as const,
|
||||
content,
|
||||
timestamp: options?.timestamp ?? generateTimestamp(),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建助手消息
|
||||
*/
|
||||
createAssistant(content: string, options?: {
|
||||
id?: string;
|
||||
timestamp?: string;
|
||||
streaming?: boolean;
|
||||
model?: string;
|
||||
}) {
|
||||
return {
|
||||
id: options?.id ?? generateId('msg'),
|
||||
role: 'assistant' as const,
|
||||
content,
|
||||
timestamp: options?.timestamp ?? generateTimestamp(),
|
||||
streaming: options?.streaming ?? false,
|
||||
model: options?.model ?? 'claude-3-sonnet',
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建工具消息
|
||||
*/
|
||||
createTool(toolName: string, input: unknown, output: unknown) {
|
||||
return {
|
||||
id: generateId('msg'),
|
||||
role: 'tool' as const,
|
||||
content: '',
|
||||
timestamp: generateTimestamp(),
|
||||
toolName,
|
||||
toolInput: JSON.stringify(input),
|
||||
toolOutput: JSON.stringify(output),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建 Hand 消息
|
||||
*/
|
||||
createHand(handName: string, status: string, result?: unknown) {
|
||||
return {
|
||||
id: generateId('msg'),
|
||||
role: 'hand' as const,
|
||||
content: '',
|
||||
timestamp: generateTimestamp(),
|
||||
handName,
|
||||
handStatus: status,
|
||||
handResult: result,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建 Workflow 消息
|
||||
*/
|
||||
createWorkflow(workflowId: string, step: string, status: string) {
|
||||
return {
|
||||
id: generateId('msg'),
|
||||
role: 'workflow' as const,
|
||||
content: '',
|
||||
timestamp: generateTimestamp(),
|
||||
workflowId,
|
||||
workflowStep: step,
|
||||
workflowStatus: status,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建消息列表
|
||||
*/
|
||||
createConversation(messages: Array<{ role: string; content: string }>) {
|
||||
return messages.map((m) => {
|
||||
if (m.role === 'user') {
|
||||
return this.createUser(m.content);
|
||||
}
|
||||
return this.createAssistant(m.content);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 测试分身工厂
|
||||
*/
|
||||
export const cloneFactory = {
|
||||
/**
|
||||
* 创建分身
|
||||
*/
|
||||
create(options?: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
role?: string;
|
||||
model?: string;
|
||||
workspaceDir?: string;
|
||||
}) {
|
||||
return {
|
||||
id: options?.id ?? generateId('clone'),
|
||||
name: options?.name ?? `测试分身-${Date.now()}`,
|
||||
role: options?.role ?? 'AI Assistant',
|
||||
model: options?.model ?? 'claude-3-sonnet',
|
||||
workspaceDir: options?.workspaceDir ?? '/tmp/workspace',
|
||||
createdAt: generateTimestamp(),
|
||||
onboardingCompleted: true,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建多个分身
|
||||
*/
|
||||
createMany(count: number) {
|
||||
return Array.from({ length: count }, (_, i) =>
|
||||
this.create({
|
||||
name: `分身-${i + 1}`,
|
||||
role: i === 0 ? 'Main Assistant' : `Specialist ${i + 1}`,
|
||||
})
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 测试 Hand 工厂
|
||||
*/
|
||||
export const handFactory = {
|
||||
/**
|
||||
* 创建 Hand
|
||||
*/
|
||||
create(options?: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
status?: string;
|
||||
category?: string;
|
||||
requirementsMet?: boolean;
|
||||
}) {
|
||||
return {
|
||||
id: options?.id ?? generateId('hand'),
|
||||
name: options?.name ?? 'TestHand',
|
||||
description: `Test Hand: ${options?.name ?? 'TestHand'}`,
|
||||
status: options?.status ?? 'idle',
|
||||
category: options?.category ?? 'automation',
|
||||
requirements_met: options?.requirementsMet ?? true,
|
||||
tools: ['tool1', 'tool2'],
|
||||
metrics: ['metric1'],
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建 Browser Hand
|
||||
*/
|
||||
createBrowser(status = 'idle') {
|
||||
return this.create({
|
||||
id: 'browser',
|
||||
name: 'Browser',
|
||||
status,
|
||||
category: 'automation',
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建 Collector Hand
|
||||
*/
|
||||
createCollector(status = 'idle') {
|
||||
return this.create({
|
||||
id: 'collector',
|
||||
name: 'Collector',
|
||||
status,
|
||||
category: 'data',
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建需要审批的 Hand
|
||||
*/
|
||||
createNeedsApproval() {
|
||||
return this.create({
|
||||
status: 'needs_approval',
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建多个 Hands
|
||||
*/
|
||||
createMany(count: number) {
|
||||
const categories = ['automation', 'data', 'research', 'analytics'];
|
||||
return Array.from({ length: count }, (_, i) =>
|
||||
this.create({
|
||||
id: `hand-${i + 1}`,
|
||||
name: `Hand${i + 1}`,
|
||||
category: categories[i % categories.length],
|
||||
})
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 测试工作流工厂
|
||||
*/
|
||||
export const workflowFactory = {
|
||||
/**
|
||||
* 创建工作流
|
||||
*/
|
||||
create(options?: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
steps?: number;
|
||||
}) {
|
||||
return {
|
||||
id: options?.id ?? generateId('wf'),
|
||||
name: options?.name ?? `工作流-${Date.now()}`,
|
||||
description: '测试工作流',
|
||||
steps: options?.steps ?? 1,
|
||||
status: 'idle',
|
||||
createdAt: generateTimestamp(),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建工作流步骤
|
||||
*/
|
||||
createStep(options?: {
|
||||
id?: string;
|
||||
handName?: string;
|
||||
params?: Record<string, unknown>;
|
||||
condition?: string;
|
||||
}) {
|
||||
return {
|
||||
id: options?.id ?? generateId('step'),
|
||||
handName: options?.handName ?? 'Browser',
|
||||
params: options?.params ?? {},
|
||||
condition: options?.condition,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建完整工作流(含步骤)
|
||||
*/
|
||||
createWithSteps(stepCount: number) {
|
||||
const steps = Array.from({ length: stepCount }, (_, i) =>
|
||||
this.createStep({
|
||||
handName: ['Browser', 'Collector', 'Researcher'][i % 3],
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
...this.create({ steps: stepCount }),
|
||||
steps,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 测试技能工厂
|
||||
*/
|
||||
export const skillFactory = {
|
||||
/**
|
||||
* 创建技能
|
||||
*/
|
||||
create(options?: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
category?: string;
|
||||
installed?: boolean;
|
||||
}) {
|
||||
return {
|
||||
id: options?.id ?? generateId('skill'),
|
||||
name: options?.name ?? `技能-${Date.now()}`,
|
||||
description: '测试技能描述',
|
||||
category: options?.category ?? 'development',
|
||||
triggers: ['trigger1', 'trigger2'],
|
||||
capabilities: ['capability1'],
|
||||
installed: options?.installed ?? false,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建已安装的技能
|
||||
*/
|
||||
createInstalled(name?: string) {
|
||||
return this.create({
|
||||
name: name ?? '已安装技能',
|
||||
installed: true,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建多个技能
|
||||
*/
|
||||
createMany(count: number) {
|
||||
const categories = ['development', 'security', 'analytics', 'productivity'];
|
||||
return Array.from({ length: count }, (_, i) =>
|
||||
this.create({
|
||||
id: `skill-${i + 1}`,
|
||||
name: `技能 ${i + 1}`,
|
||||
category: categories[i % categories.length],
|
||||
installed: i < 2, // 前两个已安装
|
||||
})
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 测试团队工厂
|
||||
*/
|
||||
export const teamFactory = {
|
||||
/**
|
||||
* 创建团队
|
||||
*/
|
||||
create(options?: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
pattern?: string;
|
||||
}) {
|
||||
return {
|
||||
id: options?.id ?? generateId('team'),
|
||||
name: options?.name ?? `团队-${Date.now()}`,
|
||||
description: '测试团队',
|
||||
members: [],
|
||||
tasks: [],
|
||||
pattern: options?.pattern ?? 'sequential',
|
||||
status: 'active',
|
||||
createdAt: generateTimestamp(),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建团队成员
|
||||
*/
|
||||
createMember(options?: {
|
||||
id?: string;
|
||||
role?: string;
|
||||
}) {
|
||||
return {
|
||||
id: options?.id ?? generateId('member'),
|
||||
agentId: generateId('agent'),
|
||||
role: options?.role ?? 'member',
|
||||
joinedAt: generateTimestamp(),
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 创建团队任务
|
||||
*/
|
||||
createTask(options?: {
|
||||
id?: string;
|
||||
status?: string;
|
||||
}) {
|
||||
return {
|
||||
id: options?.id ?? generateId('task'),
|
||||
title: '测试任务',
|
||||
description: '任务描述',
|
||||
status: options?.status ?? 'pending',
|
||||
assigneeId: null,
|
||||
createdAt: generateTimestamp(),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 测试审批工厂
|
||||
*/
|
||||
export const approvalFactory = {
|
||||
/**
|
||||
* 创建审批请求
|
||||
*/
|
||||
create(options?: {
|
||||
id?: string;
|
||||
handName?: string;
|
||||
status?: string;
|
||||
}) {
|
||||
return {
|
||||
id: options?.id ?? generateId('approval'),
|
||||
handName: options?.handName ?? 'Browser',
|
||||
reason: '需要用户批准执行',
|
||||
params: {},
|
||||
status: options?.status ?? 'pending',
|
||||
createdAt: generateTimestamp(),
|
||||
expiresAt: new Date(Date.now() + 3600000).toISOString(),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 预设测试场景数据
|
||||
*/
|
||||
export const testScenarios = {
|
||||
/**
|
||||
* 完整的聊天场景
|
||||
*/
|
||||
chatConversation: [
|
||||
{ role: 'user', content: '你好' },
|
||||
{ role: 'assistant', content: '你好!我是 AI 助手,有什么可以帮助你的吗?' },
|
||||
{ role: 'user', content: '请写一个简单的函数' },
|
||||
{ role: 'assistant', content: '好的,这是一个简单的函数:\n```python\ndef hello():\n print("Hello, World!")\n```' },
|
||||
],
|
||||
|
||||
/**
|
||||
* Hand 执行场景
|
||||
*/
|
||||
handExecution: {
|
||||
hand: handFactory.createBrowser(),
|
||||
params: { url: 'https://example.com' },
|
||||
expectedStatus: ['idle', 'running', 'completed'],
|
||||
},
|
||||
|
||||
/**
|
||||
* 工作流场景
|
||||
*/
|
||||
workflowExecution: {
|
||||
workflow: workflowFactory.createWithSteps(3),
|
||||
expectedSteps: ['step-1', 'step-2', 'step-3'],
|
||||
},
|
||||
|
||||
/**
|
||||
* 审批场景
|
||||
*/
|
||||
approvalFlow: {
|
||||
approval: approvalFactory.create({ handName: 'Browser' }),
|
||||
actions: ['approve', 'reject'] as const,
|
||||
},
|
||||
|
||||
/**
|
||||
* 团队协作场景
|
||||
*/
|
||||
teamCollaboration: {
|
||||
team: teamFactory.create({ pattern: 'review_loop' }),
|
||||
members: [teamFactory.createMember({ role: 'developer' }), teamFactory.createMember({ role: 'reviewer' })],
|
||||
task: teamFactory.createTask(),
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user