diff --git a/apps/web/src/styles/viewer/pets.css b/apps/web/src/styles/viewer/pets.css index 608cff1f5..10b0dd9ed 100644 --- a/apps/web/src/styles/viewer/pets.css +++ b/apps/web/src/styles/viewer/pets.css @@ -699,7 +699,7 @@ align-items: center; justify-content: center; gap: 5px; - min-width: max-content; + min-width: 0; min-height: 30px; padding: 5px 10px; font-size: 11.5px; @@ -710,7 +710,6 @@ color: var(--text-muted); cursor: pointer; white-space: nowrap; - min-width: 0; } .composer-tools-tab:hover { color: var(--text); } .composer-tools-tab.active { @@ -763,7 +762,9 @@ display: inline-flex; align-items: center; justify-content: center; + overflow: hidden; min-height: 28px; + min-width: 0; padding: 5px 8px; border: 1px solid transparent; border-radius: calc(var(--radius-sm) - 1px); @@ -772,7 +773,8 @@ font: inherit; font-size: 11.5px; cursor: pointer; - min-width: 0; + text-overflow: ellipsis; + white-space: nowrap; } .composer-tools-segment:hover { color: var(--text); @@ -785,11 +787,6 @@ font-weight: 600; box-shadow: var(--shadow-xs); } -.composer-tools-segment { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} .composer-tools-search { width: 100%; height: 32px; diff --git a/apps/web/tests/components/ChatComposer.plugin-clear-prunes-draft.test.tsx b/apps/web/tests/components/ChatComposer.plugin-clear-prunes-draft.test.tsx index 20c7dff14..d87b63825 100644 --- a/apps/web/tests/components/ChatComposer.plugin-clear-prunes-draft.test.tsx +++ b/apps/web/tests/components/ChatComposer.plugin-clear-prunes-draft.test.tsx @@ -22,7 +22,7 @@ // (#2929 review — boundary alignment). import { StrictMode } from 'react'; -import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { ChatComposer } from '../../src/components/ChatComposer'; @@ -95,6 +95,16 @@ function renderComposer() { ); } +function findToolsPluginButton(title: string): HTMLButtonElement | undefined { + return within(screen.getByRole('menu')) + .getAllByRole('menuitem') + .find( + (btn): btn is HTMLButtonElement => + btn instanceof HTMLButtonElement && + btn.querySelector('strong')?.textContent?.trim() === title, + ); +} + beforeEach(() => { fetchMock = vi.fn(async (url: string) => { if (url === '/api/mcp/servers') { @@ -177,14 +187,10 @@ describe('ChatComposer plugin clear prunes draft (#2881)', () => { fireEvent.click(trigger!); await waitFor(() => expect(screen.getByRole('menu')).toBeTruthy()); - // Pick the plugin from inside the now-open tools popover. The - // plugin row's main button title lives inside a child; we - // match against that to avoid the row's description trailing text. - const popoverPluginButton = Array.from( - document.querySelectorAll('.composer-tools-row-main'), - ).find( - (btn) => btn.querySelector('strong')?.textContent?.trim() === 'Airbnb', - ); + // Pick the plugin from inside the now-open tools popover. The row + // title lives inside a child; match against that to avoid + // the description and action text in the accessible name. + const popoverPluginButton = findToolsPluginButton('Airbnb'); expect(popoverPluginButton).toBeTruthy(); fireEvent.click(popoverPluginButton!); @@ -698,11 +704,7 @@ describe('ChatComposer plugin clear prunes draft (#2881)', () => { fireEvent.click(trigger!); await waitFor(() => expect(screen.getByRole('menu')).toBeTruthy()); - const popoverPluginButton = Array.from( - document.querySelectorAll('.composer-tools-row-main'), - ).find( - (btn) => btn.querySelector('strong')?.textContent?.trim() === 'SecondPlugin', - ); + const popoverPluginButton = findToolsPluginButton('SecondPlugin'); expect(popoverPluginButton).toBeTruthy(); fireEvent.click(popoverPluginButton!); @@ -930,11 +932,7 @@ describe('ChatComposer plugin clear prunes draft (#2881)', () => { fireEvent.click(trigger!); await waitFor(() => expect(screen.getByRole('menu')).toBeTruthy()); - const popoverPluginButton = Array.from( - document.querySelectorAll('.composer-tools-row-main'), - ).find( - (btn) => btn.querySelector('strong')?.textContent?.trim() === 'Airbnb', - ); + const popoverPluginButton = findToolsPluginButton('Airbnb'); expect(popoverPluginButton).toBeTruthy(); fireEvent.click(popoverPluginButton!); @@ -1185,11 +1183,7 @@ describe('ChatComposer plugin clear prunes draft (#2881)', () => { fireEvent.click(trigger!); await waitFor(() => expect(screen.getByRole('menu')).toBeTruthy()); - const popoverSecondPluginButton = Array.from( - document.querySelectorAll('.composer-tools-row-main'), - ).find( - (btn) => btn.querySelector('strong')?.textContent?.trim() === 'SecondPlugin', - ); + const popoverSecondPluginButton = findToolsPluginButton('SecondPlugin'); expect(popoverSecondPluginButton).toBeTruthy(); fireEvent.click(popoverSecondPluginButton!);