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