feat: complete Phase 1-3 architecture optimization
Phase 1 - Security: - Add AES-GCM encryption for localStorage fallback - Enforce WSS protocol for non-localhost WebSocket connections - Add URL sanitization to prevent XSS in markdown links Phase 2 - Domain Reorganization: - Create Intelligence Domain with Valtio store and caching - Add unified intelligence-client for Rust backend integration - Migrate from legacy agent-memory, heartbeat, reflection modules Phase 3 - Core Optimization: - Add virtual scrolling for ChatArea with react-window - Implement LRU cache with TTL for intelligence operations - Add message virtualization utilities Additional: - Add OpenFang compatibility test suite - Update E2E test fixtures - Add audit logging infrastructure - Update project documentation and plans Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
109
desktop/tests/e2e/openfang-compat/specs/protocol-compat.spec.ts
Normal file
109
desktop/tests/e2e/openfang-compat/specs/protocol-compat.spec.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* OpenFang 协议兼容性测试
|
||||
*
|
||||
* 验证 ZCLAW 前端与 OpenFang 后端的协议兼容性。
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { openFangResponses, streamEvents, gatewayFrames } from '../fixtures/openfang-responses';
|
||||
|
||||
const BASE_URL = 'http://localhost:1420';
|
||||
|
||||
test.describe('OpenFang 协议兼容性测试', () => {
|
||||
|
||||
test.describe('PROTO-01: 流事件类型解析', () => {
|
||||
test('应正确解析 text_delta 事件', () => {
|
||||
const event = streamEvents.textDelta('Hello World');
|
||||
expect(event.type).toBe('text_delta');
|
||||
expect(event.content).toBe('Hello World');
|
||||
});
|
||||
|
||||
test('应正确解析 phase 事件', () => {
|
||||
const doneEvent = streamEvents.phaseDone;
|
||||
expect(doneEvent.type).toBe('phase');
|
||||
expect(doneEvent.phase).toBe('done');
|
||||
});
|
||||
|
||||
test('应正确解析 tool_call 和 tool_result 事件', () => {
|
||||
const toolCall = streamEvents.toolCall('search', { query: 'test' });
|
||||
expect(toolCall.type).toBe('tool_call');
|
||||
expect(toolCall.tool).toBe('search');
|
||||
|
||||
const toolResult = streamEvents.toolResult('search', { results: [] });
|
||||
expect(toolResult.type).toBe('tool_result');
|
||||
});
|
||||
|
||||
test('应正确解析 hand 事件', () => {
|
||||
const handEvent = streamEvents.hand('Browser', 'completed', { pages: 5 });
|
||||
expect(handEvent.type).toBe('hand');
|
||||
expect(handEvent.hand_name).toBe('Browser');
|
||||
expect(handEvent.hand_status).toBe('completed');
|
||||
});
|
||||
|
||||
test('应正确解析 error 事件', () => {
|
||||
const errorEvent = streamEvents.error('TIMEOUT', 'Request timed out');
|
||||
expect(errorEvent.type).toBe('error');
|
||||
expect(errorEvent.code).toBe('TIMEOUT');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('PROTO-02: Gateway 帧格式兼容', () => {
|
||||
test('应正确构造请求帧', () => {
|
||||
const frame = gatewayFrames.request(1, 'chat', { message: 'Hello' });
|
||||
expect(frame.type).toBe('req');
|
||||
expect(frame.id).toBe(1);
|
||||
expect(frame.method).toBe('chat');
|
||||
});
|
||||
|
||||
test('应正确构造响应帧', () => {
|
||||
const frame = gatewayFrames.response(1, { status: 'ok' });
|
||||
expect(frame.type).toBe('res');
|
||||
expect(frame.id).toBe(1);
|
||||
});
|
||||
|
||||
test('应正确构造事件帧', () => {
|
||||
const frame = gatewayFrames.event({ type: 'text_delta', content: 'test' });
|
||||
expect(frame.type).toBe('event');
|
||||
});
|
||||
|
||||
test('应正确构造 pong 帧', () => {
|
||||
const frame = gatewayFrames.pong(1);
|
||||
expect(frame.type).toBe('pong');
|
||||
expect(frame.id).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('PROTO-03: 连接状态管理', () => {
|
||||
const validStates = ['disconnected', 'connecting', 'handshaking', 'connected', 'reconnecting'];
|
||||
|
||||
test('连接状态应为有效值', () => {
|
||||
validStates.forEach(state => {
|
||||
expect(['disconnected', 'connecting', 'handshaking', 'connected', 'reconnecting']).toContain(state);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('PROTO-04: 心跳机制', () => {
|
||||
test('心跳帧格式正确', () => {
|
||||
const pingFrame = { type: 'ping' };
|
||||
expect(pingFrame.type).toBe('ping');
|
||||
});
|
||||
|
||||
test('pong 响应格式正确', () => {
|
||||
const pongFrame = gatewayFrames.pong(1);
|
||||
expect(pongFrame.type).toBe('pong');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('PROTO-05: 设备认证流程', () => {
|
||||
test('设备认证响应格式', () => {
|
||||
const authResponse = {
|
||||
status: 'authenticated',
|
||||
device_id: 'device-001',
|
||||
token: 'jwt-token-here',
|
||||
};
|
||||
expect(authResponse.status).toBe('authenticated');
|
||||
expect(authResponse.device_id).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user