#!/usr/bin/env node /** * Test API Demo Script * * Demonstrates the Test API Server functionality * and validates all endpoints work correctly. * * @author Matthew Raymer * @version 1.0.0 */ const fetch = require('node-fetch'); const API_BASE_URL = 'http://localhost:3001'; /** * Make HTTP request with timeout * @param {string} url - Request URL * @param {Object} options - Fetch options * @returns {Promise} Response data */ async function makeRequest(url, options = {}) { try { const response = await fetch(url, { timeout: 10000, ...options }); const data = await response.json(); return { status: response.status, data, headers: Object.fromEntries(response.headers.entries()) }; } catch (error) { return { status: 0, error: error.message }; } } /** * Test health endpoint */ async function testHealth() { console.log('šŸ” Testing health endpoint...'); const result = await makeRequest(`${API_BASE_URL}/health`); if (result.error) { console.error('āŒ Health check failed:', result.error); return false; } console.log('āœ… Health check passed'); console.log(' Status:', result.status); console.log(' Version:', result.data.version); console.log(' Endpoints:', Object.keys(result.data.endpoints).length); return true; } /** * Test content fetching */ async function testContentFetching() { console.log('\nšŸ“± Testing content fetching...'); const slotId = 'slot-08:00'; const result = await makeRequest(`${API_BASE_URL}/api/content/${slotId}`); if (result.error) { console.error('āŒ Content fetch failed:', result.error); return false; } console.log('āœ… Content fetch passed'); console.log(' Status:', result.status); console.log(' Slot ID:', result.data.slotId); console.log(' Title:', result.data.title); console.log(' ETag:', result.headers.etag); return result.headers.etag; } /** * Test ETag caching */ async function testETagCaching(etag) { console.log('\nšŸ”„ Testing ETag caching...'); const slotId = 'slot-08:00'; const result = await makeRequest(`${API_BASE_URL}/api/content/${slotId}`, { headers: { 'If-None-Match': etag } }); if (result.error) { console.error('āŒ ETag test failed:', result.error); return false; } if (result.status === 304) { console.log('āœ… ETag caching works (304 Not Modified)'); return true; } else { console.log('āš ļø ETag caching unexpected response:', result.status); return false; } } /** * Test error scenarios */ async function testErrorScenarios() { console.log('\n🚨 Testing error scenarios...'); const errorTypes = ['server-error', 'not-found', 'rate-limit', 'unauthorized']; let passed = 0; for (const errorType of errorTypes) { const result = await makeRequest(`${API_BASE_URL}/api/error/${errorType}`); if (result.error) { console.log(`āŒ ${errorType}: ${result.error}`); } else { console.log(`āœ… ${errorType}: ${result.status}`); passed++; } } console.log(` Passed: ${passed}/${errorTypes.length}`); return passed === errorTypes.length; } /** * Test metrics endpoint */ async function testMetrics() { console.log('\nšŸ“Š Testing metrics endpoint...'); const result = await makeRequest(`${API_BASE_URL}/api/metrics`); if (result.error) { console.error('āŒ Metrics test failed:', result.error); return false; } console.log('āœ… Metrics endpoint works'); console.log(' Content store size:', result.data.contentStore.size); console.log(' ETag store size:', result.data.etagStore.size); console.log(' Uptime:', Math.round(result.data.uptime), 'seconds'); return true; } /** * Test content update */ async function testContentUpdate() { console.log('\nāœļø Testing content update...'); const slotId = 'slot-08:00'; const newContent = { content: { title: 'Updated Test Title', body: 'This is updated test content', timestamp: Date.now() } }; const result = await makeRequest(`${API_BASE_URL}/api/content/${slotId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newContent) }); if (result.error) { console.error('āŒ Content update failed:', result.error); return false; } console.log('āœ… Content update works'); console.log(' Status:', result.status); console.log(' New ETag:', result.data.etag); return true; } /** * Test content clearing */ async function testContentClearing() { console.log('\nšŸ—‘ļø Testing content clearing...'); const result = await makeRequest(`${API_BASE_URL}/api/content`, { method: 'DELETE' }); if (result.error) { console.error('āŒ Content clearing failed:', result.error); return false; } console.log('āœ… Content clearing works'); console.log(' Status:', result.status); return true; } /** * Main test runner */ async function runTests() { console.log('šŸš€ Starting Test API validation...\n'); const tests = [ { name: 'Health Check', fn: testHealth }, { name: 'Content Fetching', fn: testContentFetching }, { name: 'ETag Caching', fn: testETagCaching }, { name: 'Error Scenarios', fn: testErrorScenarios }, { name: 'Metrics', fn: testMetrics }, { name: 'Content Update', fn: testContentUpdate }, { name: 'Content Clearing', fn: testContentClearing } ]; let passed = 0; let etag = null; for (const test of tests) { try { if (test.name === 'ETag Caching' && etag) { const result = await test.fn(etag); if (result) passed++; } else { const result = await test.fn(); if (result) { passed++; if (test.name === 'Content Fetching' && typeof result === 'string') { etag = result; } } } } catch (error) { console.error(`āŒ ${test.name} failed with error:`, error.message); } } console.log(`\nšŸ“‹ Test Results: ${passed}/${tests.length} passed`); if (passed === tests.length) { console.log('šŸŽ‰ All tests passed! Test API is working correctly.'); } else { console.log('āš ļø Some tests failed. Check the output above for details.'); } console.log('\nšŸ’” Next steps:'); console.log(' 1. Start your test app'); console.log(' 2. Configure it to use this API'); console.log(' 3. Test plugin functionality'); console.log(' 4. Monitor API metrics at /api/metrics'); } // Check if API server is running async function checkServer() { try { const result = await makeRequest(`${API_BASE_URL}/health`); if (result.error) { console.error('āŒ Cannot connect to Test API Server'); console.error(' Make sure the server is running: npm start'); console.error(' Server should be available at:', API_BASE_URL); process.exit(1); } } catch (error) { console.error('āŒ Cannot connect to Test API Server'); console.error(' Make sure the server is running: npm start'); console.error(' Server should be available at:', API_BASE_URL); process.exit(1); } } // Run tests checkServer().then(() => { runTests().catch(error => { console.error('āŒ Test runner failed:', error.message); process.exit(1); }); });