test_chat_mobile.py
4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env python3
"""RED phase test: Verify that /chat page correctly extends base.html and has
responsive layout + session loading.
Before fix (RED): Page is standalone with no topbar/☰ menu → FAIL.
After fix (GREEN): Page extends base.html with topbar, ☰, session sidebar toggle → PASS.
"""
import subprocess, sys, json
BASE_URL = "http://127.0.0.1:5000"
FAILURES = []
def check(name, condition):
if condition:
print(f" [PASS] {name}")
else:
print(f" [FAIL] {name}")
FAILURES.append(name)
def curl(url):
r = subprocess.run(["curl", "-s", url, "--connect-timeout", "5", "--max-time", "10"],
capture_output=True, text=True, timeout=15)
return r.stdout, r.returncode
def curl_status(url):
r = subprocess.run(["curl", "-s", "-o", "/dev/null", "-w", "%{http_code}",
url, "--connect-timeout", "5", "--max-time", "10"],
capture_output=True, text=True, timeout=15)
return r.stdout.strip()
def curl_json(url):
html, _ = curl(url)
try:
return json.loads(html)
except:
return None
# ── Test Suite ──
print("=== TC0: Page accessibility ===")
status = curl_status(f"{BASE_URL}/chat")
check("GET /chat returns 200", status == "200")
html, _ = curl(f"{BASE_URL}/chat")
print("\n=== TC1: base.html integration ===")
# After fix, /chat should extend base.html and have these:
check("Has topbar with ☰ menu button", 'class="menu-btn"' in html and '☰' in html)
check("Has drawer overlay", 'class="overlay"' in html)
check("Has drawer div", 'class="drawer"' in html)
check("Has drawer navigation", 'class="drawer-nav"' in html)
check("Has topbar brand", 'class="topbar"' in html)
check("Has main content area", 'class="main"' in html)
print("\n=== TC2: Chat-specific layout ===")
# Session sidebar + chat area
check("Has session sidebar (or drawer)", 'convList' in html)
check("Has message list area", 'msgList' in html)
check("Has message input", 'msgInput' in html)
check("Has send button", 'sendBtn' in html)
check("Has loadConversations function", 'loadConversations' in html)
check("Has selectConversation function", 'selectConversation' in html)
check("Has loadMessages function", 'loadMessages' in html)
check("Has sendMessage function", 'sendMessage' in html)
check("Has newConversation function", 'newConversation' in html)
check("Has SSE EventSource usage", 'EventSource' in html)
print("\n=== TC3: Jinja2 template safety ===")
# No Jinja2 escaping issues
check("No Jinja2 escaped quotes in onclick", 'onclick=\\"' not in html)
check("No style backslash bug", "style=\\\\\\'" not in html)
check("No triple escape bug", '\\\\\\\\\\\\\\\"' not in html)
# base.html uses onclick inline (toggleDrawer, closeDrawer) - but those are in base.html
# Check that aichat-specific onclick patterns are clean
assert_newline_escapes = True
for line in html.split('\n'):
if 'onclick=' in line and ('newConversation' in line or 'sendMessage' in line or 'selectConversation' in line):
if '\\' in line:
assert_newline_escapes = False
break
check("Chat-specific onclick clean (no backslash escaping)", assert_newline_escapes)
print("\n=== TC4: Responsive layout markers ===")
# Check for mobile-responsive CSS
check("Has media query for mobile (<768px)", "@media" in html and "768" in html)
check("Has session sidebar toggle button (mobile)", 'toggle-chat-sidebar' in html or 'toggleChatSidebar' in html or 'toggleSessions' in html)
print("\n=== TC5: API connectivity ===")
# Conversations API
conv_data = curl_json(f"{BASE_URL}/api/conversations")
check("GET /api/conversations returns ok", conv_data and conv_data.get("ok"))
check("GET /api/conversations has data array", isinstance(conv_data.get("data"), list) if conv_data else False)
# Messages API (if conversations exist)
if conv_data and conv_data.get("data"):
conv_id = conv_data["data"][0]["id"]
msg_data = curl_json(f"{BASE_URL}/api/conversations/{conv_id}/messages")
check(f"GET /api/conversations/{conv_id}/messages returns ok",
msg_data and msg_data.get("ok"))
if msg_data and msg_data.get("data"):
m = msg_data["data"][0]
check("Messages have role field", "role" in m)
check("Messages have content field", "content" in m)
check("Messages have created_at field", "created_at" in m)
check("Messages have id field", "id" in m)
print(f"\n=== {len(FAILURES)} failure(s) ===")
if FAILURES:
for f in FAILURES:
print(f" FAIL: {f}")
sys.exit(1)
else:
print("ALL TESTS PASSED")
sys.exit(0)