Files
Claude-Code-Workflow/test-e2e-final.mjs
catlog22 c6093ef741 feat: add CLI Command Node and Prompt Node components for orchestrator
- Implemented CliCommandNode component for executing CLI tools with AI models.
- Implemented PromptNode component for constructing AI prompts with context.
- Added styling for mode and tool badges in both components.
- Enhanced user experience with command and argument previews, execution status, and error handling.

test: add comprehensive tests for ask_question tool

- Created direct test for ask_question tool execution.
- Developed end-to-end tests to validate ask_question tool integration with WebSocket and A2UI surfaces.
- Implemented simple and integrated WebSocket tests to ensure proper message handling and surface reception.
- Added tool registration test to verify ask_question tool is correctly registered.

chore: add WebSocket listener and simulation tests

- Added WebSocket listener for A2UI surfaces to facilitate testing.
- Implemented frontend simulation test to validate complete flow from backend to frontend.
- Created various test scripts to ensure robust testing of ask_question tool functionality.
2026-02-03 23:10:36 +08:00

135 lines
3.8 KiB
JavaScript

/**
* Final E2E test for ask_question tool
* Uses `ccw tool exec` to call tool through running server
*/
import { spawn } from 'child_process';
import { WebSocket } from 'ws';
async function testEndToEnd() {
console.log('=== E2E Test: ask_question Tool ===\n');
// Connect WebSocket client
console.log('1. Connecting WebSocket client...');
const ws = new WebSocket('ws://127.0.0.1:3456/ws');
await new Promise((resolve, reject) => {
ws.on('open', () => {
console.log('✓ WebSocket connected');
// Give the server time to register the client
setTimeout(resolve, 500);
});
ws.on('error', reject);
setTimeout(() => reject(new Error('Connection timeout')), 5000);
});
console.log(' Waiting for server to register client...\n');
// Listen for A2UI surface messages
let surfaceResolve;
const surfaceReceived = new Promise((resolve) => {
surfaceResolve = resolve;
});
let answered = false;
ws.on('message', (data) => {
try {
const message = JSON.parse(data.toString());
if (message.type === 'a2ui-surface' && !answered) {
console.log('3. ✓ Frontend received A2UI surface:');
console.log(' Surface ID:', message.surfaceUpdate.surfaceId);
console.log(' Components:', message.surfaceUpdate.components.length);
console.log(' Question:', message.surfaceUpdate.initialState?.questionId);
surfaceResolve(message);
// Auto-answer after receiving surface
setTimeout(() => {
console.log('\n4. Frontend sending answer via WebSocket...');
ws.send(JSON.stringify({
type: 'a2ui-answer',
questionId: message.surfaceUpdate.initialState?.questionId,
surfaceId: message.surfaceUpdate.surfaceId,
value: true, // Clicking "Confirm"
cancelled: false,
timestamp: new Date().toISOString()
}));
answered = true;
}, 100);
}
} catch (e) {
// Ignore parse errors
}
});
// Execute tool via ccw tool exec
console.log('2. Executing ask_question via `ccw tool exec`...\n');
const toolParams = JSON.stringify({
question: {
id: 'e2e-final-test',
type: 'confirm',
title: 'E2E Integration Test',
message: 'Testing complete ask_question flow',
description: 'WebSocket → A2UI Surface → User Answer → Backend'
},
timeout: 10000
});
const ccw = spawn('ccw', ['tool', 'exec', 'ask_question', toolParams], {
shell: true
});
let output = '';
ccw.stdout.on('data', (data) => {
output += data.toString();
});
ccw.stderr.on('data', (data) => {
console.error(' [ccw stderr]:', data.toString());
});
// Wait for surface OR timeout
try {
await Promise.race([
surfaceReceived,
new Promise((_, reject) => setTimeout(() => reject(new Error('Surface not received within 8s')), 8000))
]);
// Wait for ccw to finish
await new Promise((resolve) => {
ccw.on('close', (code) => {
console.log('\n5. ✓ Tool execution completed (exit code:', code + ')');
console.log('\nTool output:');
console.log(output);
resolve();
});
});
ws.close();
console.log('\n✅ E2E Test PASSED!');
console.log('\nVerified flow:');
console.log(' 1. WebSocket client connected ✓');
console.log(' 2. Backend tool executed via ccw ✓');
console.log(' 3. A2UI surface sent to frontend ✓');
console.log(' 4. Frontend answered via WebSocket ✓');
console.log(' 5. Backend received answer ✓');
} catch (error) {
console.error('\n❌ Test failed:', error.message);
ccw.kill();
ws.close();
process.exit(1);
}
}
testEndToEnd()
.then(() => process.exit(0))
.catch((err) => {
console.error('\n❌ E2E Test FAILED:', err.message);
process.exit(1);
});