← 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();