#!/usr/bin/env node /** * End-to-End Voice Command Test * Tests the full voice flow: classify + create activity in database */ const API_URL = process.env.API_URL || 'http://localhost:3020'; // ANSI color codes const colors = { reset: '\x1b[0m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', cyan: '\x1b[36m', }; // Test credentials const TEST_USER = { email: 'andrei@cloudz.ro', password: 'Test1234!', }; // Test commands const commands = [ 'Change wet diaper', 'Baby ate 150ml formula', 'Baby slept for 1 hour', 'Alice ate 3 pcs of broccoli at 11:00 AM', ]; let accessToken = null; let childId = null; async function login() { console.log(`${colors.blue}Logging in...${colors.reset}`); const response = await fetch(`${API_URL}/api/v1/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(TEST_USER), }); const data = await response.json(); if (!response.ok || !data.success) { throw new Error(`Login failed: ${data.message || 'Unknown error'}`); } accessToken = data.data.accessToken; console.log(`${colors.green}✓ Logged in successfully${colors.reset}\n`); } async function getChild() { console.log(`${colors.blue}Fetching children...${colors.reset}`); const response = await fetch(`${API_URL}/api/v1/children`, { headers: { 'Authorization': `Bearer ${accessToken}` }, }); const data = await response.json(); if (!response.ok || !data.success || data.data.length === 0) { throw new Error('No children found'); } childId = data.data[0].id; console.log(`${colors.green}✓ Found child: ${data.data[0].name} (${childId})${colors.reset}\n`); } async function getActivitiesCount(type = null) { let url = `${API_URL}/api/v1/activities?childId=${childId}&limit=1000`; if (type) url += `&type=${type}`; const response = await fetch(url, { headers: { 'Authorization': `Bearer ${accessToken}` }, }); const data = await response.json(); return data.success ? data.data.length : 0; } async function classifyAndCreateActivity(text) { console.log(`${colors.yellow}Processing: "${text}"${colors.reset}`); // Step 1: Classify the command const classifyResponse = await fetch(`${API_URL}/api/v1/voice/transcribe`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}`, }, body: JSON.stringify({ text, language: 'en', childName: 'Alice', }), }); const classifyData = await classifyResponse.json(); if (!classifyResponse.ok || !classifyData.success) { console.log(`${colors.red}✗ Classification failed${colors.reset}`); console.log(JSON.stringify(classifyData, null, 2)); return false; } const { type, details, timestamp, confidence } = classifyData.classification; console.log(` Type: ${type} (confidence: ${confidence})`); console.log(` Details: ${JSON.stringify(details)}`); if (type === 'unknown' || confidence < 0.3) { console.log(`${colors.red}✗ Low confidence or unknown type${colors.reset}\n`); return false; } // Step 2: Create the activity const activityData = { type, timestamp: timestamp || new Date().toISOString(), data: details || {}, notes: details?.notes || undefined, }; const createResponse = await fetch(`${API_URL}/api/v1/activities`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}`, }, body: JSON.stringify({ childId, ...activityData, }), }); const createData = await createResponse.json(); if (!createResponse.ok || !createData.success) { console.log(`${colors.red}✗ Failed to create activity${colors.reset}`); console.log(JSON.stringify(createData, null, 2)); return false; } console.log(`${colors.green}✓ Activity created: ${createData.data.id}${colors.reset}\n`); return true; } async function runTests() { console.log(`${colors.blue}========================================${colors.reset}`); console.log(`${colors.blue}Voice E2E Test Suite${colors.reset}`); console.log(`${colors.blue}========================================${colors.reset}\n`); try { // Login and get child await login(); await getChild(); // Get initial counts const initialCounts = { total: await getActivitiesCount(), diaper: await getActivitiesCount('diaper'), feeding: await getActivitiesCount('feeding'), sleep: await getActivitiesCount('sleep'), }; console.log(`${colors.cyan}Initial activity counts:${colors.reset}`); console.log(` Total: ${initialCounts.total}`); console.log(` Diapers: ${initialCounts.diaper}`); console.log(` Feedings: ${initialCounts.feeding}`); console.log(` Sleep: ${initialCounts.sleep}\n`); // Run tests let passed = 0; let failed = 0; for (const command of commands) { const result = await classifyAndCreateActivity(command); if (result) { passed++; } else { failed++; } } // Get final counts const finalCounts = { total: await getActivitiesCount(), diaper: await getActivitiesCount('diaper'), feeding: await getActivitiesCount('feeding'), sleep: await getActivitiesCount('sleep'), }; console.log(`${colors.cyan}Final activity counts:${colors.reset}`); console.log(` Total: ${finalCounts.total} (+${finalCounts.total - initialCounts.total})`); console.log(` Diapers: ${finalCounts.diaper} (+${finalCounts.diaper - initialCounts.diaper})`); console.log(` Feedings: ${finalCounts.feeding} (+${finalCounts.feeding - initialCounts.feeding})`); console.log(` Sleep: ${finalCounts.sleep} (+${finalCounts.sleep - initialCounts.sleep})\n`); // Summary console.log(`${colors.blue}========================================${colors.reset}`); console.log(`${colors.blue}Test Summary${colors.reset}`); console.log(`${colors.blue}========================================${colors.reset}`); console.log(`Total: ${commands.length}`); console.log(`${colors.green}Passed: ${passed}${colors.reset}`); console.log(`${colors.red}Failed: ${failed}${colors.reset}`); console.log(''); if (failed === 0) { console.log(`${colors.green}All tests passed! Activities saved to database. 🎉${colors.reset}`); process.exit(0); } else { console.log(`${colors.red}Some tests failed. Check the output above.${colors.reset}`); process.exit(1); } } catch (error) { console.error(`${colors.red}Fatal error: ${error.message}${colors.reset}`); console.error(error.stack); process.exit(1); } } // Run tests runTests();