← back to Dear Bubbe Nextjs
archived/tests/mobile-test-quick.js
289 lines
/**
* Quick Mobile Test for Dear Bubbe
* Focused on core functionality verification
*/
const puppeteer = require('puppeteer');
const TEST_URL = 'http://45.61.58.125:3011';
async function runQuickMobileTest() {
console.log('🚀 Dear Bubbe Quick Mobile Test');
console.log('=' .repeat(50));
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const results = {
passed: 0,
failed: 0,
tests: []
};
function log(test, status, details = '') {
const icon = status === 'PASS' ? '✅' : '❌';
console.log(`${icon} ${test}: ${status}`);
if (details) console.log(` ${details}`);
results.tests.push({ test, status, details });
if (status === 'PASS') results.passed++;
else results.failed++;
}
try {
const page = await browser.newPage();
// Set iPhone 12 viewport
await page.setViewport({ width: 390, height: 844 });
await page.setUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X)');
console.log('\n📱 Testing iPhone 12 Experience');
console.log('-'.repeat(50));
// Navigate to site
await page.goto(TEST_URL, { waitUntil: 'networkidle2' });
// Test 1: Page loads
const title = await page.title();
if (title) {
log('Page Load', 'PASS', `Title: ${title}`);
} else {
log('Page Load', 'FAIL', 'No title found');
}
// Test 2: Check for Bubbe's initial message
await new Promise(r => setTimeout(r, 5000)) // Give more time for API call;
const bubbeMessages = await page.evaluate(() => {
// Look for Bubbe messages - they have white background with border
const messages = document.querySelectorAll('.bg-white.border-gray-200, .rounded-2xl');
return Array.from(messages).map(el => el.textContent).filter(t => t && t.length > 10);
});
if (bubbeMessages.length > 0) {
log('Auto-start Voice', 'PASS', `Found ${bubbeMessages.length} Bubbe messages`);
console.log(` First message: "${bubbeMessages[0].substring(0, 50)}..."`);
// Check for invasive questions
const hasQuestion = bubbeMessages.some(msg => msg.includes('?'));
if (hasQuestion) {
log('Invasive Questions', 'PASS', 'Bubbe asks questions');
} else {
log('Invasive Questions', 'FAIL', 'No questions found');
}
} else {
log('Auto-start Voice', 'FAIL', 'No Bubbe messages found');
}
// Test 3: Check input field exists
const inputField = await page.$('textarea, input[type="text"]');
if (inputField) {
log('Input Field', 'PASS', 'Chat input available');
// Test sending a message
await inputField.type('Hello Bubbe!');
await page.keyboard.press('Enter');
await new Promise(r => setTimeout(r, 5000)); // Wait longer for response
const newMessages = await page.evaluate(() => {
// Count all message divs with rounded corners (both user and Bubbe)
const messages = document.querySelectorAll('.rounded-2xl');
return Array.from(messages).filter(el => el.textContent && el.textContent.length > 5).length;
});
// Should have at least 2 more messages (user message + Bubbe response)
if (newMessages >= bubbeMessages.length + 2) {
log('Message Response', 'PASS', `Bubbe responded (${newMessages} total messages)`);
} else {
log('Message Response', 'FAIL', `No new response (${newMessages} messages)`);
}
} else {
log('Input Field', 'FAIL', 'No input field found');
}
// Test 4: Check for share button
const shareButton = await page.evaluate(() => {
// Look for share icon or button
const buttons = Array.from(document.querySelectorAll('button'));
const shareBtn = buttons.find(btn => {
const text = btn.textContent?.toLowerCase() || '';
const ariaLabel = btn.getAttribute('aria-label')?.toLowerCase() || '';
return text.includes('share') || ariaLabel.includes('share');
});
if (shareBtn) return true;
// Check for share SVG icon
const svgs = document.querySelectorAll('svg');
return Array.from(svgs).some(svg => {
const parent = svg.closest('button');
return parent !== null;
});
});
if (shareButton) {
log('Share Button', 'PASS', 'Share functionality present');
} else {
log('Share Button', 'FAIL', 'No share button found');
}
// Test 5: Check mobile viewport meta
const viewportMeta = await page.evaluate(() => {
const meta = document.querySelector('meta[name="viewport"]');
return meta?.getAttribute('content');
});
if (viewportMeta && viewportMeta.includes('width=device-width')) {
log('Mobile Viewport', 'PASS', viewportMeta);
} else {
log('Mobile Viewport', 'FAIL', 'Missing proper viewport meta');
}
// Test 6: Check for TALK button (should NOT be visible after Bubbe speaks)
const talkButtonVisible = await page.evaluate(() => {
const buttons = Array.from(document.querySelectorAll('button'));
const talkBtn = buttons.find(btn => btn.textContent === 'TALK');
return talkBtn && window.getComputedStyle(talkBtn).display !== 'none';
});
if (!talkButtonVisible) {
log('No TALK Button Bug', 'PASS', 'TALK button correctly hidden');
} else {
log('No TALK Button Bug', 'FAIL', 'TALK button showing incorrectly');
}
// Test 7: Check response length (mobile optimized)
const lastBubbeMessage = bubbeMessages[bubbeMessages.length - 1] || '';
if (lastBubbeMessage.length <= 320) {
log('Mobile Message Length', 'PASS', `${lastBubbeMessage.length} chars`);
} else {
log('Mobile Message Length', 'FAIL', `Too long: ${lastBubbeMessage.length} chars`);
}
// Test 8: Check for console errors
const errors = [];
page.on('console', msg => {
if (msg.type() === 'error') {
errors.push(msg.text());
}
});
await page.reload();
await new Promise(r => setTimeout(r, 2000));
if (errors.length === 0) {
log('No Console Errors', 'PASS', 'Clean console');
} else {
log('No Console Errors', 'FAIL', `${errors.length} errors found`);
errors.slice(0, 3).forEach(err => console.log(` Error: ${err.substring(0, 100)}`));
}
// Test 9: Test landscape mode - simplified test
await page.setViewport({ width: 844, height: 390 });
await new Promise(r => setTimeout(r, 2000)); // Give more time for reflow
const landscapeWorks = await page.evaluate(() => {
// Simple test - just check if critical elements are still accessible
const input = document.querySelector('textarea, input[type="text"]');
const messages = document.querySelectorAll('.rounded-2xl');
// As long as we can still see messages and input, it's functional
return input && messages.length > 0;
});
if (landscapeWorks) {
log('Landscape Mode', 'PASS', 'Core functionality maintained in landscape');
} else {
log('Landscape Mode', 'FAIL', 'Critical elements not accessible in landscape');
}
// Test 10: Check for profile/login options
const profileOptions = await page.evaluate(() => {
const buttons = Array.from(document.querySelectorAll('button'));
return buttons.some(btn => {
const text = btn.textContent?.toLowerCase() || '';
return text.includes('profile') || text.includes('sign') || text.includes('log');
});
});
if (profileOptions) {
log('Profile/Login Access', 'PASS', 'User account options available');
} else {
log('Profile/Login Access', 'FAIL', 'No profile options found');
}
// Take final screenshot
await page.setViewport({ width: 390, height: 844 }); // Back to portrait
await page.screenshot({
path: `/root/Projects/dear-bubbe-nextjs/test-screenshots/mobile-quick-test-${Date.now()}.png`,
fullPage: false
});
} catch (error) {
console.error('Fatal error:', error.message);
} finally {
await browser.close();
}
// Print summary
console.log('\n' + '='.repeat(50));
console.log('📊 TEST SUMMARY');
console.log('='.repeat(50));
console.log(`✅ Passed: ${results.passed}`);
console.log(`❌ Failed: ${results.failed}`);
console.log(`📈 Success Rate: ${Math.round((results.passed / (results.passed + results.failed)) * 100)}%`);
// Print recommendations
console.log('\n💡 RECOMMENDATIONS:');
const recommendations = [];
results.tests.forEach(test => {
if (test.status === 'FAIL') {
switch(test.test) {
case 'Auto-start Voice':
recommendations.push('• Fix auto-start: Bubbe should greet immediately on load');
break;
case 'Share Button':
recommendations.push('• Add share button: Users need to share funny responses');
break;
case 'No TALK Button Bug':
recommendations.push('• Fix TALK button: Should not appear after Bubbe speaks');
break;
case 'Message Response':
recommendations.push('• Fix chat flow: Ensure messages get responses');
break;
case 'Mobile Message Length':
recommendations.push('• Shorten responses: Keep under 320 chars for mobile');
break;
case 'No Console Errors':
recommendations.push('• Fix JavaScript errors: Check console for issues');
break;
case 'Invasive Questions':
recommendations.push('• Add invasive questions: Bubbe must be nosy!');
break;
}
}
});
if (recommendations.length > 0) {
recommendations.forEach(rec => console.log(rec));
} else {
console.log('✅ All tests passed! Mobile experience is working well.');
}
return results.failed === 0 ? 0 : 1;
}
// Run the test
runQuickMobileTest()
.then(exitCode => {
console.log('\n✅ Quick mobile test completed!');
process.exit(exitCode);
})
.catch(error => {
console.error('Test failed:', error);
process.exit(1);
});