feat: add view dropdown trigger and menu to app header (task-4)
- Add #view-dropdown-trigger button between wordmark and header-actions - Add #view-dropdown-menu container with role='menu' and hidden class - Add #view-dropdown-label with default text 'All Sessions' - Add caret span with aria-hidden='true' - Trigger has aria-haspopup='true', aria-expanded='false', aria-controls attributes - All wrapped in .view-dropdown div with id='view-dropdown' Tests added: - test_view_dropdown_trigger_exists - test_view_dropdown_container_exists - test_view_dropdown_trigger_has_aria - test_view_dropdown_menu_has_role_menu All 93 tests pass (4 new + 89 existing).
This commit is contained in:
@@ -19,6 +19,13 @@
|
||||
<div id="view-overview" class="view view--active">
|
||||
<header class="app-header">
|
||||
<h1 class="app-wordmark"><img src="/wordmark-on-dark.svg" alt="muxplex" height="24" /></h1>
|
||||
<div class="view-dropdown" id="view-dropdown">
|
||||
<button id="view-dropdown-trigger" class="view-dropdown__trigger" aria-haspopup="true" aria-expanded="false" aria-controls="view-dropdown-menu">
|
||||
<span id="view-dropdown-label">All Sessions</span>
|
||||
<span class="view-dropdown__caret" aria-hidden="true">▾</span>
|
||||
</button>
|
||||
<div id="view-dropdown-menu" class="view-dropdown__menu hidden" role="menu" aria-label="Switch view"></div>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button id="new-session-btn" class="header-btn" aria-label="New session">+</button>
|
||||
<button id="view-mode-btn" class="header-btn" aria-label="Toggle view mode" title="View: auto">▦</button>
|
||||
|
||||
@@ -1419,3 +1419,48 @@ def test_html_has_search_bar() -> None:
|
||||
html = read_html()
|
||||
assert "terminal-search-bar" in html, "Must have #terminal-search-bar element"
|
||||
assert "terminal-search-input" in html, "Must have #terminal-search-input element"
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Header Dropdown (task-4)
|
||||
# ============================================================
|
||||
|
||||
|
||||
def test_view_dropdown_trigger_exists() -> None:
|
||||
"""#view-dropdown-trigger element must exist in the header."""
|
||||
soup = _SOUP
|
||||
trigger = soup.find(id="view-dropdown-trigger")
|
||||
assert trigger is not None, "Missing #view-dropdown-trigger"
|
||||
assert trigger.name == "button", (
|
||||
f"#view-dropdown-trigger must be a <button>, got: {trigger.name}"
|
||||
)
|
||||
|
||||
|
||||
def test_view_dropdown_container_exists() -> None:
|
||||
"""#view-dropdown-menu container must exist in the header."""
|
||||
soup = _SOUP
|
||||
menu = soup.find(id="view-dropdown-menu")
|
||||
assert menu is not None, "Missing #view-dropdown-menu"
|
||||
|
||||
|
||||
def test_view_dropdown_trigger_has_aria() -> None:
|
||||
"""#view-dropdown-trigger must have aria-haspopup='true' and aria-expanded='false'."""
|
||||
soup = _SOUP
|
||||
trigger = soup.find(id="view-dropdown-trigger")
|
||||
assert trigger is not None, "Missing #view-dropdown-trigger"
|
||||
assert trigger.get("aria-haspopup") == "true", (
|
||||
f"#view-dropdown-trigger must have aria-haspopup='true', got: {trigger.get('aria-haspopup')!r}"
|
||||
)
|
||||
assert trigger.get("aria-expanded") == "false", (
|
||||
f"#view-dropdown-trigger must have aria-expanded='false', got: {trigger.get('aria-expanded')!r}"
|
||||
)
|
||||
|
||||
|
||||
def test_view_dropdown_menu_has_role_menu() -> None:
|
||||
"""#view-dropdown-menu must have role='menu'."""
|
||||
soup = _SOUP
|
||||
menu = soup.find(id="view-dropdown-menu")
|
||||
assert menu is not None, "Missing #view-dropdown-menu"
|
||||
assert menu.get("role") == "menu", (
|
||||
f"#view-dropdown-menu must have role='menu', got: {menu.get('role')!r}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user