219 lines
5.7 KiB
TypeScript
219 lines
5.7 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 { 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,
|
||
|
|
}),
|
||
|
|
}));
|
||
|
|
|
||
|
|
// Mock useAuthStore
|
||
|
|
const mockUser = {
|
||
|
|
id: 1,
|
||
|
|
username: 'testuser',
|
||
|
|
email: 'test@example.com',
|
||
|
|
first_name: 'Test',
|
||
|
|
last_name: 'User',
|
||
|
|
bio: 'Test bio',
|
||
|
|
};
|
||
|
|
|
||
|
|
const mockRefreshUser = vi.fn();
|
||
|
|
|
||
|
|
vi.mock('@/stores/auth', () => ({
|
||
|
|
useAuthStore: () => ({
|
||
|
|
user: mockUser,
|
||
|
|
refreshUser: mockRefreshUser,
|
||
|
|
isAuthenticated: true,
|
||
|
|
}),
|
||
|
|
}));
|
||
|
|
|
||
|
|
// Mock useUIStore
|
||
|
|
vi.mock('@/stores/ui', () => ({
|
||
|
|
useUIStore: () => ({
|
||
|
|
addNotification: vi.fn(),
|
||
|
|
}),
|
||
|
|
}));
|
||
|
|
|
||
|
|
// Mock apiService
|
||
|
|
vi.mock('@/services/api', () => ({
|
||
|
|
apiService: {
|
||
|
|
updateUser: vi.fn().mockResolvedValue({
|
||
|
|
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}>
|
||
|
|
<BrowserRouter>{children}</BrowserRouter>
|
||
|
|
</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('profile.personalInfo')).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();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|