- Add user management system with all CRUD operations - Add promotion statistics dashboard with export - Simplify Trading & Market settings UI - Fix promotion schema (dates now optional) - Add missing API endpoints and PATCH support - Add comprehensive documentation - Fix critical bugs (deletePromotion, duplicate endpoints) All features tested and production-ready.
236 lines
7.9 KiB
JavaScript
236 lines
7.9 KiB
JavaScript
#!/usr/bin/env node
|
||
|
||
/**
|
||
* Admin Routes Test Script
|
||
* Tests if admin routes are properly registered and accessible
|
||
*/
|
||
|
||
import axios from 'axios';
|
||
|
||
const API_URL = 'http://localhost:3000';
|
||
const COLORS = {
|
||
reset: '\x1b[0m',
|
||
red: '\x1b[31m',
|
||
green: '\x1b[32m',
|
||
yellow: '\x1b[33m',
|
||
blue: '\x1b[34m',
|
||
cyan: '\x1b[36m',
|
||
};
|
||
|
||
function colorize(text, color) {
|
||
return `${COLORS[color]}${text}${COLORS.reset}`;
|
||
}
|
||
|
||
function logSuccess(message) {
|
||
console.log(`${colorize('✅', 'green')} ${message}`);
|
||
}
|
||
|
||
function logError(message) {
|
||
console.log(`${colorize('❌', 'red')} ${message}`);
|
||
}
|
||
|
||
function logInfo(message) {
|
||
console.log(`${colorize('ℹ️', 'blue')} ${message}`);
|
||
}
|
||
|
||
function logWarning(message) {
|
||
console.log(`${colorize('⚠️', 'yellow')} ${message}`);
|
||
}
|
||
|
||
async function testHealth() {
|
||
console.log('\n' + colorize('='.repeat(60), 'cyan'));
|
||
console.log(colorize('TEST 1: Health Check', 'cyan'));
|
||
console.log(colorize('='.repeat(60), 'cyan'));
|
||
|
||
try {
|
||
const response = await axios.get(`${API_URL}/health`, { timeout: 5000 });
|
||
logSuccess('Backend is running');
|
||
logInfo(` Uptime: ${Math.floor(response.data.uptime)}s`);
|
||
logInfo(` Environment: ${response.data.environment}`);
|
||
return true;
|
||
} catch (error) {
|
||
logError('Backend is not accessible');
|
||
logError(` Error: ${error.message}`);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
async function testRoutesList() {
|
||
console.log('\n' + colorize('='.repeat(60), 'cyan'));
|
||
console.log(colorize('TEST 2: Routes List (Development Only)', 'cyan'));
|
||
console.log(colorize('='.repeat(60), 'cyan'));
|
||
|
||
try {
|
||
const response = await axios.get(`${API_URL}/api/routes`, { timeout: 5000 });
|
||
const adminRoutes = response.data.routes.filter(r => r.url.includes('/api/admin'));
|
||
const configRoutes = response.data.routes.filter(r => r.url.includes('/api/config'));
|
||
|
||
logSuccess(`Found ${adminRoutes.length} admin routes`);
|
||
logSuccess(`Found ${configRoutes.length} config routes`);
|
||
|
||
console.log('\n' + colorize('Admin Routes:', 'yellow'));
|
||
adminRoutes.slice(0, 10).forEach(route => {
|
||
console.log(` ${colorize(route.method.padEnd(6), 'green')} ${route.url}`);
|
||
});
|
||
|
||
if (adminRoutes.length > 10) {
|
||
console.log(` ... and ${adminRoutes.length - 10} more`);
|
||
}
|
||
|
||
console.log('\n' + colorize('Config Routes:', 'yellow'));
|
||
configRoutes.forEach(route => {
|
||
console.log(` ${colorize(route.method.padEnd(6), 'green')} ${route.url}`);
|
||
});
|
||
|
||
return adminRoutes.length > 0;
|
||
} catch (error) {
|
||
logWarning('Routes list not accessible (may be production mode)');
|
||
logInfo(' This is normal in production');
|
||
return null; // Not a failure, just unavailable
|
||
}
|
||
}
|
||
|
||
async function testAdminConfigNoAuth() {
|
||
console.log('\n' + colorize('='.repeat(60), 'cyan'));
|
||
console.log(colorize('TEST 3: Admin Config (No Auth)', 'cyan'));
|
||
console.log(colorize('='.repeat(60), 'cyan'));
|
||
|
||
try {
|
||
await axios.get(`${API_URL}/api/admin/config`, { timeout: 5000 });
|
||
logWarning('Admin config accessible without auth (security issue!)');
|
||
return false;
|
||
} catch (error) {
|
||
if (error.response?.status === 401) {
|
||
logSuccess('Admin config properly protected (401 Unauthorized)');
|
||
return true;
|
||
} else if (error.response?.status === 404) {
|
||
logError('Admin config route not found (404)');
|
||
logError(' Routes may not be registered. Restart the server!');
|
||
return false;
|
||
} else {
|
||
logError(`Unexpected error: ${error.response?.status || error.message}`);
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
async function testAdminUsersNoAuth() {
|
||
console.log('\n' + colorize('='.repeat(60), 'cyan'));
|
||
console.log(colorize('TEST 4: Admin Users Search (No Auth)', 'cyan'));
|
||
console.log(colorize('='.repeat(60), 'cyan'));
|
||
|
||
try {
|
||
await axios.get(`${API_URL}/api/admin/users/search?query=test&limit=1`, { timeout: 5000 });
|
||
logWarning('Admin users route accessible without auth (security issue!)');
|
||
return false;
|
||
} catch (error) {
|
||
if (error.response?.status === 401) {
|
||
logSuccess('Admin users route properly protected (401 Unauthorized)');
|
||
return true;
|
||
} else if (error.response?.status === 404) {
|
||
logError('Admin users route not found (404)');
|
||
logError(' Routes may not be registered. Restart the server!');
|
||
return false;
|
||
} else {
|
||
logError(`Unexpected error: ${error.response?.status || error.message}`);
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
async function testPublicConfig() {
|
||
console.log('\n' + colorize('='.repeat(60), 'cyan'));
|
||
console.log(colorize('TEST 5: Public Config Status', 'cyan'));
|
||
console.log(colorize('='.repeat(60), 'cyan'));
|
||
|
||
try {
|
||
const response = await axios.get(`${API_URL}/api/config/status`, { timeout: 5000 });
|
||
logSuccess('Public config status accessible');
|
||
logInfo(` Maintenance Mode: ${response.data.maintenance?.enabled ? 'ON' : 'OFF'}`);
|
||
logInfo(` Trading: ${response.data.trading ? 'Enabled' : 'Disabled'}`);
|
||
logInfo(` Market: ${response.data.market ? 'Enabled' : 'Disabled'}`);
|
||
return true;
|
||
} catch (error) {
|
||
if (error.response?.status === 404) {
|
||
logError('Public config route not found (404)');
|
||
logError(' Routes may not be registered. Restart the server!');
|
||
return false;
|
||
} else {
|
||
logError(`Error accessing public config: ${error.message}`);
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
async function runTests() {
|
||
console.log('\n' + colorize('╔' + '═'.repeat(58) + '╗', 'cyan'));
|
||
console.log(colorize('║' + ' '.repeat(12) + 'ADMIN ROUTES TEST SUITE' + ' '.repeat(23) + '║', 'cyan'));
|
||
console.log(colorize('╚' + '═'.repeat(58) + '╝', 'cyan'));
|
||
|
||
const results = {
|
||
health: false,
|
||
routes: null,
|
||
configNoAuth: false,
|
||
usersNoAuth: false,
|
||
publicConfig: false,
|
||
};
|
||
|
||
// Run tests
|
||
results.health = await testHealth();
|
||
|
||
if (!results.health) {
|
||
console.log('\n' + colorize('='.repeat(60), 'red'));
|
||
logError('Backend is not running. Start it with: npm run dev');
|
||
console.log(colorize('='.repeat(60), 'red'));
|
||
process.exit(1);
|
||
}
|
||
|
||
results.routes = await testRoutesList();
|
||
results.configNoAuth = await testAdminConfigNoAuth();
|
||
results.usersNoAuth = await testAdminUsersNoAuth();
|
||
results.publicConfig = await testPublicConfig();
|
||
|
||
// Summary
|
||
console.log('\n' + colorize('╔' + '═'.repeat(58) + '╗', 'cyan'));
|
||
console.log(colorize('║' + ' '.repeat(21) + 'TEST SUMMARY' + ' '.repeat(24) + '║', 'cyan'));
|
||
console.log(colorize('╚' + '═'.repeat(58) + '╝', 'cyan'));
|
||
|
||
const passed = [
|
||
results.health,
|
||
results.routes !== false,
|
||
results.configNoAuth,
|
||
results.usersNoAuth,
|
||
results.publicConfig,
|
||
].filter(Boolean).length;
|
||
|
||
const total = 5;
|
||
|
||
console.log(`\n${colorize(`Passed: ${passed}/${total}`, passed === total ? 'green' : 'yellow')}`);
|
||
|
||
if (results.configNoAuth === false || results.usersNoAuth === false || results.publicConfig === false) {
|
||
console.log('\n' + colorize('⚠️ ACTION REQUIRED:', 'yellow'));
|
||
console.log(colorize(' Routes are not registered properly.', 'yellow'));
|
||
console.log(colorize(' Please RESTART the backend server:', 'yellow'));
|
||
console.log(colorize(' 1. Stop server (Ctrl+C)', 'yellow'));
|
||
console.log(colorize(' 2. Run: npm run dev', 'yellow'));
|
||
console.log(colorize(' 3. Run this test again', 'yellow'));
|
||
} else {
|
||
console.log('\n' + colorize('✅ All routes are properly registered!', 'green'));
|
||
console.log(colorize(' Admin panel should work correctly.', 'green'));
|
||
console.log(colorize(' Access it at: http://localhost:5173/admin', 'green'));
|
||
}
|
||
|
||
console.log('\n' + colorize('='.repeat(60), 'cyan'));
|
||
console.log(colorize('Note: These tests check route registration, not authentication.', 'blue'));
|
||
console.log(colorize('To test full admin access, use the Debug panel in /admin', 'blue'));
|
||
console.log(colorize('='.repeat(60), 'cyan') + '\n');
|
||
|
||
process.exit(passed === total ? 0 : 1);
|
||
}
|
||
|
||
// Run tests
|
||
runTests().catch(error => {
|
||
console.error('\n' + colorize('Fatal Error:', 'red'), error.message);
|
||
process.exit(1);
|
||
});
|