fix: isolate settings and unify account controls with Code
This commit is contained in:
1 parent
430233f825
commit
2cc542f1f8
32 files changed
+759
-1091
No files matched your search
@@ -0,0 +1,108 @@
|
||||
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<HTMLButtonElement>();
|
||||
let clickedButton: HTMLButtonElement | null = null;
|
||||
const onClick = vi.fn((event: MouseEvent<HTMLButtonElement>) => {
|
||||
clickedButton = event.currentTarget;
|
||||
});
|
||||
render(<AccountMenuTrigger
|
||||
ref={ref}
|
||||
accountName="小麦"
|
||||
onClick={onClick}
|
||||
aria-label="打开账户菜单"
|
||||
aria-haspopup="menu"
|
||||
aria-expanded={true}
|
||||
aria-controls="account-menu"
|
||||
data-testid="account-trigger"
|
||||
surfaceTestId="account-surface"
|
||||
avatarTestId="account-avatar"
|
||||
open
|
||||
/>);
|
||||
|
||||
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(<AccountMenuTrigger
|
||||
ref={ref}
|
||||
accountName="小麦"
|
||||
aria-label="账户菜单"
|
||||
type="submit"
|
||||
title="查看账户"
|
||||
disabled
|
||||
onClick={onClick}
|
||||
/>);
|
||||
|
||||
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(<AccountMenuTrigger
|
||||
accountName="小麦"
|
||||
avatarUrl="https://example.test/avatar.png"
|
||||
avatarTestId="account-avatar"
|
||||
aria-label="账户菜单"
|
||||
/>);
|
||||
const button = screen.getByRole('button', { name: '账户菜单' });
|
||||
const avatar = screen.getByTestId('account-avatar');
|
||||
expect(within(button).getByText('小麦')).toBeInTheDocument();
|
||||
expect(button.querySelector('svg')).toBeInTheDocument();
|
||||
|
||||
view.rerender(<AccountMenuTrigger
|
||||
accountName="小麦"
|
||||
avatarUrl="https://example.test/avatar.png"
|
||||
avatarTestId="account-avatar"
|
||||
aria-label="账户菜单"
|
||||
collapsed
|
||||
/>);
|
||||
|
||||
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(<AccountMenuTrigger accountName="小麦" aria-label="账户菜单" />);
|
||||
const button = screen.getByRole('button', { name: '账户菜单' });
|
||||
expect(button).toHaveStyle({ width: '150px' });
|
||||
|
||||
view.rerender(<AccountMenuTrigger accountName="小麦" aria-label="账户菜单" expandedWidth={188} />);
|
||||
expect(button).toHaveStyle({ width: '188px' });
|
||||
|
||||
view.rerender(<AccountMenuTrigger accountName="小麦" aria-label="账户菜单" expandedWidth={188} collapsed />);
|
||||
expect(button.style.width).toBe('');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user