"""Playwright headless smoke test. Boots ``app.py`` in a subprocess (via the ``app_url`` fixture in :mod:`conftest`) and asserts the Phase D minimum: - All three Gradio tabs render. - The Detailed View tab carries two stacked ``Leaderboard`` widgets (Validated + Unvalidated, per the two-tier viewer landed in C3). If the Space won't load these tabs or the leaderboards don't render, every other test downstream is meaningless. Requires: - ``pip install -r requirements-dev.txt`` - ``playwright install chromium`` (one-off, fetches the bundled browser) """ from __future__ import annotations from playwright.sync_api import expect, sync_playwright def test_three_tabs_render(app_url): with sync_playwright() as p: browser = p.chromium.launch(headless=True) try: page = browser.new_page() page.goto(app_url) for tab_name in ("Leaderboard", "Submit", "About"): expect(page.get_by_role("tab", name=tab_name)).to_be_visible( timeout=15_000 ) finally: browser.close() def test_two_leaderboard_widgets_render(app_url): """Both Validated and Unvalidated leaderboards render on the Detailed View tab. The Leaderboard (visual) tab is the default (first) tab, so the Detailed View tab's content is mounted-but-hidden until selected; click the tab first, then assert. The two widgets are identified by their labels (set in app.py). The labels are case-sensitive substrings that don't overlap ("Validated Leaderboard" is not a substring of "Unvalidated Leaderboard" with the uppercase V). The ``Leaderboard`` widget renders each label twice: the visible ``
`` label and a screen-reader-only ``
`` label to avoid a strict-mode "resolved to 2 elements" violation. """ with sync_playwright() as p: browser = p.chromium.launch(headless=True) try: page = browser.new_page() page.goto(app_url) page.get_by_role("tab", name="Detailed View").click() expect( page.get_by_text("Validated Leaderboard", exact=True) .and_(page.locator("p")) ).to_be_visible(timeout=15_000) expect( page.get_by_text("Unvalidated Leaderboard", exact=True) .and_(page.locator("p")) ).to_be_visible(timeout=15_000) finally: browser.close()