veza/apps/web/src/features/settings/components/PreferenceSettings.test.tsx

246 lines
6.8 KiB
TypeScript
Raw Normal View History

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { PreferenceSettings } from './PreferenceSettings';
import { PreferenceSettings as PreferenceSettingsType } from '../../types/settings';
// Mock ResizeObserver for tests
global.ResizeObserver = vi.fn().mockImplementation(() => ({
observe: vi.fn(),
unobserve: vi.fn(),
disconnect: vi.fn(),
}));
// Mock Select component
vi.mock('@/components/ui/select', () => ({
Select: ({ value, onChange, options, placeholder }: any) => (
<div data-testid="select">
<select
value={typeof value === 'string' ? value : ''}
onChange={(e) => onChange(e.target.value)}
data-placeholder={placeholder}
>
<option value="">{placeholder}</option>
{options.map((opt: any) => (
<option key={opt.value} value={opt.value}>
{opt.label}
</option>
))}
</select>
</div>
),
}));
// Mock RadioGroup
vi.mock('@/components/ui/radio-group', () => ({
RadioGroup: ({ children, value, onValueChange }: any) => (
<div data-testid="radio-group" data-value={value}>
{children}
<button onClick={() => onValueChange('light')}>Select Light</button>
<button onClick={() => onValueChange('dark')}>Select Dark</button>
<button onClick={() => onValueChange('auto')}>Select Auto</button>
</div>
),
RadioGroupItem: ({ value, id }: any) => (
<input type="radio" value={value} id={id} data-testid={`radio-${value}`} />
),
}));
// Mock Label
vi.mock('@/components/ui/label', () => ({
Label: ({ children, htmlFor }: any) => (
<label htmlFor={htmlFor}>{children}</label>
),
}));
// Mock useTranslation hook
vi.mock('@/hooks/useTranslation', () => ({
useTranslation: () => ({
t: (key: string) => {
const translations: Record<string, string> = {
'settings.language.language': 'Language',
'settings.language.title': 'Language and Region',
'settings.preferences.timezone': 'Time Zone',
'settings.language.description': 'Choose your preferred language',
'settings.appearance.theme': 'Theme',
'settings.appearance.light': 'Light',
'settings.appearance.dark': 'Dark',
'settings.appearance.system': 'System',
'common.search': 'Search',
};
return translations[key] ?? key;
},
changeLanguage: vi.fn(),
language: 'en',
isReady: true,
}),
}));
describe('PreferenceSettings Component', () => {
const mockPreferences: PreferenceSettingsType = {
language: 'en',
timezone: 'UTC',
theme: 'auto',
};
const mockOnChange = vi.fn();
beforeEach(() => {
vi.clearAllMocks();
});
it('should render all preference fields', () => {
render(
2025-12-13 02:34:34 +00:00
<PreferenceSettings
preferences={mockPreferences}
onChange={mockOnChange}
/>,
);
expect(screen.getByText('Language')).toBeInTheDocument();
// Bug #18: label was "Language and Region", now correctly "Time Zone"
expect(screen.getByText('Time Zone')).toBeInTheDocument();
expect(screen.getByText('Theme')).toBeInTheDocument();
expect(screen.getByTestId('radio-group')).toBeInTheDocument();
});
it('should display current language value', () => {
render(
2025-12-13 02:34:34 +00:00
<PreferenceSettings
preferences={mockPreferences}
onChange={mockOnChange}
/>,
);
const selects = screen.getAllByTestId('select');
const languageSelect = selects[0].querySelector('select');
expect(languageSelect).toHaveValue('en');
});
it('should call onChange when language changes', () => {
render(
2025-12-13 02:34:34 +00:00
<PreferenceSettings
preferences={mockPreferences}
onChange={mockOnChange}
/>,
);
const selects = screen.getAllByTestId('select');
const languageSelect = selects[0].querySelector('select');
if (languageSelect) {
fireEvent.change(languageSelect, { target: { value: 'fr' } });
expect(mockOnChange).toHaveBeenCalledWith({
...mockPreferences,
language: 'fr',
});
}
});
it('should display current timezone value', () => {
render(
2025-12-13 02:34:34 +00:00
<PreferenceSettings
preferences={mockPreferences}
onChange={mockOnChange}
/>,
);
const selects = screen.getAllByTestId('select');
const timezoneSelect = selects[1].querySelector('select');
expect(timezoneSelect).toHaveValue('UTC');
});
it('should call onChange when timezone changes', () => {
render(
2025-12-13 02:34:34 +00:00
<PreferenceSettings
preferences={mockPreferences}
onChange={mockOnChange}
/>,
);
const selects = screen.getAllByTestId('select');
const timezoneSelect = selects[1].querySelector('select');
if (timezoneSelect) {
fireEvent.change(timezoneSelect, { target: { value: 'Europe/Paris' } });
expect(mockOnChange).toHaveBeenCalledWith({
...mockPreferences,
timezone: 'Europe/Paris',
});
}
});
it('should display current theme value', () => {
render(
2025-12-13 02:34:34 +00:00
<PreferenceSettings
preferences={mockPreferences}
onChange={mockOnChange}
/>,
);
const radioGroup = screen.getByTestId('radio-group');
expect(radioGroup).toHaveAttribute('data-value', 'auto');
});
it('should call onChange when theme changes to light', () => {
render(
2025-12-13 02:34:34 +00:00
<PreferenceSettings
preferences={mockPreferences}
onChange={mockOnChange}
/>,
);
const lightButton = screen.getByText('Select Light');
fireEvent.click(lightButton);
expect(mockOnChange).toHaveBeenCalledWith({
...mockPreferences,
theme: 'light',
});
});
it('should call onChange when theme changes to dark', () => {
render(
2025-12-13 02:34:34 +00:00
<PreferenceSettings
preferences={mockPreferences}
onChange={mockOnChange}
/>,
);
const darkButton = screen.getByText('Select Dark');
fireEvent.click(darkButton);
expect(mockOnChange).toHaveBeenCalledWith({
...mockPreferences,
theme: 'dark',
});
});
it('should call onChange when theme changes to auto', () => {
render(
2025-12-13 02:34:34 +00:00
<PreferenceSettings
preferences={{ ...mockPreferences, theme: 'light' }}
onChange={mockOnChange}
/>,
);
const autoButton = screen.getByText('Select Auto');
fireEvent.click(autoButton);
expect(mockOnChange).toHaveBeenCalledWith({
...mockPreferences,
theme: 'auto',
});
});
it('should render all theme options', () => {
render(
2025-12-13 02:34:34 +00:00
<PreferenceSettings
preferences={mockPreferences}
onChange={mockOnChange}
/>,
);
expect(screen.getByTestId('radio-light')).toBeInTheDocument();
expect(screen.getByTestId('radio-dark')).toBeInTheDocument();
expect(screen.getByTestId('radio-auto')).toBeInTheDocument();
});
});