mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 07:11:08 -05:00
Refactor the mobile authentication button handling by removing a global event listener and implementing a direct component interaction method. This ensures the auth modal can be opened correctly from mobile buttons. Additional tests and documentation have been added to verify and explain the functionality. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 495199c6-aa06-48cd-8c40-9cccf398cfcf Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/d6d61dac-164d-45dd-929f-7dcdfd771b64/495199c6-aa06-48cd-8c40-9cccf398cfcf/IQPlVNL
317 lines
14 KiB
Python
317 lines
14 KiB
Python
#!/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()) |