veza/apps/web/src/features/user/components/ProfileForm.test.tsx

224 lines
5.8 KiB
TypeScript
Raw Normal View History

import { render, screen, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import userEvent from '@testing-library/user-event';
import { BrowserRouter } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ToastProvider } from '@/components/feedback/ToastProvider';
import { ProfileForm } from './ProfileForm';
// Mock useTranslation
vi.mock('@/hooks/useTranslation', () => ({
useTranslation: () => ({
t: (key: string) => key,
i18n: { changeLanguage: vi.fn() },
language: 'fr',
changeLanguage: vi.fn(),
isReady: true,
}),
}));
const mockUser = {
id: '1',
username: 'testuser',
email: 'test@example.com',
first_name: 'Test',
last_name: 'User',
bio: 'Test bio',
};
vi.mock('@/features/auth/hooks/useUser', () => ({
useUser: () => ({
data: mockUser,
isLoading: false,
error: null,
}),
}));
// Mock useUIStore
vi.mock('@/stores/ui', () => ({
useUIStore: () => ({
addNotification: vi.fn(),
}),
}));
// Mock apiClient
vi.mock('@/services/api/client', () => ({
apiClient: {
put: vi.fn().mockResolvedValue({
data: {
id: 1,
username: 'testuser',
email: 'test@example.com',
first_name: 'Test',
last_name: 'User',
bio: 'Test bio',
},
}),
},
}));
const createTestQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false },
},
});
const TestWrapper = ({ children }: { children: React.ReactNode }) => {
const queryClient = createTestQueryClient();
return (
<QueryClientProvider client={queryClient}>
<ToastProvider>
<BrowserRouter>{children}</BrowserRouter>
</ToastProvider>
</QueryClientProvider>
);
};
describe('ProfileForm Component', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('renders profile form correctly', () => {
render(
<TestWrapper>
<ProfileForm />
2025-12-13 02:34:34 +00:00
</TestWrapper>,
);
expect(screen.getByText('profile.title')).toBeInTheDocument();
expect(screen.getByText('Personal Information')).toBeInTheDocument();
});
it('displays user information', () => {
render(
<TestWrapper>
<ProfileForm />
2025-12-13 02:34:34 +00:00
</TestWrapper>,
);
expect(screen.getByDisplayValue('testuser')).toBeInTheDocument();
expect(screen.getByDisplayValue('test@example.com')).toBeInTheDocument();
expect(screen.getByDisplayValue('Test')).toBeInTheDocument();
expect(screen.getByDisplayValue('User')).toBeInTheDocument();
});
it('enables editing mode when edit button is clicked', async () => {
const user = userEvent.setup();
render(
<TestWrapper>
<ProfileForm />
2025-12-13 02:34:34 +00:00
</TestWrapper>,
);
const editButton = screen.getByText('profile.edit');
await user.click(editButton);
// Les champs devraient être éditables
const usernameInput = screen.getByDisplayValue('testuser');
expect(usernameInput).not.toBeDisabled();
});
it('validates form fields', async () => {
const user = userEvent.setup();
render(
<TestWrapper>
<ProfileForm />
2025-12-13 02:34:34 +00:00
</TestWrapper>,
);
const editButton = screen.getByText('profile.edit');
await user.click(editButton);
// Vider le champ username
const usernameInput = screen.getByDisplayValue('testuser');
await user.clear(usernameInput);
await user.type(usernameInput, 'ab'); // Trop court
// Vider le champ email
const emailInput = screen.getByDisplayValue('test@example.com');
await user.clear(emailInput);
await user.type(emailInput, 'invalid-email');
// Soumettre le formulaire
const saveButton = screen.getByText('profile.save');
await user.click(saveButton);
// Attendre que les erreurs de validation apparaissent
await waitFor(() => {
2025-12-13 02:34:34 +00:00
expect(
screen.getByText(
/Le nom d'utilisateur doit contenir au moins 3 caractères/,
),
).toBeInTheDocument();
});
});
it('allows form submission with valid data', async () => {
const user = userEvent.setup();
render(
<TestWrapper>
<ProfileForm />
2025-12-13 02:34:34 +00:00
</TestWrapper>,
);
const editButton = screen.getByText('profile.edit');
await user.click(editButton);
const usernameInput = screen.getByDisplayValue('testuser');
expect(usernameInput).not.toBeDisabled();
2025-12-13 02:34:34 +00:00
await user.clear(usernameInput);
await user.type(usernameInput, 'newusername');
const saveButton = screen.getByText('profile.save');
expect(saveButton).toBeInTheDocument();
expect(saveButton).not.toBeDisabled();
});
it('cancels editing and resets form', async () => {
const user = userEvent.setup();
render(
<TestWrapper>
<ProfileForm />
2025-12-13 02:34:34 +00:00
</TestWrapper>,
);
const editButton = screen.getByText('profile.edit');
await user.click(editButton);
const usernameInput = screen.getByDisplayValue('testuser');
await user.clear(usernameInput);
await user.type(usernameInput, 'modified');
const cancelButton = screen.getByText('profile.cancel');
await user.click(cancelButton);
// Le formulaire devrait être réinitialisé
await waitFor(() => {
expect(screen.getByDisplayValue('testuser')).toBeInTheDocument();
});
// Les champs devraient être désactivés
expect(usernameInput).toBeDisabled();
});
it('handles avatar upload', async () => {
const user = userEvent.setup();
render(
<TestWrapper>
<ProfileForm />
2025-12-13 02:34:34 +00:00
</TestWrapper>,
);
const editButton = screen.getByText('profile.edit');
await user.click(editButton);
// Trouver le bouton d'upload d'avatar
const avatarButton = screen.getByText('profile.avatar.changePhoto');
expect(avatarButton).toBeInTheDocument();
});
});