- 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.
359 lines
9.6 KiB
JavaScript
359 lines
9.6 KiB
JavaScript
/**
|
||
* Test script to verify admin can perform actions during maintenance mode
|
||
*
|
||
* This script tests:
|
||
* 1. Admin can authenticate during maintenance
|
||
* 2. Admin can access admin endpoints during maintenance
|
||
* 3. Admin can perform CRUD operations during maintenance
|
||
* 4. Non-admin users are still blocked during maintenance
|
||
*
|
||
* Usage: node test-admin-maintenance.js
|
||
*/
|
||
|
||
import fetch from 'node-fetch';
|
||
import dotenv from 'dotenv';
|
||
|
||
dotenv.config();
|
||
|
||
const API_URL = process.env.VITE_API_URL || 'http://localhost:3000';
|
||
const BASE_URL = `${API_URL}/api`;
|
||
|
||
// Colors for console output
|
||
const colors = {
|
||
reset: '\x1b[0m',
|
||
bright: '\x1b[1m',
|
||
green: '\x1b[32m',
|
||
red: '\x1b[31m',
|
||
yellow: '\x1b[33m',
|
||
blue: '\x1b[34m',
|
||
};
|
||
|
||
function log(message, color = 'reset') {
|
||
console.log(`${colors[color]}${message}${colors.reset}`);
|
||
}
|
||
|
||
function logTest(name) {
|
||
console.log(`\n${colors.bright}${colors.blue}🧪 Testing: ${name}${colors.reset}`);
|
||
}
|
||
|
||
function logSuccess(message) {
|
||
log(`✅ ${message}`, 'green');
|
||
}
|
||
|
||
function logError(message) {
|
||
log(`❌ ${message}`, 'red');
|
||
}
|
||
|
||
function logWarning(message) {
|
||
log(`⚠️ ${message}`, 'yellow');
|
||
}
|
||
|
||
function logInfo(message) {
|
||
log(`ℹ️ ${message}`, 'blue');
|
||
}
|
||
|
||
// Helper to make authenticated requests
|
||
async function makeRequest(endpoint, options = {}) {
|
||
const url = endpoint.startsWith('http') ? endpoint : `${BASE_URL}${endpoint}`;
|
||
|
||
try {
|
||
const response = await fetch(url, {
|
||
...options,
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
...options.headers,
|
||
},
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
return {
|
||
status: response.status,
|
||
ok: response.ok,
|
||
data,
|
||
};
|
||
} catch (error) {
|
||
return {
|
||
status: 0,
|
||
ok: false,
|
||
error: error.message,
|
||
};
|
||
}
|
||
}
|
||
|
||
// Test 1: Check if maintenance mode is enabled
|
||
async function testMaintenanceStatus() {
|
||
logTest('Checking maintenance status');
|
||
|
||
const result = await makeRequest('/config/status');
|
||
|
||
if (result.ok) {
|
||
const { maintenance } = result.data;
|
||
if (maintenance) {
|
||
logSuccess('Maintenance mode is ENABLED');
|
||
return true;
|
||
} else {
|
||
logWarning('Maintenance mode is DISABLED - enable it to test properly');
|
||
return false;
|
||
}
|
||
} else {
|
||
logError(`Failed to check maintenance status: ${result.status}`);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// Test 2: Check public config endpoint (should work during maintenance)
|
||
async function testPublicConfig() {
|
||
logTest('Testing public config endpoint (should work during maintenance)');
|
||
|
||
const result = await makeRequest('/config/public');
|
||
|
||
if (result.ok) {
|
||
logSuccess('Public config endpoint accessible');
|
||
return true;
|
||
} else {
|
||
logError(`Public config endpoint failed: ${result.status}`);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// Test 3: Test unauthenticated admin request (should be blocked)
|
||
async function testUnauthenticatedAdminRequest() {
|
||
logTest('Testing unauthenticated admin request (should be blocked)');
|
||
|
||
const result = await makeRequest('/admin/config');
|
||
|
||
if (result.status === 503) {
|
||
logSuccess('Unauthenticated request correctly blocked (503)');
|
||
logInfo(`Message: ${result.data.message}`);
|
||
return true;
|
||
} else if (result.status === 401) {
|
||
logSuccess('Unauthenticated request blocked by auth (401)');
|
||
return true;
|
||
} else {
|
||
logError(`Unexpected status: ${result.status}`);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// Test 4: Test admin authentication (manual test - requires actual admin cookies)
|
||
async function testAdminAuthentication(cookies) {
|
||
logTest('Testing admin authentication with provided cookies');
|
||
|
||
if (!cookies) {
|
||
logWarning('No cookies provided - skipping authenticated tests');
|
||
logInfo('To test with authentication, run: node test-admin-maintenance.js "accessToken=your_token"');
|
||
return null;
|
||
}
|
||
|
||
const result = await makeRequest('/auth/me', {
|
||
headers: {
|
||
Cookie: cookies,
|
||
},
|
||
});
|
||
|
||
if (result.ok && result.data.user) {
|
||
const { user } = result.data;
|
||
logSuccess(`Authenticated as: ${user.username}`);
|
||
logInfo(`Staff Level: ${user.staffLevel}`);
|
||
|
||
if (user.staffLevel >= 3) {
|
||
logSuccess('User is an admin (staffLevel >= 3)');
|
||
return cookies;
|
||
} else {
|
||
logWarning('User is NOT an admin (staffLevel < 3)');
|
||
return null;
|
||
}
|
||
} else {
|
||
logError('Authentication failed');
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// Test 5: Test admin endpoints with authentication
|
||
async function testAdminEndpoints(cookies) {
|
||
if (!cookies) {
|
||
logWarning('Skipping admin endpoint tests - no valid admin cookies');
|
||
return false;
|
||
}
|
||
|
||
logTest('Testing admin endpoints during maintenance');
|
||
|
||
// Test 5a: Get admin config
|
||
const configResult = await makeRequest('/admin/config', {
|
||
headers: {
|
||
Cookie: cookies,
|
||
},
|
||
});
|
||
|
||
if (configResult.ok) {
|
||
logSuccess('GET /admin/config - Success');
|
||
} else {
|
||
logError(`GET /admin/config - Failed (${configResult.status})`);
|
||
if (configResult.data) {
|
||
logError(`Message: ${configResult.data.message || JSON.stringify(configResult.data)}`);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// Test 5b: Get users list
|
||
const usersResult = await makeRequest('/admin/users?page=1&limit=10', {
|
||
headers: {
|
||
Cookie: cookies,
|
||
},
|
||
});
|
||
|
||
if (usersResult.ok) {
|
||
logSuccess('GET /admin/users - Success');
|
||
logInfo(`Found ${usersResult.data.users?.length || 0} users`);
|
||
} else {
|
||
logError(`GET /admin/users - Failed (${usersResult.status})`);
|
||
if (usersResult.data) {
|
||
logError(`Message: ${usersResult.data.message || JSON.stringify(usersResult.data)}`);
|
||
}
|
||
}
|
||
|
||
// Test 5c: Get announcements
|
||
const announcementsResult = await makeRequest('/admin/announcements', {
|
||
headers: {
|
||
Cookie: cookies,
|
||
},
|
||
});
|
||
|
||
if (announcementsResult.ok) {
|
||
logSuccess('GET /admin/announcements - Success');
|
||
logInfo(`Found ${announcementsResult.data.announcements?.length || 0} announcements`);
|
||
} else {
|
||
logError(`GET /admin/announcements - Failed (${announcementsResult.status})`);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
// Test 6: Test maintenance toggle (the actual action that was failing)
|
||
async function testMaintenanceToggle(cookies) {
|
||
if (!cookies) {
|
||
logWarning('Skipping maintenance toggle test - no valid admin cookies');
|
||
return false;
|
||
}
|
||
|
||
logTest('Testing maintenance mode toggle (the critical test)');
|
||
|
||
// First, get current config
|
||
const getCurrentConfig = await makeRequest('/admin/config', {
|
||
headers: {
|
||
Cookie: cookies,
|
||
},
|
||
});
|
||
|
||
if (!getCurrentConfig.ok) {
|
||
logError('Failed to get current config');
|
||
return false;
|
||
}
|
||
|
||
const currentMaintenanceState = getCurrentConfig.data.config.maintenance.enabled;
|
||
logInfo(`Current maintenance state: ${currentMaintenanceState}`);
|
||
|
||
// Try to toggle maintenance (just toggle and toggle back)
|
||
const newState = !currentMaintenanceState;
|
||
|
||
const updateResult = await makeRequest('/admin/config/maintenance', {
|
||
method: 'PUT',
|
||
headers: {
|
||
Cookie: cookies,
|
||
},
|
||
body: JSON.stringify({
|
||
enabled: newState,
|
||
message: "Test toggle during maintenance",
|
||
}),
|
||
});
|
||
|
||
if (updateResult.ok) {
|
||
logSuccess(`Successfully toggled maintenance to: ${newState}`);
|
||
|
||
// Toggle back to original state
|
||
const restoreResult = await makeRequest('/admin/config/maintenance', {
|
||
method: 'PUT',
|
||
headers: {
|
||
Cookie: cookies,
|
||
},
|
||
body: JSON.stringify({
|
||
enabled: currentMaintenanceState,
|
||
message: getCurrentConfig.data.config.maintenance.message,
|
||
}),
|
||
});
|
||
|
||
if (restoreResult.ok) {
|
||
logSuccess(`Restored maintenance to original state: ${currentMaintenanceState}`);
|
||
} else {
|
||
logWarning(`Failed to restore original state - maintenance is now ${newState}`);
|
||
}
|
||
|
||
return true;
|
||
} else {
|
||
logError(`Failed to toggle maintenance (${updateResult.status})`);
|
||
if (updateResult.data) {
|
||
logError(`Message: ${updateResult.data.message || JSON.stringify(updateResult.data)}`);
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// Main test runner
|
||
async function runTests() {
|
||
log('\n' + '='.repeat(60), 'bright');
|
||
log('🔧 Admin Maintenance Mode Test Suite', 'bright');
|
||
log('='.repeat(60) + '\n', 'bright');
|
||
|
||
// Get cookies from command line if provided
|
||
const cookies = process.argv[2] || null;
|
||
|
||
if (!cookies) {
|
||
logWarning('No authentication cookies provided');
|
||
logInfo('To test with authentication:');
|
||
logInfo('1. Login to the site as admin');
|
||
logInfo('2. Open browser DevTools > Application > Cookies');
|
||
logInfo('3. Copy your accessToken cookie value');
|
||
logInfo('4. Run: node test-admin-maintenance.js "accessToken=YOUR_TOKEN_HERE"');
|
||
console.log();
|
||
}
|
||
|
||
let allPassed = true;
|
||
|
||
// Run tests
|
||
const maintenanceEnabled = await testMaintenanceStatus();
|
||
if (!maintenanceEnabled) {
|
||
logWarning('\n⚠️ Please enable maintenance mode in admin panel first!');
|
||
process.exit(1);
|
||
}
|
||
|
||
allPassed = await testPublicConfig() && allPassed;
|
||
allPassed = await testUnauthenticatedAdminRequest() && allPassed;
|
||
|
||
const validCookies = await testAdminAuthentication(cookies);
|
||
|
||
if (validCookies) {
|
||
allPassed = await testAdminEndpoints(validCookies) && allPassed;
|
||
allPassed = await testMaintenanceToggle(validCookies) && allPassed;
|
||
}
|
||
|
||
// Summary
|
||
log('\n' + '='.repeat(60), 'bright');
|
||
if (allPassed && validCookies) {
|
||
log('✅ All tests passed!', 'green');
|
||
} else if (!validCookies) {
|
||
log('⚠️ Basic tests passed, but admin tests were skipped', 'yellow');
|
||
log('Provide admin cookies to run full test suite', 'yellow');
|
||
} else {
|
||
log('❌ Some tests failed', 'red');
|
||
}
|
||
log('='.repeat(60) + '\n', 'bright');
|
||
}
|
||
|
||
// Run the tests
|
||
runTests().catch((error) => {
|
||
logError(`Test suite failed with error: ${error.message}`);
|
||
console.error(error);
|
||
process.exit(1);
|
||
});
|