SeparateTracks / specs /test_gallery.py
Surn's picture
Refactor: modularize app, add AudioGallery, MCP, tests
6182d7b
"""
Test: AudioGallery file serving and UI flow for video ID f-H9bbi0Vyw.
Server must already be running on http://localhost:7860.
"""
import sys
from pathlib import Path
from playwright.sync_api import sync_playwright, expect
VIDEO_ID = "f-H9bbi0Vyw"
BASE_URL = "http://localhost:7860"
STEMS = ["bass", "drums", "guitar", "music", "other", "piano", "vocals"]
SEPARATED = Path("D:/Projects/SeparateTracks/separated/htdemucs_6s") / VIDEO_ID
def test_file_endpoint(page):
"""Part 1: verify each /file= URL returns audio data (200 + audio MIME)."""
print("\n=== Part 1: /file= endpoint ===")
all_ok = True
for stem in STEMS:
path = (SEPARATED / f"{stem}.mp3").as_posix()
url = f"{BASE_URL}/file={path}"
resp = page.request.head(url)
status = resp.status
ct = resp.headers.get("content-type", "")
ok = status == 200 and "audio" in ct
symbol = "OK" if ok else "FAIL"
print(f" {symbol} {stem:8s} HTTP {status} {ct}")
if not ok:
all_ok = False
return all_ok
def test_ui_flow(page):
"""Part 2: enter video ID, click button, wait for gallery, verify audio elements."""
print("\n=== Part 2: UI flow ===")
page.goto(BASE_URL)
page.wait_for_load_state("networkidle")
page.screenshot(path="specs/screenshots/01_initial.png", full_page=True)
print(" Screenshot: 01_initial.png")
# Fill in the video ID
textbox = page.get_by_label("YouTube Video ID")
textbox.fill(VIDEO_ID)
page.screenshot(path="specs/screenshots/02_filled.png", full_page=True)
print(f" Entered video ID: {VIDEO_ID}")
# Click Separate Tracks
page.get_by_role("button", name="Separate Tracks").click()
print(" Clicked 'Separate Tracks' — waiting for pipeline (CPU may take ~10 min)…")
# Wait for the AudioGallery HTML to appear (long timeout for CPU demucs)
try:
page.wait_for_selector(".audio-gallery-container", timeout=720_000)
except Exception:
page.screenshot(path="specs/screenshots/03_timeout.png", full_page=True)
print(" ❌ Timed out waiting for .audio-gallery-container")
return False
page.screenshot(path="specs/screenshots/03_gallery.png", full_page=True)
print(" Screenshot: 03_gallery.png")
# Count audio elements
audio_els = page.locator("audio").all()
print(f" Found {len(audio_els)} <audio> element(s)")
# Check each audio src
all_ok = True
for i, el in enumerate(audio_els):
src = el.get_attribute("src") or ""
# Verify src ends in .mp3 and contains the video ID or /file=
ok = ".mp3" in src and ("/file=" in src or VIDEO_ID in src)
symbol = "OK" if ok else "FAIL"
print(f" {symbol} audio[{i}] src={src[:80]}")
if not ok:
all_ok = False
# Verify progress textbox shows "Done."
progress = page.get_by_label("Progress").input_value()
done_ok = "Done." in progress or "Separation complete" in progress
print(f" {'OK' if done_ok else 'FAIL'} Progress box: {progress[-60:].strip()!r}")
return all_ok and len(audio_els) == 7
def main():
Path("specs/screenshots").mkdir(parents=True, exist_ok=True)
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
endpoint_ok = test_file_endpoint(page)
ui_ok = test_ui_flow(page)
browser.close()
print("\n=== Summary ===")
print(f" /file= endpoint: {'PASS' if endpoint_ok else 'FAIL'}")
print(f" UI flow: {'PASS' if ui_ok else 'FAIL'}")
sys.exit(0 if (endpoint_ok and ui_ok) else 1)
if __name__ == "__main__":
main()