#!/usr/bin/env python3 """The reels HUD: up when you're using it, down when you're swiping past it. Run against a locally running backend: backend/main.py & .venv/bin/python tests/smoke_hud.py One panel and one swipe, deliberately: what's under test is when the controls come and go, not anything about the layout. The presses here are dispatched rather than clicked, because moving a mouse is itself a reason to wake the HUD and would hide what is being asked. """ import sys from playwright.sync_api import sync_playwright BASE = "http://127.0.0.1:5000/" SERVER = "https://hottubapp.io" CHANNEL = "xvideos" SEED = """([server, channel]) => { localStorage.setItem('config', JSON.stringify({ servers: [{ [server]: {} }] })); localStorage.setItem('preferences', JSON.stringify({ [server]: { channelId: channel } })); localStorage.removeItem('session'); }""" IDLE = """() => document.getElementById('feed-view').classList.contains('feed-hud-idle')""" PRESS = """(selector) => { const el = document.querySelector('.feed-slide.is-active ' + selector); if (!el) return 'missing'; el.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true })); return document.getElementById('feed-view').classList.contains('feed-hud-idle'); }""" SWIPE = """() => { const s = document.getElementById('feed-scroll'); s.scrollTop += s.clientHeight; }""" class Checks: def __init__(self): self.failed = 0 def ok(self, label, condition, detail=""): mark = "PASS" if condition else "FAIL" if not condition: self.failed += 1 print(f" [{mark}] {label}" + (f" -- {detail}" if detail and not condition else "")) def main(): c = Checks() with sync_playwright() as p: browser = p.chromium.launch(args=[ "--no-sandbox", "--disable-dev-shm-usage", "--disable-gpu", "--autoplay-policy=no-user-gesture-required", "--renderer-process-limit=1", "--js-flags=--max-old-space-size=512", ]) page = browser.new_page(viewport={"width": 430, "height": 930}) crashes = [] page.on("pageerror", lambda e: crashes.append(str(e))) page.goto(BASE, wait_until="domcontentloaded") page.evaluate(SEED, [SERVER, CHANNEL]) page.goto(BASE, wait_until="load") try: page.wait_for_selector(".video-card", timeout=90000) except Exception: # One reload, in case the status refresh or the listing failed. page.goto(BASE, wait_until="load") page.wait_for_selector(".video-card", timeout=90000) page.wait_for_timeout(2500) page.evaluate("() => App.feed.open()") page.wait_for_selector(".feed-slide", timeout=20000) page.wait_for_timeout(400) print("\nopening the feed") c.ok("the controls are up to start with", page.evaluate(IDLE) is False) print("\nleaving it alone") page.wait_for_timeout(1600) c.ok("they fade on their own", page.evaluate(IDLE) is True) print("\nswiping to the next reel") page.evaluate(SWIPE) page.wait_for_timeout(300) c.ok("the swipe does not put them back up mid-flight", page.evaluate(IDLE) is True) page.wait_for_timeout(2500) c.ok("nor once it has landed", page.evaluate(IDLE) is True) c.ok("and the reel it landed on is playing", page.evaluate("""() => { const v = document.querySelector('.feed-slide.is-active .feed-video'); return !!v && !v.paused; }""")) print("\nwhat does bring them back") c.ok("pressing the video -- which is how a swipe begins -- does not", page.evaluate(PRESS, ".feed-video") is True) c.ok("pressing a control does", page.evaluate(PRESS, ".feed-pane-mute") is False) page.wait_for_timeout(1600) c.ok("after which they fade again", page.evaluate(IDLE) is True) page.mouse.move(200, 400) page.mouse.move(210, 420) page.wait_for_timeout(200) c.ok("moving the mouse does too", page.evaluate(IDLE) is False) print("\na swipe started while they are up") c.ok("puts them away", (page.evaluate(SWIPE), page.wait_for_timeout(500), page.evaluate(IDLE))[2] is True) c.ok("nothing threw along the way", not crashes, str(crashes[:2])) browser.close() print(f"\n{'OK' if not c.failed else 'FAILED'}: {c.failed} check(s) failed") return 1 if c.failed else 0 sys.exit(main())