import { createRef, type MouseEvent } from 'react'; import { cleanup, fireEvent, render, screen, within } from '@testing-library/react'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { AccountMenuTrigger } from '@/components/account/AccountMenuTrigger'; afterEach(cleanup); describe('AccountMenuTrigger', () => { it('forwards the button ref, click handler, menu accessibility attributes and test IDs', () => { const ref = createRef(); let clickedButton: HTMLButtonElement | null = null; const onClick = vi.fn((event: MouseEvent) => { clickedButton = event.currentTarget; }); render(); const button = screen.getByRole('button', { name: '打开账户菜单' }); expect(ref.current).toBe(button); expect(screen.getByTestId('account-trigger')).toBe(button); expect(button).toHaveAttribute('type', 'button'); expect(button).toHaveAttribute('aria-haspopup', 'menu'); expect(button).toHaveAttribute('aria-expanded', 'true'); expect(button).toHaveAttribute('aria-controls', 'account-menu'); expect(within(button).getByTestId('account-surface')).toContainElement(screen.getByTestId('account-avatar')); expect(within(button).getByText('小麦')).toBeInTheDocument(); fireEvent.click(button); expect(onClick).toHaveBeenCalledTimes(1); expect(clickedButton).toBe(button); expect(button).toHaveAttribute('aria-expanded', 'true'); }); it('supports callback refs and native button attributes, including disabled clicks', () => { const ref = vi.fn<(node: HTMLButtonElement | null) => void>(); const onClick = vi.fn(); const view = render(); const button = screen.getByRole('button', { name: '账户菜单' }); expect(ref.mock.calls.at(-1)?.[0]).toBe(button); expect(button).toHaveAttribute('type', 'submit'); expect(button).toHaveAttribute('title', '查看账户'); expect(button).toBeDisabled(); fireEvent.click(button); expect(onClick).not.toHaveBeenCalled(); view.unmount(); expect(ref.mock.calls.at(-1)?.[0]).toBe(null); }); it('preserves the avatar and accessible name when collapsed while hiding the account name and arrow', () => { const view = render(); const button = screen.getByRole('button', { name: '账户菜单' }); const avatar = screen.getByTestId('account-avatar'); expect(within(button).getByText('小麦')).toBeInTheDocument(); expect(button.querySelector('svg')).toBeInTheDocument(); view.rerender(); expect(screen.getByRole('button', { name: '账户菜单' })).toBe(button); expect(screen.getByTestId('account-avatar')).toBe(avatar); expect(avatar.querySelector('img')).toHaveAttribute('src', 'https://example.test/avatar.png'); expect(within(button).queryByText('小麦')).not.toBeInTheDocument(); expect(button.querySelector('svg')).not.toBeInTheDocument(); }); it('uses the default or preferred expanded width and fills its container when collapsed', () => { const view = render(); const button = screen.getByRole('button', { name: '账户菜单' }); expect(button).toHaveStyle({ width: '150px' }); view.rerender(); expect(button).toHaveStyle({ width: '188px' }); view.rerender(); expect(button.style.width).toBe(''); }); });