veza/apps/web/src/features/tracks/components/CommentSection.test.tsx

279 lines
6.7 KiB
TypeScript
Raw Normal View History

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { CommentSection } from './CommentSection';
2025-12-13 02:34:34 +00:00
import {
getComments,
createComment,
CommentError,
} from '../services/commentService';
import { useAuthStore } from '@/features/auth/store/authStore';
import { useToast } from '@/hooks/useToast';
import type { TrackComment } from '../services/commentService';
// Mock dependencies
vi.mock('../services/commentService');
vi.mock('@/features/auth/store/authStore');
vi.mock('@/hooks/useToast');
describe('CommentSection', () => {
const mockToast = {
success: vi.fn(),
error: vi.fn(),
warning: vi.fn(),
info: vi.fn(),
toast: vi.fn(),
};
const mockUser = {
id: 123,
username: 'testuser',
email: 'test@example.com',
};
const mockComments: TrackComment[] = [
{
id: 1,
track_id: 1,
2025-12-22 21:00:50 +00:00
creator_id: 123,
content: 'Great track!',
is_edited: false,
created_at: '2024-01-01T00:00:00Z',
updated_at: '2024-01-01T00:00:00Z',
user: {
id: 123,
username: 'testuser',
},
},
{
id: 2,
track_id: 1,
2025-12-22 21:00:50 +00:00
creator_id: 456,
content: 'Amazing!',
is_edited: false,
created_at: '2024-01-02T00:00:00Z',
updated_at: '2024-01-02T00:00:00Z',
user: {
id: 456,
username: 'otheruser',
},
},
];
beforeEach(() => {
vi.clearAllMocks();
vi.mocked(useAuthStore).mockReturnValue({
user: mockUser,
isAuthenticated: true,
isLoading: false,
error: null,
login: vi.fn(),
register: vi.fn(),
logout: vi.fn(),
refreshUser: vi.fn(),
clearError: vi.fn(),
setLoading: vi.fn(),
checkAuthStatus: vi.fn(),
});
vi.mocked(useToast).mockReturnValue(mockToast);
});
afterEach(() => {
vi.restoreAllMocks();
});
it('should render comment section', async () => {
vi.mocked(getComments).mockResolvedValue({
comments: mockComments,
total: 2,
page: 1,
limit: 20,
});
render(<CommentSection trackId={1} />);
await waitFor(() => {
expect(screen.getByText('Commentaires (2)')).toBeInTheDocument();
});
});
it('should display loading state', () => {
vi.mocked(getComments).mockImplementation(
() =>
new Promise((resolve) => {
setTimeout(() => {
resolve({
comments: [],
total: 0,
page: 1,
limit: 20,
});
}, 100);
2025-12-13 02:34:34 +00:00
}),
);
render(<CommentSection trackId={1} />);
expect(screen.getByRole('status')).toBeInTheDocument();
});
it('should display empty state when no comments', async () => {
vi.mocked(getComments).mockResolvedValue({
comments: [],
total: 0,
page: 1,
limit: 20,
});
render(<CommentSection trackId={1} />);
await waitFor(() => {
2025-12-13 02:34:34 +00:00
expect(
screen.getByText(/aucun commentaire pour le moment/i),
).toBeInTheDocument();
});
});
it('should display comments', async () => {
vi.mocked(getComments).mockResolvedValue({
comments: mockComments,
total: 2,
page: 1,
limit: 20,
});
render(<CommentSection trackId={1} />);
await waitFor(() => {
expect(screen.getByText('Great track!')).toBeInTheDocument();
expect(screen.getByText('Amazing!')).toBeInTheDocument();
});
});
it('should create a new comment', async () => {
const user = userEvent.setup();
const newComment: TrackComment = {
id: 3,
track_id: 1,
2025-12-22 21:00:50 +00:00
creator_id: 123,
content: 'New comment',
is_edited: false,
created_at: '2024-01-03T00:00:00Z',
updated_at: '2024-01-03T00:00:00Z',
user: {
id: 123,
username: 'testuser',
},
};
vi.mocked(getComments).mockResolvedValue({
comments: mockComments,
total: 2,
page: 1,
limit: 20,
});
vi.mocked(createComment).mockResolvedValue(newComment);
render(<CommentSection trackId={1} />);
await waitFor(() => {
2025-12-13 02:34:34 +00:00
expect(
screen.getByPlaceholderText('Écrivez un commentaire...'),
).toBeInTheDocument();
});
const textarea = screen.getByPlaceholderText('Écrivez un commentaire...');
await user.type(textarea, 'New comment');
const submitButton = screen.getByRole('button', { name: /commenter/i });
await user.click(submitButton);
await waitFor(() => {
expect(createComment).toHaveBeenCalledWith(1, 'New comment', undefined);
expect(mockToast.success).toHaveBeenCalledWith('Commentaire ajouté');
});
});
it('should load more comments', async () => {
const user = userEvent.setup();
const moreComments: TrackComment[] = [
{
id: 3,
track_id: 1,
2025-12-22 21:00:50 +00:00
creator_id: 123,
content: 'More comments',
is_edited: false,
created_at: '2024-01-03T00:00:00Z',
updated_at: '2024-01-03T00:00:00Z',
user: {
id: 123,
username: 'testuser',
},
},
];
vi.mocked(getComments)
.mockResolvedValueOnce({
comments: mockComments,
total: 3,
page: 1,
limit: 20,
})
.mockResolvedValueOnce({
comments: moreComments,
total: 3,
page: 2,
limit: 20,
});
render(<CommentSection trackId={1} />);
await waitFor(() => {
expect(screen.getByText('Great track!')).toBeInTheDocument();
});
2025-12-13 02:34:34 +00:00
const loadMoreButton = screen.getByRole('button', {
name: /charger plus/i,
});
await user.click(loadMoreButton);
await waitFor(() => {
expect(getComments).toHaveBeenCalledWith(1, 2, 20);
});
});
it('should handle error when loading comments', async () => {
const error = new CommentError('Failed to load comments', 'NETWORK', true);
vi.mocked(getComments).mockRejectedValue(error);
render(<CommentSection trackId={1} />);
await waitFor(() => {
expect(mockToast.error).toHaveBeenCalledWith('Failed to load comments');
});
});
it('should refresh comments', async () => {
const user = userEvent.setup();
vi.mocked(getComments).mockResolvedValue({
comments: mockComments,
total: 2,
page: 1,
limit: 20,
});
render(<CommentSection trackId={1} />);
await waitFor(() => {
expect(screen.getByText('Great track!')).toBeInTheDocument();
});
const refreshButton = screen.getByRole('button', { name: /actualiser/i });
await user.click(refreshButton);
await waitFor(() => {
expect(getComments).toHaveBeenCalledWith(1, 1, 20);
});
});
});