- Add add-ai-provider-visibility and add-missing-columns migration scripts - Add clear-error-book, seed-error-book, diagnose-error-book scripts - Add diagnose-tables and create-missing-tables scripts - Add test-failing-modules and test-teacher-pages test scripts
152 lines
6.0 KiB
Python
152 lines
6.0 KiB
Python
"""
|
|
检查学情诊断、错题分析、公告、消息 4 个模块的实际渲染状态
|
|
截取截图 + 捕获控制台错误 + 检查页面内容
|
|
"""
|
|
import os
|
|
import time
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
BASE_URL = "http://localhost:3000"
|
|
TEACHER_EMAIL = "t_chinese_1@xiaoxue.edu.cn"
|
|
TEACHER_PASSWORD = "123456"
|
|
SCREENSHOT_DIR = os.path.join(os.path.dirname(__file__), "..", "bugs", "screenshots")
|
|
os.makedirs(SCREENSHOT_DIR, exist_ok=True)
|
|
|
|
ROUTES = [
|
|
("/teacher/diagnostic", "学情诊断"),
|
|
("/teacher/error-book", "错题分析"),
|
|
("/announcements", "公告"),
|
|
("/messages", "消息"),
|
|
]
|
|
|
|
|
|
def main():
|
|
with sync_playwright() as p:
|
|
browser = p.chromium.launch(headless=True)
|
|
context = browser.new_context(viewport={"width": 1440, "height": 900})
|
|
page = context.new_page()
|
|
|
|
# Login
|
|
print(">>> 登录...")
|
|
page.goto(f"{BASE_URL}/login", wait_until="domcontentloaded")
|
|
page.wait_for_timeout(3000)
|
|
page.locator('input[name="email"]').fill(TEACHER_EMAIL)
|
|
page.locator('input[type="password"]').first.fill(TEACHER_PASSWORD)
|
|
page.evaluate("""() => {
|
|
const form = document.querySelector('form');
|
|
if (form) {
|
|
const event = new Event('submit', { cancelable: true, bubbles: true });
|
|
form.dispatchEvent(event);
|
|
}
|
|
}""")
|
|
page.wait_for_timeout(5000)
|
|
print(f"登录后 URL: {page.url}")
|
|
|
|
for route, name in ROUTES:
|
|
print(f"\n{'='*60}")
|
|
print(f">>> 测试: {name} ({route})")
|
|
print(f"{'='*60}")
|
|
|
|
console_errors = []
|
|
console_warnings = []
|
|
|
|
def on_console(msg):
|
|
if msg.type == "error":
|
|
console_errors.append(msg.text)
|
|
elif msg.type == "warning":
|
|
console_warnings.append(msg.text)
|
|
|
|
def on_page_error(err):
|
|
console_errors.append(f"PageError: {str(err)[:300]}")
|
|
|
|
page.on("console", on_console)
|
|
page.on("pageerror", on_page_error)
|
|
|
|
try:
|
|
response = page.goto(f"{BASE_URL}{route}", timeout=30000, wait_until="domcontentloaded")
|
|
page.wait_for_timeout(3000) # Wait for client-side JS to execute
|
|
|
|
print(f" HTTP Status: {response.status if response else 'N/A'}")
|
|
print(f" Final URL: {page.url}")
|
|
|
|
# Check for error indicators on page
|
|
body_text = page.locator("body").text_content() or ""
|
|
print(f" Body text length: {len(body_text)}")
|
|
|
|
# Check for common error patterns
|
|
error_elements = page.locator('[role="alert"], .text-destructive, .text-red-500, .text-red-600')
|
|
error_count = error_elements.count()
|
|
if error_count > 0:
|
|
print(f" Error elements on page: {error_count}")
|
|
for i in range(min(error_count, 5)):
|
|
try:
|
|
text = error_elements.nth(i).text_content()
|
|
if text and text.strip():
|
|
print(f" [{i}] {text.strip()[:200]}")
|
|
except:
|
|
pass
|
|
|
|
# Check for loading spinners still visible
|
|
spinners = page.locator('.animate-spin, [role="status"], .loading')
|
|
spinner_count = spinners.count()
|
|
if spinner_count > 0:
|
|
print(f" Loading spinners still visible: {spinner_count}")
|
|
|
|
# Check for empty state
|
|
if "暂无" in body_text or "No data" in body_text or "没有" in body_text:
|
|
# Find the context
|
|
for keyword in ["暂无", "No data", "没有"]:
|
|
idx = body_text.find(keyword)
|
|
if idx >= 0:
|
|
context_text = body_text[max(0, idx-30):idx+80]
|
|
print(f" Empty state: ...{context_text}...")
|
|
break
|
|
|
|
# Check for "加载失败" or "error" text
|
|
for keyword in ["加载失败", "load", "error", "错误", "失败", "Error"]:
|
|
if keyword.lower() in body_text.lower():
|
|
idx = body_text.lower().find(keyword.lower())
|
|
context_text = body_text[max(0, idx-30):idx+100]
|
|
print(f" Found '{keyword}': ...{context_text}...")
|
|
break
|
|
|
|
# Take screenshot
|
|
screenshot_name = route.replace("/", "_").strip("_") + ".png"
|
|
screenshot_path = os.path.join(SCREENSHOT_DIR, screenshot_name)
|
|
page.screenshot(path=screenshot_path, full_page=True)
|
|
print(f" Screenshot: {screenshot_path}")
|
|
|
|
# Print console errors
|
|
if console_errors:
|
|
print(f"\n Console Errors ({len(console_errors)}):")
|
|
for err in console_errors[:10]:
|
|
print(f" - {err[:300]}")
|
|
else:
|
|
print(f" Console Errors: 0")
|
|
|
|
if console_warnings:
|
|
print(f"\n Console Warnings ({len(console_warnings)}):")
|
|
for w in console_warnings[:5]:
|
|
print(f" - {w[:200]}")
|
|
|
|
except Exception as e:
|
|
print(f" EXCEPTION: {type(e).__name__}: {str(e)[:300]}")
|
|
screenshot_name = route.replace("/", "_").strip("_") + "_error.png"
|
|
screenshot_path = os.path.join(SCREENSHOT_DIR, screenshot_name)
|
|
try:
|
|
page.screenshot(path=screenshot_path, full_page=True)
|
|
except:
|
|
pass
|
|
finally:
|
|
page.remove_listener("console", on_console)
|
|
page.remove_listener("pageerror", on_page_error)
|
|
|
|
browser.close()
|
|
print(f"\n{'='*60}")
|
|
print("测试完成!")
|
|
print(f"{'='*60}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|