← back to Dear Bubbe Nextjs

archived/tests/test-mobile-audio-fixes.js

311 lines

const puppeteer = require('puppeteer');
const fs = require('fs');

async function testMobileAudioFixes() {
  console.log('📱 TESTING MOBILE AUDIO FIXES');
  console.log('==============================\n');
  
  const browser = await puppeteer.launch({
    headless: true,
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--use-fake-ui-for-media-stream',
      '--use-fake-device-for-media-stream',
      '--allow-running-insecure-content',
      '--autoplay-policy=no-user-gesture-required',  // Allow autoplay for testing
      '--disable-web-security',
      '--disable-features=VizDisplayCompositor'
    ]
  });

  const results = {
    timestamp: new Date().toISOString(),
    overall: 'PASS',
    tests: [],
    issues: [],
    fixes_verified: []
  };

  try {
    // Test on mobile devices
    const mobileDevices = [
      {
        name: 'iPhone 12 Pro',
        viewport: { width: 390, height: 844, isMobile: true },
        userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1'
      },
      {
        name: 'Samsung Galaxy S21',
        viewport: { width: 360, height: 800, isMobile: true },
        userAgent: 'Mozilla/5.0 (Linux; Android 11; SM-G991B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36'
      }
    ];

    for (const device of mobileDevices) {
      console.log(`🔍 Testing ${device.name}...`);
      
      const page = await browser.newPage();
      await page.setViewport(device.viewport);
      await page.setUserAgent(device.userAgent);

      // Enable console logging
      page.on('console', msg => {
        if (msg.type() === 'log' && msg.text().includes('[VoiceManager]')) {
          console.log(`  📱 ${device.name}: ${msg.text()}`);
        }
      });

      await page.goto('http://localhost:3011', {
        waitUntil: 'networkidle0',
        timeout: 30000
      });

      // Wait for page to initialize
      await page.waitForTimeout(2000);

      // Test 1: Check if VoiceManager component loaded
      const voiceManagerExists = await page.evaluate(() => {
        return document.querySelector('.voice-manager') !== null;
      });

      results.tests.push({
        device: device.name,
        test: 'VoiceManager Component Loaded',
        result: voiceManagerExists ? 'PASS' : 'FAIL',
        details: voiceManagerExists ? 'Component found in DOM' : 'Component not found'
      });

      // Test 2: Check AudioContext support
      const audioContextSupport = await page.evaluate(() => {
        return !!(window.AudioContext || window.webkitAudioContext);
      });

      results.tests.push({
        device: device.name,
        test: 'AudioContext Support',
        result: audioContextSupport ? 'PASS' : 'FAIL',
        details: audioContextSupport ? 'AudioContext available' : 'AudioContext not supported'
      });

      // Test 3: Check Speech Recognition support
      const speechRecognitionSupport = await page.evaluate(() => {
        return !!(window.SpeechRecognition || window.webkitSpeechRecognition);
      });

      results.tests.push({
        device: device.name,
        test: 'Speech Recognition Support',
        result: speechRecognitionSupport ? 'PASS' : 'FAIL',
        details: speechRecognitionSupport ? 'SpeechRecognition API available' : 'SpeechRecognition not supported'
      });

      // Test 4: Check getUserMedia support
      const getUserMediaSupport = await page.evaluate(() => {
        return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia);
      });

      results.tests.push({
        device: device.name,
        test: 'getUserMedia Support',
        result: getUserMediaSupport ? 'PASS' : 'FAIL',
        details: getUserMediaSupport ? 'Media devices API available' : 'Media devices API not supported'
      });

      // Test 5: Check mobile overlay appears (should show for autoplay block)
      const overlayVisible = await page.evaluate(() => {
        const overlay = document.querySelector('[class*="fixed inset-0"]');
        return overlay && window.getComputedStyle(overlay).display !== 'none';
      });

      results.tests.push({
        device: device.name,
        test: 'Mobile Start Overlay',
        result: overlayVisible ? 'PASS' : 'FAIL',
        details: overlayVisible ? 'Overlay shown for user interaction' : 'No overlay found'
      });

      // Test 6: Simulate user tap to unlock audio
      if (overlayVisible) {
        console.log(`  📱 ${device.name}: Simulating user tap to unlock audio...`);
        
        await page.click('body');
        await page.waitForTimeout(1000);
        
        // Check if overlay disappeared
        const overlayHidden = await page.evaluate(() => {
          const overlay = document.querySelector('[class*="fixed inset-0"]');
          return !overlay || window.getComputedStyle(overlay).display === 'none';
        });

        results.tests.push({
          device: device.name,
          test: 'Audio Unlock on Tap',
          result: overlayHidden ? 'PASS' : 'FAIL',
          details: overlayHidden ? 'Overlay hidden after tap, audio unlocked' : 'Overlay still visible after tap'
        });

        if (overlayHidden) {
          results.fixes_verified.push(`${device.name}: Mobile audio unlock working`);
        }
      }

      // Test 7: Check Test Voice button functionality
      const testVoiceButton = await page.$('button:has-text("Test Voice")');
      if (testVoiceButton) {
        console.log(`  📱 ${device.name}: Testing voice button...`);
        
        await testVoiceButton.click();
        await page.waitForTimeout(2000);
        
        // Check if any audio element was created
        const audioElementExists = await page.evaluate(() => {
          return document.querySelectorAll('audio').length > 0;
        });

        results.tests.push({
          device: device.name,
          test: 'Test Voice Button',
          result: audioElementExists ? 'PASS' : 'FAIL',
          details: audioElementExists ? 'Audio element created on button click' : 'No audio element found after click'
        });

        if (audioElementExists) {
          results.fixes_verified.push(`${device.name}: Test Voice button working`);
        }
      }

      // Test 8: Check mobile-specific audio attributes
      const mobileAudioOptimization = await page.evaluate(() => {
        const audioElements = document.querySelectorAll('audio');
        if (audioElements.length === 0) return false;
        
        const audio = audioElements[0];
        return audio.hasAttribute('playsinline') || audio.hasAttribute('webkit-playsinline');
      });

      results.tests.push({
        device: device.name,
        test: 'Mobile Audio Optimization',
        result: mobileAudioOptimization ? 'PASS' : 'FAIL',
        details: mobileAudioOptimization ? 'playsinline attribute detected' : 'Mobile audio attributes missing'
      });

      if (mobileAudioOptimization) {
        results.fixes_verified.push(`${device.name}: Mobile audio attributes applied`);
      }

      // Test 9: Check viewport scaling
      const viewportCorrect = await page.evaluate(() => {
        const viewport = document.querySelector('meta[name="viewport"]');
        return viewport && viewport.getAttribute('content').includes('width=device-width');
      });

      results.tests.push({
        device: device.name,
        test: 'Mobile Viewport',
        result: viewportCorrect ? 'PASS' : 'FAIL',
        details: viewportCorrect ? 'Viewport meta tag configured correctly' : 'Viewport meta tag missing or incorrect'
      });

      // Test 10: Check touch target sizes (buttons should be 44px+ on mobile)
      const touchTargetSizes = await page.evaluate(() => {
        const buttons = document.querySelectorAll('button');
        let adequateTargets = 0;
        
        buttons.forEach(button => {
          const rect = button.getBoundingClientRect();
          if (rect.width >= 44 && rect.height >= 44) {
            adequateTargets++;
          }
        });
        
        return {
          total: buttons.length,
          adequate: adequateTargets,
          percentage: buttons.length > 0 ? Math.round((adequateTargets / buttons.length) * 100) : 0
        };
      });

      results.tests.push({
        device: device.name,
        test: 'Touch Target Sizes',
        result: touchTargetSizes.percentage >= 80 ? 'PASS' : 'FAIL',
        details: `${touchTargetSizes.adequate}/${touchTargetSizes.total} buttons (${touchTargetSizes.percentage}%) meet 44px minimum`
      });

      await page.close();
    }

    // Generate summary
    const totalTests = results.tests.length;
    const passedTests = results.tests.filter(t => t.result === 'PASS').length;
    const overallScore = Math.round((passedTests / totalTests) * 100);

    if (overallScore < 80) {
      results.overall = 'FAIL';
      results.issues.push(`Overall score too low: ${overallScore}%`);
    }

    console.log('\n📊 MOBILE AUDIO FIXES TEST RESULTS');
    console.log('==================================');

    // Group by device
    const deviceResults = {};
    results.tests.forEach(test => {
      if (!deviceResults[test.device]) {
        deviceResults[test.device] = { passed: 0, total: 0, tests: [] };
      }
      deviceResults[test.device].tests.push(test);
      deviceResults[test.device].total++;
      if (test.result === 'PASS') deviceResults[test.device].passed++;
    });

    Object.keys(deviceResults).forEach(device => {
      const deviceData = deviceResults[device];
      const deviceScore = Math.round((deviceData.passed / deviceData.total) * 100);
      
      console.log(`\n📱 ${device}: ${deviceScore}% (${deviceData.passed}/${deviceData.total})`);
      
      deviceData.tests.forEach(test => {
        const emoji = test.result === 'PASS' ? '✅' : '❌';
        console.log(`  ${emoji} ${test.test}: ${test.result}`);
        if (test.result === 'FAIL') {
          console.log(`     ${test.details}`);
        }
      });
    });

    console.log(`\n🎯 OVERALL: ${results.overall} (${passedTests}/${totalTests} tests passed - ${overallScore}%)`);

    if (results.fixes_verified.length > 0) {
      console.log('\n✅ FIXES VERIFIED:');
      results.fixes_verified.forEach(fix => console.log(`  ✓ ${fix}`));
    }

    if (results.issues.length > 0) {
      console.log('\n❌ ISSUES:');
      results.issues.forEach(issue => console.log(`  ✗ ${issue}`));
    }

  } catch (error) {
    console.error('❌ Test failed:', error);
    results.overall = 'FAIL';
    results.issues.push(`Test framework error: ${error.message}`);
  } finally {
    await browser.close();
  }

  // Save detailed results
  fs.writeFileSync('mobile-audio-fixes-test-results.json', JSON.stringify(results, null, 2));
  console.log('\n📄 Detailed results saved to mobile-audio-fixes-test-results.json');

  return results;
}

// Run if called directly
if (require.main === module) {
  testMobileAudioFixes().catch(console.error);
}

module.exports = testMobileAudioFixes;