#!/usr/bin/env python3 """ ThrillWiki Mobile Authentication Button Testing Tests the mobile Sign In and Join buttons functionality """ import asyncio import sys import os from playwright.async_api import async_playwright, expect import time class MobileAuthTester: def __init__(self): self.base_url = "http://localhost:5000" self.test_results = [] self.issues_found = [] def log_test_result(self, test_name, status, details=""): """Log test result and print to console""" result = { "test": test_name, "status": status, # "PASS", "FAIL", "SKIP" "details": details } self.test_results.append(result) status_emoji = "āœ…" if status == "PASS" else "āŒ" if status == "FAIL" else "āš ļø" print(f"{status_emoji} {test_name}: {status}") if details: print(f" Details: {details}") if status == "FAIL": self.issues_found.append(f"{test_name}: {details}") async def test_mobile_auth_buttons(self): """Main test function for mobile authentication buttons""" print("šŸš€ Starting ThrillWiki Mobile Authentication Tests\n") print("=" * 60) async with async_playwright() as p: # Launch browser in mobile mode browser = await p.chromium.launch(headless=False, slow_mo=500) # Create mobile context (iPhone 12 viewport) context = await browser.new_context( viewport={'width': 390, 'height': 844}, user_agent='Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1' ) page = await context.new_page() try: # Test 1: Navigate to homepage await self.test_homepage_navigation(page) # Test 2: Locate mobile authentication buttons await self.test_locate_mobile_buttons(page) # Test 3: Test Sign In button functionality await self.test_sign_in_button(page) # Test 4: Test Join button functionality await self.test_join_button(page) # Test 5: Test modal close functionality await self.test_modal_close_functionality(page) # Test 6: Verify button sizing and touch-friendliness await self.test_button_sizing_and_touch_friendliness(page) except Exception as e: self.log_test_result("OVERALL_TEST", "FAIL", f"Unexpected error: {str(e)}") finally: await browser.close() # Print final results self.print_final_results() async def test_homepage_navigation(self, page): """Test 1: Navigate to ThrillWiki homepage on mobile""" try: print("\n1ļøāƒ£ Testing homepage navigation...") await page.goto(self.base_url, wait_until="networkidle") # Wait for page to fully load await page.wait_for_selector('header', timeout=10000) # Check if we're on the homepage title = await page.title() if "ThrillWiki" in title: self.log_test_result("Homepage Navigation", "PASS", f"Successfully loaded: {title}") else: self.log_test_result("Homepage Navigation", "FAIL", f"Unexpected title: {title}") except Exception as e: self.log_test_result("Homepage Navigation", "FAIL", str(e)) async def test_locate_mobile_buttons(self, page): """Test 2: Locate mobile Sign In and Join buttons in header""" try: print("\n2ļøāƒ£ Locating mobile authentication buttons...") # Check for mobile section (should be visible on mobile viewport) mobile_section = page.locator('.md\\:hidden') await expect(mobile_section).to_be_visible() # Look for Sign In button specifically in mobile section sign_in_button = page.locator('.md\\:hidden button:has-text("Sign In")') join_button = page.locator('.md\\:hidden button:has-text("Join")') # Check if buttons exist and are visible sign_in_visible = await sign_in_button.is_visible() join_visible = await join_button.is_visible() if sign_in_visible and join_visible: self.log_test_result("Locate Mobile Buttons", "PASS", "Both Sign In and Join buttons found in mobile header") else: missing = [] if not sign_in_visible: missing.append("Sign In") if not join_visible: missing.append("Join") self.log_test_result("Locate Mobile Buttons", "FAIL", f"Missing buttons: {', '.join(missing)}") except Exception as e: self.log_test_result("Locate Mobile Buttons", "FAIL", str(e)) async def test_sign_in_button(self, page): """Test 3: Test Sign In button functionality""" try: print("\n3ļøāƒ£ Testing Sign In button functionality...") # Find the Sign In button in mobile section sign_in_button = page.locator('.md\\:hidden button:has-text("Sign In")') await expect(sign_in_button).to_be_visible() # Click the Sign In button await sign_in_button.click() # Wait for authentication modal to appear auth_modal = page.locator('[x-data*="authModal"]') await expect(auth_modal).to_be_visible(timeout=5000) # Check if login form is displayed (should show "Sign In" heading) login_heading = page.locator('h2:has-text("Sign In")') await expect(login_heading).to_be_visible() # Check for login form elements username_field = page.locator('input[type="text"], input[type="email"]').first password_field = page.locator('input[type="password"]').first username_visible = await username_field.is_visible() password_visible = await password_field.is_visible() if username_visible and password_visible: self.log_test_result("Sign In Button Functionality", "PASS", "Sign In button opens modal with login form") else: self.log_test_result("Sign In Button Functionality", "FAIL", "Login form elements not found in modal") except Exception as e: self.log_test_result("Sign In Button Functionality", "FAIL", str(e)) async def test_join_button(self, page): """Test 4: Test Join button functionality""" try: print("\n4ļøāƒ£ Testing Join button functionality...") # First, close any open modal by clicking overlay or escape try: overlay = page.locator('.fixed.inset-0.bg-background\\/80') if await overlay.is_visible(): await overlay.click() await page.wait_for_timeout(500) except: pass # Find the Join button in mobile section join_button = page.locator('.md\\:hidden button:has-text("Join")') await expect(join_button).to_be_visible() # Click the Join button await join_button.click() # Wait for authentication modal to appear auth_modal = page.locator('[x-data*="authModal"]') await expect(auth_modal).to_be_visible(timeout=5000) # Check if registration form is displayed (should show "Create Account" or "Sign Up" heading) register_heading = page.locator('h2:has-text("Create Account"), h2:has-text("Sign Up")') await expect(register_heading).to_be_visible() # Check for registration form elements first_name_field = page.locator('input[id*="first"], input[placeholder*="first" i]') email_field = page.locator('input[type="email"]') first_name_visible = await first_name_field.is_visible() email_visible = await email_field.is_visible() if first_name_visible and email_visible: self.log_test_result("Join Button Functionality", "PASS", "Join button opens modal with registration form") else: self.log_test_result("Join Button Functionality", "FAIL", "Registration form elements not found in modal") except Exception as e: self.log_test_result("Join Button Functionality", "FAIL", str(e)) async def test_modal_close_functionality(self, page): """Test 5: Test modal close functionality""" try: print("\n5ļøāƒ£ Testing modal close functionality...") # Ensure modal is open (click Join button if needed) auth_modal = page.locator('[x-data*="authModal"]') if not await auth_modal.is_visible(): join_button = page.locator('.md\\:hidden button:has-text("Join")') await join_button.click() await expect(auth_modal).to_be_visible(timeout=5000) # Test close button close_button = page.locator('button:has(i.fa-times), button[aria-label*="close" i]') if await close_button.is_visible(): await close_button.click() await expect(auth_modal).to_be_hidden(timeout=3000) self.log_test_result("Modal Close Button", "PASS", "Close button successfully closes modal") else: self.log_test_result("Modal Close Button", "FAIL", "Close button not found") return # Test escape key functionality join_button = page.locator('.md\\:hidden button:has-text("Join")') await join_button.click() await expect(auth_modal).to_be_visible(timeout=5000) await page.keyboard.press('Escape') await expect(auth_modal).to_be_hidden(timeout=3000) self.log_test_result("Modal Escape Key", "PASS", "Escape key successfully closes modal") except Exception as e: self.log_test_result("Modal Close Functionality", "FAIL", str(e)) async def test_button_sizing_and_touch_friendliness(self, page): """Test 6: Verify button sizing and touch-friendliness""" try: print("\n6ļøāƒ£ Testing button sizing and touch-friendliness...") # Get Sign In and Join buttons sign_in_button = page.locator('.md\\:hidden button:has-text("Sign In")') join_button = page.locator('.md\\:hidden button:has-text("Join")') # Check button dimensions (should be at least 44px for touch-friendliness) sign_in_box = await sign_in_button.bounding_box() join_box = await join_button.bounding_box() touch_friendly_issues = [] # Check Sign In button dimensions if sign_in_box: if sign_in_box['height'] < 44: touch_friendly_issues.append(f"Sign In button height ({sign_in_box['height']}px) below 44px minimum") if sign_in_box['width'] < 44: touch_friendly_issues.append(f"Sign In button width ({sign_in_box['width']}px) below 44px minimum") else: touch_friendly_issues.append("Could not measure Sign In button dimensions") # Check Join button dimensions if join_box: if join_box['height'] < 44: touch_friendly_issues.append(f"Join button height ({join_box['height']}px) below 44px minimum") if join_box['width'] < 44: touch_friendly_issues.append(f"Join button width ({join_box['width']}px) below 44px minimum") else: touch_friendly_issues.append("Could not measure Join button dimensions") if touch_friendly_issues: self.log_test_result("Button Touch-Friendliness", "FAIL", "; ".join(touch_friendly_issues)) else: sign_in_size = f"{sign_in_box['width']:.0f}x{sign_in_box['height']:.0f}px" if sign_in_box else "N/A" join_size = f"{join_box['width']:.0f}x{join_box['height']:.0f}px" if join_box else "N/A" self.log_test_result("Button Touch-Friendliness", "PASS", f"Buttons are touch-friendly - Sign In: {sign_in_size}, Join: {join_size}") except Exception as e: self.log_test_result("Button Touch-Friendliness", "FAIL", str(e)) def print_final_results(self): """Print comprehensive test results""" print("\n" + "=" * 60) print("šŸ“Š FINAL TEST RESULTS") print("=" * 60) passed = sum(1 for result in self.test_results if result["status"] == "PASS") failed = sum(1 for result in self.test_results if result["status"] == "FAIL") total = len(self.test_results) print(f"\nTotal Tests: {total}") print(f"āœ… Passed: {passed}") print(f"āŒ Failed: {failed}") print(f"Success Rate: {(passed/total)*100:.1f}%") if self.issues_found: print(f"\nšŸ› ISSUES FOUND ({len(self.issues_found)}):") for i, issue in enumerate(self.issues_found, 1): print(f" {i}. {issue}") else: print("\nšŸŽ‰ No issues found! All mobile authentication functionality is working correctly.") print("\n" + "=" * 60) async def main(): """Main entry point""" tester = MobileAuthTester() await tester.test_mobile_auth_buttons() if __name__ == "__main__": asyncio.run(main())