import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, expect, it, vi } from 'vitest'; import { LanguageSwitcher } from '../language-switcher'; // Mock next-intl vi.mock('next-intl', () => ({ useLocale: () => 'vi', useTranslations: () => (key: string) => { const translations: Record = { label: 'Ngôn ngữ', vi: 'Tiếng Việt', en: 'English', }; return translations[key] ?? key; }, })); // Mock i18n navigation const mockReplace = vi.fn(); vi.mock('@/i18n/navigation', () => ({ useRouter: () => ({ replace: mockReplace, }), usePathname: () => '/search', })); describe('LanguageSwitcher', () => { beforeEach(() => { mockReplace.mockClear(); }); it('renders a button', () => { render(); expect(screen.getByRole('button')).toBeInTheDocument(); }); it('has correct aria-label', () => { render(); expect(screen.getByRole('button')).toHaveAttribute( 'aria-label', expect.stringContaining('Ngôn ngữ'), ); }); it('shows next locale label (EN when current is VI)', () => { render(); // The button should display the label for "en" since current is "vi" expect(screen.getByText(/EN/)).toBeInTheDocument(); }); it('calls router.replace when clicked', async () => { const user = userEvent.setup(); render(); await user.click(screen.getByRole('button')); expect(mockReplace).toHaveBeenCalledWith('/search', { locale: 'en' }); }); it('has screen reader text', () => { render(); const srText = document.querySelector('.sr-only'); expect(srText).toBeInTheDocument(); expect(srText).toHaveTextContent('English'); }); });