voiceCal-ai-v3 / unit_tests /test_chat_widget.py
pgits's picture
TESTS: Organize tests into unit_tests directory with runner
1e041ce
#!/usr/bin/env python3
"""
Playwright test script to verify the chat widget at http://localhost:8000/chat-widget
Tests: page loading, JavaScript errors, CSS formatting, UI elements, chat functionality
"""
import asyncio
import sys
from playwright.async_api import async_playwright
import json
from datetime import datetime
async def test_chat_widget():
"""Comprehensive test of the chat widget interface"""
async with async_playwright() as p:
# Launch browser in headed mode so we can see what's happening
browser = await p.chromium.launch(headless=False, slow_mo=1000)
context = await browser.new_context(
viewport={'width': 1280, 'height': 720}
)
# Enable console logging to capture JavaScript errors
page = await context.new_page()
console_messages = []
errors = []
def handle_console(msg):
console_messages.append({
'type': msg.type,
'text': msg.text,
'location': msg.location
})
print(f"Console {msg.type}: {msg.text}")
def handle_page_error(error):
errors.append(str(error))
print(f"Page Error: {error}")
def handle_response(response):
if response.status >= 400:
print(f"HTTP Error: {response.status} - {response.url}")
page.on('console', handle_console)
page.on('pageerror', handle_page_error)
page.on('response', handle_response)
try:
print("πŸš€ Starting chat widget test...")
# Test 1: Page Loading
print("\nπŸ“„ Test 1: Loading page at http://localhost:8000/chat-widget")
try:
response = await page.goto('http://localhost:8000/chat-widget', wait_until='networkidle')
print(f"βœ… Page loaded with status: {response.status}")
if response.status != 200:
print(f"❌ Unexpected status code: {response.status}")
return False
except Exception as e:
print(f"❌ Failed to load page: {e}")
return False
# Wait for page to fully load
await page.wait_for_load_state('domcontentloaded')
await asyncio.sleep(2) # Give time for any async loading
# Test 2: JavaScript Errors
print("\nπŸ› Test 2: Checking for JavaScript errors")
js_errors = [msg for msg in console_messages if msg['type'] == 'error']
# Filter out 404 errors that might be for optional resources
critical_js_errors = []
resource_404_errors = []
for error in js_errors:
if "Failed to load resource" in error['text'] and "404" in error['text']:
resource_404_errors.append(error)
else:
critical_js_errors.append(error)
if critical_js_errors:
print(f"❌ Found {len(critical_js_errors)} critical JavaScript errors:")
for error in critical_js_errors:
print(f" - {error['text']}")
return False
else:
print("βœ… No critical JavaScript errors found")
if resource_404_errors:
print(f"⚠️ Found {len(resource_404_errors)} resource 404 errors (may be non-critical):")
for error in resource_404_errors:
print(f" - {error['text']}")
if errors:
print(f"❌ Found {len(errors)} page errors:")
for error in errors:
print(f" - {error}")
return False
else:
print("βœ… No page errors found")
# Test 3: CSS and Layout Check
print("\n🎨 Test 3: Checking CSS formatting and layout")
# Check if main container exists and is visible
main_container = page.locator('#chat-widget, .chat-container, .chat-widget')
if await main_container.count() > 0:
print("βœ… Main chat container found")
# Check if container is visible
if await main_container.first.is_visible():
print("βœ… Main container is visible")
else:
print("❌ Main container is not visible")
return False
else:
print("❌ Main chat container not found")
return False
# Test 4: UI Elements Visibility and Positioning
print("\nπŸ” Test 4: Checking UI elements visibility and positioning")
# Check for common chat widget elements
elements_to_check = [
{'selector': 'input[type="text"], textarea, .message-input', 'name': 'Message input field'},
{'selector': 'button[type="submit"], .send-button, .submit-button', 'name': 'Send button'},
{'selector': '.chat-messages, .messages-container, .conversation', 'name': 'Messages container'},
]
all_elements_found = True
for element in elements_to_check:
locator = page.locator(element['selector'])
count = await locator.count()
if count > 0:
is_visible = await locator.first.is_visible()
print(f"βœ… {element['name']}: Found ({count}) and {'visible' if is_visible else 'hidden'}")
if not is_visible:
all_elements_found = False
else:
print(f"❌ {element['name']}: Not found")
all_elements_found = False
if not all_elements_found:
print("⚠️ Some UI elements missing or hidden, but continuing with tests...")
# Test 5: Chat Interface Functionality
print("\nπŸ’¬ Test 5: Testing chat interface functionality")
# Try to find and interact with the input field
input_field = page.locator('input[type="text"], textarea, .message-input').first
send_button = page.locator('button[type="submit"], .send-button, .submit-button').first
if await input_field.count() > 0 and await send_button.count() > 0:
print("βœ… Found input field and send button")
try:
# Test typing in the input field
await input_field.fill("Hello, this is a test message")
print("βœ… Successfully typed in input field")
# Test clicking send button
await send_button.click()
print("βœ… Successfully clicked send button")
# Wait a moment for any response
await asyncio.sleep(3)
except Exception as e:
print(f"⚠️ Chat interaction failed: {e}")
else:
print("⚠️ Could not find input field or send button for interaction test")
# Test 6: Take Screenshot
print("\nπŸ“Έ Test 6: Taking screenshot for visual confirmation")
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
screenshot_path = f"/Users/petergits/dev/voiceCal-ai-v1/chat_widget_test_{timestamp}.png"
await page.screenshot(path=screenshot_path, full_page=True)
print(f"βœ… Screenshot saved to: {screenshot_path}")
# Additional checks for common CSS issues
print("\nπŸ”§ Additional CSS and Layout Checks:")
# Check page title
title = await page.title()
print(f"πŸ“„ Page title: {title}")
# Check body background and basic styling
body_styles = await page.evaluate("""
() => {
const body = document.body;
const computedStyles = window.getComputedStyle(body);
return {
backgroundColor: computedStyles.backgroundColor,
fontFamily: computedStyles.fontFamily,
margin: computedStyles.margin,
padding: computedStyles.padding
};
}
""")
print(f"🎨 Body styles: {json.dumps(body_styles, indent=2)}")
# Check if any CSS files failed to load
css_errors = [msg for msg in console_messages if 'css' in msg['text'].lower() or 'stylesheet' in msg['text'].lower()]
if css_errors:
print(f"⚠️ Found potential CSS loading issues:")
for error in css_errors:
print(f" - {error['text']}")
else:
print("βœ… No CSS loading errors detected")
print("\nπŸŽ‰ Test completed successfully!")
print(f"πŸ“Š Summary:")
print(f" - Console messages: {len(console_messages)}")
print(f" - JavaScript errors: {len(js_errors)}")
print(f" - Page errors: {len(errors)}")
print(f" - Screenshot saved: {screenshot_path}")
return True
except Exception as e:
print(f"❌ Test failed with exception: {e}")
return False
finally:
# Keep browser open for a moment to see the final state
print("\n⏳ Keeping browser open for 5 seconds for manual inspection...")
await asyncio.sleep(5)
await browser.close()
if __name__ == "__main__":
print("πŸ§ͺ Chat Widget Playwright Test")
print("=" * 50)
try:
result = asyncio.run(test_chat_widget())
if result:
print("\nβœ… All tests passed!")
sys.exit(0)
else:
print("\n❌ Some tests failed!")
sys.exit(1)
except KeyboardInterrupt:
print("\n⏹️ Test interrupted by user")
sys.exit(1)
except Exception as e:
print(f"\nπŸ’₯ Test crashed: {e}")
sys.exit(1)