← back to Handbag Auth Nextjs
auction-viewer/master-test-suite.js
878 lines
#!/usr/bin/env node
/**
* LUXVAULT Master Test Suite
* Comprehensive testing framework for all application layers
*
* Test Categories:
* - Unit Tests (Database, Calculations, Utilities)
* - Integration Tests (API Endpoints)
* - E2E Tests (User Workflows)
* - Performance Tests (Load, Response Time)
* - Security Tests (SQL Injection, XSS, Rate Limiting)
*
* Usage: node master-test-suite.js [--verbose] [--category=unit|integration|e2e|performance|security]
*/
const http = require('http');
const https = require('https');
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const HOST = process.env.TEST_HOST || '45.61.58.125';
const PORT = process.env.TEST_PORT || 7500;
const BASE_URL = `http://${HOST}:${PORT}`;
// CLI Arguments
const args = process.argv.slice(2);
const verbose = args.includes('--verbose') || args.includes('-v');
const categoryArg = args.find(arg => arg.startsWith('--category='));
const targetCategory = categoryArg ? categoryArg.split('=')[1] : 'all';
// Colors for console output
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
dim: '\x1b[2m',
green: '\x1b[32m',
red: '\x1b[31m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
cyan: '\x1b[36m',
magenta: '\x1b[35m',
white: '\x1b[37m'
};
// Test results tracking
const testResults = {
unit: { passed: 0, failed: 0, skipped: 0, errors: [] },
integration: { passed: 0, failed: 0, skipped: 0, errors: [] },
e2e: { passed: 0, failed: 0, skipped: 0, errors: [] },
performance: { passed: 0, failed: 0, skipped: 0, errors: [], benchmarks: [] },
security: { passed: 0, failed: 0, skipped: 0, errors: [] }
};
const startTime = Date.now();
// ============================================
// UTILITY FUNCTIONS
// ============================================
function log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`);
}
function logSection(title) {
console.log('\n' + '='.repeat(60));
log(title, 'bright');
console.log('='.repeat(60));
}
function logTest(name, passed, details = '') {
const symbol = passed ? '✓' : '✗';
const color = passed ? 'green' : 'red';
log(` ${symbol} ${name}`, color);
if (details && verbose) {
log(` ${details}`, 'dim');
}
}
async function makeRequest(options) {
return new Promise((resolve, reject) => {
const url = new URL(options.path || '/', BASE_URL);
const reqOptions = {
hostname: HOST,
port: PORT,
path: url.pathname + url.search,
method: options.method || 'GET',
headers: options.headers || {},
timeout: options.timeout || 10000
};
const req = http.request(reqOptions, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
resolve({
status: res.statusCode,
headers: res.headers,
data: data,
json: () => {
try {
return JSON.parse(data);
} catch (e) {
return null;
}
}
});
});
});
req.on('error', reject);
req.on('timeout', () => {
req.destroy();
reject(new Error('Request timeout'));
});
if (options.body) {
req.write(options.body);
}
req.end();
});
}
async function measureResponseTime(path) {
const start = Date.now();
await makeRequest({ path });
return Date.now() - start;
}
// ============================================
// UNIT TESTS
// ============================================
async function runUnitTests() {
if (targetCategory !== 'all' && targetCategory !== 'unit') {
testResults.unit.skipped++;
return;
}
logSection('UNIT TESTS');
try {
log('Running Jest unit tests...', 'cyan');
// Run Jest tests
try {
const output = execSync('npm run test:unit 2>&1', {
encoding: 'utf8',
cwd: path.join(__dirname)
});
// Parse Jest output
const passMatch = output.match(/Tests:\s+(\d+) passed/);
const failMatch = output.match(/(\d+) failed/);
if (passMatch) {
testResults.unit.passed += parseInt(passMatch[1]);
}
if (failMatch) {
testResults.unit.failed += parseInt(failMatch[1]);
}
logTest('Database unit tests', !failMatch, passMatch ? `${passMatch[1]} tests passed` : '');
logTest('Calculation unit tests', !failMatch);
} catch (error) {
// Jest exits with error code on test failures
const output = error.stdout || error.message;
if (output.includes('PASS')) {
const passMatch = output.match(/Tests:\s+(\d+) passed/);
if (passMatch) {
testResults.unit.passed += parseInt(passMatch[1]);
logTest('Unit tests executed', true, `${passMatch[1]} tests passed`);
}
} else {
testResults.unit.failed++;
testResults.unit.errors.push('Unit tests failed to execute');
logTest('Unit tests', false, 'Failed to execute');
}
}
} catch (error) {
testResults.unit.failed++;
testResults.unit.errors.push(error.message);
logTest('Unit test suite', false, error.message);
}
}
// ============================================
// INTEGRATION TESTS - API Endpoints
// ============================================
async function runIntegrationTests() {
if (targetCategory !== 'all' && targetCategory !== 'integration') {
testResults.integration.skipped++;
return;
}
logSection('INTEGRATION TESTS - API ENDPOINTS');
// Core Endpoints
log('\nCore Endpoints:', 'cyan');
const coreTests = [
{ name: 'Health check', path: '/health', expectStatus: 200 },
{ name: 'System status', path: '/api/status', expectStatus: 200 },
{ name: 'Main dashboard', path: '/', expectStatus: 200 },
];
for (const test of coreTests) {
try {
const response = await makeRequest({ path: test.path });
const passed = response.status === test.expectStatus;
if (passed) testResults.integration.passed++;
else {
testResults.integration.failed++;
testResults.integration.errors.push(`${test.name}: Expected ${test.expectStatus}, got ${response.status}`);
}
logTest(test.name, passed, `Status: ${response.status}`);
} catch (error) {
testResults.integration.failed++;
testResults.integration.errors.push(`${test.name}: ${error.message}`);
logTest(test.name, false, error.message);
}
}
// API v1 Endpoints
log('\nAPI v1 Endpoints:', 'cyan');
const apiTests = [
{ name: 'List auctions', path: '/api/v1/auctions?limit=5', expectStatus: 200 },
{ name: 'Pagination', path: '/api/v1/auctions?limit=10&page=2', expectStatus: 200 },
{ name: 'Brand filter', path: '/api/v1/auctions?brand=Hermes%20Birkin&limit=5', expectStatus: 200 },
{ name: 'Price range filter', path: '/api/v1/auctions?min_price=5000&max_price=10000', expectStatus: 200 },
{ name: 'Sort by price', path: '/api/v1/auctions?sort=price&order=asc', expectStatus: 200 },
{ name: 'Full-text search', path: '/api/v1/search?q=birkin', expectStatus: 200 },
{ name: 'Statistics', path: '/api/stats', expectStatus: 200 },
{ name: 'Best values', path: '/api/best-values?limit=10', expectStatus: 200 },
];
for (const test of apiTests) {
try {
const response = await makeRequest({ path: test.path });
const data = response.json();
const passed = response.status === test.expectStatus && (data && data.success !== false);
if (passed) testResults.integration.passed++;
else {
testResults.integration.failed++;
testResults.integration.errors.push(`${test.name}: Status ${response.status}`);
}
logTest(test.name, passed, `Status: ${response.status}`);
} catch (error) {
testResults.integration.failed++;
testResults.integration.errors.push(`${test.name}: ${error.message}`);
logTest(test.name, false, error.message);
}
}
// Analytics Endpoints
log('\nAnalytics Endpoints:', 'cyan');
const analyticsTests = [
{ name: 'Deal scores', path: '/api/insights/deal-scores?limit=5' },
{ name: 'Price trends', path: '/api/insights/trends' },
{ name: 'Anomalies', path: '/api/insights/anomalies' },
{ name: 'Market insights', path: '/api/insights/market' },
{ name: 'Recommendations', path: '/api/insights/recommendations?budget=5000' },
{ name: 'Compare brands', path: '/api/insights/compare-brands' },
{ name: 'Auction velocity', path: '/api/insights/velocity' },
{ name: 'Time series', path: '/api/insights/time-series?interval=month' },
];
for (const test of analyticsTests) {
try {
const response = await makeRequest({ path: test.path });
const data = response.json();
const passed = response.status === 200 && data && data.success === true;
if (passed) testResults.integration.passed++;
else {
testResults.integration.failed++;
testResults.integration.errors.push(`${test.name}: Invalid response`);
}
logTest(test.name, passed, `Status: ${response.status}`);
} catch (error) {
testResults.integration.failed++;
testResults.integration.errors.push(`${test.name}: ${error.message}`);
logTest(test.name, false, error.message);
}
}
}
// ============================================
// E2E TESTS - User Workflows
// ============================================
async function runE2ETests() {
if (targetCategory !== 'all' && targetCategory !== 'e2e') {
testResults.e2e.skipped++;
return;
}
logSection('E2E TESTS - USER WORKFLOWS');
// Workflow 1: View dashboard and navigate
log('\nWorkflow: Dashboard Navigation', 'cyan');
try {
const dashboard = await makeRequest({ path: '/' });
const passed1 = dashboard.status === 200 && dashboard.data.includes('LUXVAULT');
if (passed1) testResults.e2e.passed++;
else testResults.e2e.failed++;
logTest('Load dashboard page', passed1);
// Check if best-values page exists
const bestValues = await makeRequest({ path: '/best-values.html' });
const passed2 = bestValues.status === 200;
if (passed2) testResults.e2e.passed++;
else testResults.e2e.failed++;
logTest('Load best values page', passed2);
// Check analytics dashboard
const analytics = await makeRequest({ path: '/analytics-dashboard.html' });
const passed3 = analytics.status === 200;
if (passed3) testResults.e2e.passed++;
else testResults.e2e.failed++;
logTest('Load analytics dashboard', passed3);
} catch (error) {
testResults.e2e.failed++;
testResults.e2e.errors.push(`Dashboard workflow: ${error.message}`);
logTest('Dashboard workflow', false, error.message);
}
// Workflow 2: Search and filter
log('\nWorkflow: Search and Filter', 'cyan');
try {
// Search for items
const search = await makeRequest({ path: '/api/v1/search?q=birkin' });
const searchData = search.json();
const passed1 = search.status === 200 && searchData.success;
if (passed1) testResults.e2e.passed++;
else testResults.e2e.failed++;
logTest('Search for "birkin"', passed1, searchData ? `Found ${searchData.total || 0} results` : '');
// Filter by brand
const filter = await makeRequest({ path: '/api/v1/auctions?brand=Hermes%20Birkin&limit=10' });
const filterData = filter.json();
const passed2 = filter.status === 200 && filterData.success;
if (passed2) testResults.e2e.passed++;
else testResults.e2e.failed++;
logTest('Filter by brand', passed2);
// Apply multiple filters
const multiFilter = await makeRequest({
path: '/api/v1/auctions?brand=Hermes%20Birkin&min_price=5000&max_price=20000&sort=price&order=asc'
});
const multiData = multiFilter.json();
const passed3 = multiFilter.status === 200 && multiData.success;
if (passed3) testResults.e2e.passed++;
else testResults.e2e.failed++;
logTest('Apply multiple filters', passed3);
} catch (error) {
testResults.e2e.failed++;
testResults.e2e.errors.push(`Search workflow: ${error.message}`);
logTest('Search workflow', false, error.message);
}
// Workflow 3: Analytics exploration
log('\nWorkflow: Analytics Exploration', 'cyan');
try {
// Get market insights
const market = await makeRequest({ path: '/api/insights/market' });
const marketData = market.json();
const passed1 = market.status === 200 && marketData.success;
if (passed1) testResults.e2e.passed++;
else testResults.e2e.failed++;
logTest('View market insights', passed1);
// Get deal scores
const deals = await makeRequest({ path: '/api/insights/deal-scores?limit=10' });
const dealsData = deals.json();
const passed2 = deals.status === 200 && dealsData.success;
if (passed2) testResults.e2e.passed++;
else testResults.e2e.failed++;
logTest('View top deals', passed2);
// Get recommendations
const recs = await makeRequest({ path: '/api/insights/recommendations?budget=10000' });
const recsData = recs.json();
const passed3 = recs.status === 200 && recsData.success;
if (passed3) testResults.e2e.passed++;
else testResults.e2e.failed++;
logTest('Get recommendations', passed3);
} catch (error) {
testResults.e2e.failed++;
testResults.e2e.errors.push(`Analytics workflow: ${error.message}`);
logTest('Analytics workflow', false, error.message);
}
}
// ============================================
// PERFORMANCE TESTS
// ============================================
async function runPerformanceTests() {
if (targetCategory !== 'all' && targetCategory !== 'performance') {
testResults.performance.skipped++;
return;
}
logSection('PERFORMANCE TESTS');
// Response time benchmarks
log('\nResponse Time Benchmarks:', 'cyan');
const benchmarks = [
{ name: 'Dashboard load', path: '/', threshold: 500 },
{ name: 'API list auctions', path: '/api/v1/auctions?limit=50', threshold: 200 },
{ name: 'Search query', path: '/api/v1/search?q=birkin', threshold: 150 },
{ name: 'Statistics', path: '/api/stats', threshold: 200 },
{ name: 'Best values', path: '/api/best-values?limit=20', threshold: 200 },
{ name: 'Analytics insights', path: '/api/insights/market', threshold: 300 },
];
for (const benchmark of benchmarks) {
try {
// Run 3 times and take average
const times = [];
for (let i = 0; i < 3; i++) {
times.push(await measureResponseTime(benchmark.path));
}
const avgTime = Math.round(times.reduce((a, b) => a + b, 0) / times.length);
const passed = avgTime < benchmark.threshold;
if (passed) testResults.performance.passed++;
else {
testResults.performance.failed++;
testResults.performance.errors.push(`${benchmark.name}: ${avgTime}ms > ${benchmark.threshold}ms`);
}
testResults.performance.benchmarks.push({
name: benchmark.name,
avgTime,
threshold: benchmark.threshold,
passed
});
logTest(
benchmark.name,
passed,
`${avgTime}ms (threshold: ${benchmark.threshold}ms)`
);
} catch (error) {
testResults.performance.failed++;
testResults.performance.errors.push(`${benchmark.name}: ${error.message}`);
logTest(benchmark.name, false, error.message);
}
}
// Cache effectiveness test
log('\nCache Performance:', 'cyan');
try {
const coldTime = await measureResponseTime('/api/stats');
const warmTime = await measureResponseTime('/api/stats');
const improvement = ((coldTime - warmTime) / coldTime * 100).toFixed(1);
const passed = warmTime < coldTime;
if (passed) testResults.performance.passed++;
else testResults.performance.failed++;
logTest(
'Cache effectiveness',
passed,
`Cold: ${coldTime}ms, Warm: ${warmTime}ms (${improvement}% improvement)`
);
} catch (error) {
testResults.performance.failed++;
logTest('Cache test', false, error.message);
}
// Load test (concurrent requests)
log('\nLoad Testing:', 'cyan');
try {
const concurrentRequests = 50;
const startTime = Date.now();
const promises = Array(concurrentRequests).fill(null).map(() =>
makeRequest({ path: '/api/v1/auctions?limit=10' })
);
const results = await Promise.all(promises);
const totalTime = Date.now() - startTime;
const successCount = results.filter(r => r.status === 200).length;
const avgTime = totalTime / concurrentRequests;
const passed = successCount === concurrentRequests && avgTime < 500;
if (passed) testResults.performance.passed++;
else testResults.performance.failed++;
logTest(
`${concurrentRequests} concurrent requests`,
passed,
`${successCount}/${concurrentRequests} successful, avg ${Math.round(avgTime)}ms`
);
} catch (error) {
testResults.performance.failed++;
logTest('Load test', false, error.message);
}
}
// ============================================
// SECURITY TESTS
// ============================================
async function runSecurityTests() {
if (targetCategory !== 'all' && targetCategory !== 'security') {
testResults.security.skipped++;
return;
}
logSection('SECURITY TESTS');
// SQL Injection tests
log('\nSQL Injection Prevention:', 'cyan');
const sqlInjectionTests = [
{ name: 'Sort parameter injection', path: '/api/best-values?sort=percent; DROP TABLE auctions;--', expectStatus: 400 },
{ name: 'Limit parameter injection', path: '/api/auctions?limit=1 OR 1=1', expectStatus: 400 },
{ name: 'Search query injection', path: '/api/v1/search?q=\' OR 1=1--', expectStatus: 400 },
];
for (const test of sqlInjectionTests) {
try {
const response = await makeRequest({ path: test.path });
const passed = response.status === test.expectStatus || response.status === 200;
if (passed) testResults.security.passed++;
else {
testResults.security.failed++;
testResults.security.errors.push(`${test.name}: Unexpected status ${response.status}`);
}
logTest(test.name, passed);
} catch (error) {
testResults.security.passed++; // Connection errors are acceptable for malicious input
logTest(test.name, true, 'Request blocked');
}
}
// Input validation tests
log('\nInput Validation:', 'cyan');
const validationTests = [
{ name: 'Negative limit', path: '/api/auctions?limit=-1', expectStatus: 400 },
{ name: 'Excessive limit', path: '/api/auctions?limit=99999', expectStatus: 400 },
{ name: 'Invalid sort parameter', path: '/api/best-values?sort=invalid_field', expectStatus: 400 },
{ name: 'Invalid order parameter', path: '/api/v1/auctions?order=invalid', expectStatus: 400 },
];
for (const test of validationTests) {
try {
const response = await makeRequest({ path: test.path });
const passed = response.status === test.expectStatus;
if (passed) testResults.security.passed++;
else {
testResults.security.failed++;
testResults.security.errors.push(`${test.name}: Expected ${test.expectStatus}, got ${response.status}`);
}
logTest(test.name, passed, `Status: ${response.status}`);
} catch (error) {
testResults.security.failed++;
logTest(test.name, false, error.message);
}
}
// Security headers test
log('\nSecurity Headers:', 'cyan');
try {
const response = await makeRequest({ path: '/' });
const headers = response.headers;
const requiredHeaders = [
{ name: 'X-Content-Type-Options', check: h => h['x-content-type-options'] === 'nosniff' },
{ name: 'X-Frame-Options', check: h => h['x-frame-options'] },
{ name: 'Strict-Transport-Security', check: h => h['strict-transport-security'] },
{ name: 'Content-Security-Policy', check: h => h['content-security-policy'] },
];
for (const header of requiredHeaders) {
const passed = header.check(headers);
if (passed) testResults.security.passed++;
else {
testResults.security.failed++;
testResults.security.errors.push(`Missing header: ${header.name}`);
}
logTest(header.name, passed);
}
} catch (error) {
testResults.security.failed++;
logTest('Security headers', false, error.message);
}
// Rate limiting test
log('\nRate Limiting:', 'cyan');
try {
// Make rapid requests to trigger rate limit
const rapidRequests = 25;
let rateLimitTriggered = false;
for (let i = 0; i < rapidRequests; i++) {
const response = await makeRequest({ path: '/api/logs' });
if (response.status === 429) {
rateLimitTriggered = true;
break;
}
}
if (rateLimitTriggered) testResults.security.passed++;
else {
testResults.security.failed++;
testResults.security.errors.push('Rate limiting not triggered');
}
logTest('Rate limiting active', rateLimitTriggered);
} catch (error) {
testResults.security.failed++;
logTest('Rate limiting test', false, error.message);
}
}
// ============================================
// COVERAGE ANALYSIS
// ============================================
function analyzeCoverage() {
logSection('CODE COVERAGE ANALYSIS');
try {
const coverageFile = path.join(__dirname, 'coverage', 'coverage-summary.json');
if (fs.existsSync(coverageFile)) {
const coverage = JSON.parse(fs.readFileSync(coverageFile, 'utf8'));
const total = coverage.total;
log('\nCoverage Summary:', 'cyan');
log(` Lines: ${total.lines.pct.toFixed(2)}%`, total.lines.pct >= 70 ? 'green' : 'yellow');
log(` Statements: ${total.statements.pct.toFixed(2)}%`, total.statements.pct >= 70 ? 'green' : 'yellow');
log(` Functions: ${total.functions.pct.toFixed(2)}%`, total.functions.pct >= 70 ? 'green' : 'yellow');
log(` Branches: ${total.branches.pct.toFixed(2)}%`, total.branches.pct >= 60 ? 'green' : 'yellow');
return total;
} else {
log(' Coverage report not found', 'yellow');
return null;
}
} catch (error) {
log(` Error reading coverage: ${error.message}`, 'red');
return null;
}
}
// ============================================
// FINAL REPORT GENERATION
// ============================================
function generateReport() {
const totalTime = ((Date.now() - startTime) / 1000).toFixed(2);
logSection('TEST EXECUTION SUMMARY');
console.log('\n' + colors.bright + 'Results by Category:' + colors.reset);
console.log('─'.repeat(60));
const categories = ['unit', 'integration', 'e2e', 'performance', 'security'];
let totalPassed = 0;
let totalFailed = 0;
let totalSkipped = 0;
categories.forEach(category => {
const result = testResults[category];
totalPassed += result.passed;
totalFailed += result.failed;
totalSkipped += result.skipped;
const total = result.passed + result.failed;
const passRate = total > 0 ? ((result.passed / total) * 100).toFixed(1) : '0.0';
const color = result.failed === 0 ? 'green' : (result.failed > result.passed ? 'red' : 'yellow');
console.log(
` ${category.padEnd(15)} ` +
`${colors.green}${result.passed} passed${colors.reset} ` +
`${colors.red}${result.failed} failed${colors.reset} ` +
`${colors.dim}${result.skipped} skipped${colors.reset} ` +
`${colors[color]}(${passRate}%)${colors.reset}`
);
});
console.log('─'.repeat(60));
const grandTotal = totalPassed + totalFailed;
const overallPassRate = ((totalPassed / grandTotal) * 100).toFixed(1);
console.log(
` ${colors.bright}TOTAL${colors.reset} ` +
`${colors.green}${totalPassed} passed${colors.reset} ` +
`${colors.red}${totalFailed} failed${colors.reset} ` +
`${colors.dim}${totalSkipped} skipped${colors.reset} ` +
`${colors.bright}(${overallPassRate}%)${colors.reset}`
);
// Performance benchmarks
if (testResults.performance.benchmarks.length > 0) {
console.log('\n' + colors.bright + 'Performance Benchmarks:' + colors.reset);
console.log('─'.repeat(60));
testResults.performance.benchmarks.forEach(bench => {
const status = bench.passed ? colors.green + '✓' : colors.red + '✗';
console.log(` ${status} ${bench.name.padEnd(25)} ${bench.avgTime}ms${colors.reset}`);
});
}
// Coverage
const coverage = analyzeCoverage();
// Error summary
const allErrors = [
...testResults.unit.errors,
...testResults.integration.errors,
...testResults.e2e.errors,
...testResults.performance.errors,
...testResults.security.errors
];
if (allErrors.length > 0 && verbose) {
console.log('\n' + colors.bright + 'Error Details:' + colors.reset);
console.log('─'.repeat(60));
allErrors.slice(0, 10).forEach(error => {
log(` • ${error}`, 'red');
});
if (allErrors.length > 10) {
log(` ... and ${allErrors.length - 10} more errors`, 'dim');
}
}
// Final status
console.log('\n' + '='.repeat(60));
const allPassed = totalFailed === 0;
const statusColor = allPassed ? 'green' : 'red';
const statusSymbol = allPassed ? '✓' : '✗';
log(
`${statusSymbol} Test Suite ${allPassed ? 'PASSED' : 'FAILED'} - ` +
`${totalPassed}/${grandTotal} tests passed (${overallPassRate}%) in ${totalTime}s`,
statusColor
);
console.log('='.repeat(60) + '\n');
// Write JSON report
const report = {
timestamp: new Date().toISOString(),
duration: parseFloat(totalTime),
summary: {
total: grandTotal,
passed: totalPassed,
failed: totalFailed,
skipped: totalSkipped,
passRate: parseFloat(overallPassRate)
},
categories: testResults,
coverage: coverage,
errors: allErrors
};
fs.writeFileSync(
path.join(__dirname, 'test-results.json'),
JSON.stringify(report, null, 2)
);
log('Report saved to: test-results.json', 'dim');
return allPassed ? 0 : 1;
}
// ============================================
// MAIN EXECUTION
// ============================================
async function main() {
console.clear();
log('╔═══════════════════════════════════════════════════════════════╗', 'bright');
log('║ LUXVAULT COMPREHENSIVE TEST SUITE v2.0 ║', 'bright');
log('╠═══════════════════════════════════════════════════════════════╣', 'bright');
log(`║ Target: ${BASE_URL.padEnd(52)} ║`, 'bright');
log(`║ Category: ${targetCategory.padEnd(50)} ║`, 'bright');
log('╚═══════════════════════════════════════════════════════════════╝', 'bright');
try {
// Check server availability
log('\nChecking server availability...', 'cyan');
const health = await makeRequest({ path: '/health' });
if (health.status !== 200) {
log('Server is not responding correctly!', 'red');
process.exit(1);
}
log('✓ Server is online and healthy\n', 'green');
// Run test suites
await runUnitTests();
await runIntegrationTests();
await runE2ETests();
await runPerformanceTests();
await runSecurityTests();
// Generate and display report
const exitCode = generateReport();
process.exit(exitCode);
} catch (error) {
log(`\nFatal error: ${error.message}`, 'red');
if (verbose) {
console.error(error.stack);
}
process.exit(1);
}
}
// Run the test suite
main();