223 lines
5.8 KiB
TypeScript
223 lines
5.8 KiB
TypeScript
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 />
|
|
</TestWrapper>,
|
|
);
|
|
|
|
expect(screen.getByText('profile.title')).toBeInTheDocument();
|
|
expect(screen.getByText('Personal Information')).toBeInTheDocument();
|
|
});
|
|
|
|
it('displays user information', () => {
|
|
render(
|
|
<TestWrapper>
|
|
<ProfileForm />
|
|
</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 />
|
|
</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 />
|
|
</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(() => {
|
|
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 />
|
|
</TestWrapper>,
|
|
);
|
|
|
|
const editButton = screen.getByText('profile.edit');
|
|
await user.click(editButton);
|
|
|
|
const usernameInput = screen.getByDisplayValue('testuser');
|
|
expect(usernameInput).not.toBeDisabled();
|
|
|
|
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 />
|
|
</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 />
|
|
</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();
|
|
});
|
|
});
|