Headless Chromium 151 stops generating animation frames on idle pages, which stalls Playwright's rAF-based waits (wait_for_function default polling, click actionability 'stable' check). Fixes: - wait_for_function: explicit timer polling (100ms/250ms) - video readyState wait: 120s (cold upstream/CDN starts) - .card click: force=True - login: form submit handler (Enter key works, was button-only) - test asserts the seeded entry, not a section header that only appeared via an API-test side effect
101 lines
4.0 KiB
Python
101 lines
4.0 KiB
Python
"""Browser tests for ani-web (Playwright, headless Chromium).
|
|
|
|
Run via tests/run.py or standalone: python tests/test_browser.py <base_url>
|
|
Covers what HTTP tests can't: the login UI, the user chip, and real
|
|
video playback behind auth. Needs: pip install playwright && playwright install chromium
|
|
"""
|
|
import asyncio
|
|
import sys
|
|
|
|
from playwright.async_api import async_playwright
|
|
|
|
BASE = "http://127.0.0.1:8399"
|
|
LAUNCH_ARGS = ["--autoplay-policy=no-user-gesture-required"]
|
|
# This headless Chromium stops generating animation frames on idle pages,
|
|
# which stalls rAF-based Playwright waits (wait_for_function's default
|
|
# polling, click actionability). Poll by timer instead; force the one click.
|
|
POLL = 100
|
|
|
|
|
|
async def _login(page, user, pw):
|
|
await page.goto(BASE + "/")
|
|
await page.wait_for_selector("input#pw")
|
|
assert "create account" not in await page.content(), "self-signup UI must be absent"
|
|
await page.fill("#user", user)
|
|
await page.fill("#pw", pw)
|
|
# Enter instead of clicking #go: this playwright/chromium combo's
|
|
# "element stable" actionability check hangs non-deterministically;
|
|
# fill() leaves focus on the field, so a bare keypress submits.
|
|
await page.keyboard.press("Enter")
|
|
await page.wait_for_selector("#q", timeout=15000)
|
|
await page.wait_for_function(
|
|
f"document.getElementById('me').textContent.includes('{user}')",
|
|
timeout=5000, polling=POLL)
|
|
|
|
|
|
async def test_login_ui():
|
|
async with async_playwright() as p:
|
|
browser = await p.chromium.launch(args=LAUNCH_ARGS)
|
|
page = await (await browser.new_context()).new_page()
|
|
errors = []
|
|
page.on("pageerror", lambda e: errors.append(str(e)))
|
|
|
|
# unauth -> login form
|
|
await page.goto(BASE + "/")
|
|
await page.wait_for_selector("input#pw")
|
|
assert "/login" in page.url, page.url
|
|
|
|
# wrong password -> inline error
|
|
await page.fill("#user", "admin")
|
|
await page.fill("#pw", "wrong")
|
|
await page.keyboard.press("Enter")
|
|
await page.wait_for_function("document.querySelector('#err').textContent.length > 0",
|
|
timeout=10000, polling=POLL)
|
|
assert "wrong" in await page.inner_text("#err")
|
|
|
|
# correct -> home with user chip
|
|
await page.fill("#pw", "adminpw12345")
|
|
await page.keyboard.press("Enter")
|
|
await _login_settled(page)
|
|
assert await page.inner_text("#me") == "hi, admin"
|
|
assert "Seed Anime" in await page.inner_text("#main"), "seeded history must show"
|
|
assert not errors, errors
|
|
await browser.close()
|
|
print("ok test_login_ui")
|
|
|
|
|
|
async def _login_settled(page):
|
|
await page.wait_for_selector("#q", timeout=15000)
|
|
await page.wait_for_function(
|
|
"document.getElementById('me').textContent.length > 0", timeout=5000, polling=POLL)
|
|
|
|
|
|
async def test_video_plays_behind_auth():
|
|
async with async_playwright() as p:
|
|
browser = await p.chromium.launch(args=LAUNCH_ARGS)
|
|
page = await (await browser.new_context()).new_page()
|
|
errors = []
|
|
page.on("pageerror", lambda e: errors.append(str(e)))
|
|
page.on("console", lambda m: errors.append(m.text) if m.type == "error" else None)
|
|
|
|
await _login(page, "alice", "alicepw12345")
|
|
await page.fill("#q", "chainsaw")
|
|
await page.keyboard.press("Enter")
|
|
await page.wait_for_selector(".card", timeout=30000)
|
|
await page.click(".card", force=True)
|
|
await page.wait_for_selector("video", timeout=30000)
|
|
await page.wait_for_function(
|
|
"document.querySelector('video').readyState >= 4 && document.querySelector('video').currentTime > 1",
|
|
timeout=120000, polling=250) # 120s: cold CDN/upstream starts can be slow
|
|
real_errors = [e for e in errors if "401" not in e]
|
|
assert not real_errors, real_errors
|
|
await browser.close()
|
|
print("ok test_video_plays_behind_auth")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) > 1:
|
|
BASE = sys.argv[1]
|
|
asyncio.run(test_login_ui())
|
|
asyncio.run(test_video_plays_behind_auth())
|