From 99f4efefdd6db29f5fd8c9e14a0518453ccce88b Mon Sep 17 00:00:00 2001 From: Daniel Han Date: Thu, 7 May 2026 05:19:35 +0000 Subject: [PATCH] CI(ui): make sidebar click_nav() locate via data-sidebar=menu-button + has-text The Chat UI Tests CI run failed at "nav 'New Chat' not found": the get_by_role("button", name="New Chat") path doesn't always match because SidebarMenuButton wraps the visible label in a that the accessibility-name calculation can lose track of when the sidebar is in a collapsed/icon-only state. Try, in order: 1. [data-sidebar="menu-button"]:has-text("New Chat") -- the shadcn-ui SidebarMenuButton renders with this attribute. 2. role=button, name=re.compile(...) -- the existing path. 3. button:has-text("New Chat") -- last-resort. The first locator works regardless of sidebar collapse state because data-sidebar="menu-button" is part of the component contract, not the visual layout. --- tests/studio/playwright_chat_ui.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/tests/studio/playwright_chat_ui.py b/tests/studio/playwright_chat_ui.py index 9d14888875..365e82b17c 100644 --- a/tests/studio/playwright_chat_ui.py +++ b/tests/studio/playwright_chat_ui.py @@ -635,13 +635,33 @@ with sync_playwright() as p: # 10. Sidebar nav: New Chat, Compare, Search, Recipes. # ───────────────────────────────────────────────────── def click_nav(label, expected_url_pat = None): - btn = page.get_by_role( - "button", name = re.compile(rf"^\s*{label}\s*$", re.I) - ).first - if btn.count() == 0: + # Try, in order: data-sidebar=menu-button with text, role+name, + # button with text. Sidebar items render as SidebarMenuButton + # (data-sidebar="menu-button") containing a with the + # label; the role+name path fails when the sidebar collapses + # to icon-only mode and the visible text gets visually hidden. + candidates = [ + page.locator( + f'[data-sidebar="menu-button"]:has-text("{label}")' + ).first, + page.get_by_role( + "button", name = re.compile(rf"^\s*{label}\s*$", re.I), + ).first, + page.locator(f'button:has-text("{label}")').first, + ] + btn = None + for c in candidates: + if c.count() > 0: + btn = c + break + if btn is None: soft_fail(f"nav '{label}' not found") return False - btn.click() + try: + btn.click() + except Exception as exc: + soft_fail(f"nav '{label}' click failed: {exc!r}") + return False page.wait_for_timeout(800) if expected_url_pat and not re.search(expected_url_pat, page.url): soft_fail(