mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-10 02:24:35 +08:00
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.
This commit is contained in:
134
test-e2e-final.mjs
Normal file
134
test-e2e-final.mjs
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* 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);
|
||||
});
|
||||
Reference in New Issue
Block a user