test(7.3): add tests for Calendar pages
- CalendarPage: page render, tree/view/detail panes, MonthView default, mobile panes - CalendarKanban: page render, kanban board, task columns, error handling All 13 calendar tests passing.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
|
||||
vi.mock('@/api/calendar', () => ({
|
||||
fetchKanbanBoard: vi.fn().mockResolvedValue({
|
||||
open: [
|
||||
{ id: 'e1', calendar_id: 'cal1', entry_type: 'task', subtype: 'normal', title: 'Recherche', all_day: false, priority: 'medium', status: 'open', created_by: 'u1', due_date: '2024-07-01T00:00:00Z' },
|
||||
],
|
||||
in_progress: [
|
||||
{ id: 'e2', calendar_id: 'cal1', entry_type: 'task', subtype: 'normal', title: 'Implementation', all_day: false, priority: 'high', status: 'in_progress', created_by: 'u1', due_date: '2024-07-02T00:00:00Z' },
|
||||
],
|
||||
done: [
|
||||
{ id: 'e3', calendar_id: 'cal1', entry_type: 'task', subtype: 'normal', title: 'Tests', all_day: false, priority: 'low', status: 'done', created_by: 'u1', due_date: '2024-07-03T00:00:00Z' },
|
||||
],
|
||||
cancelled: [],
|
||||
}),
|
||||
updateEntry: vi.fn().mockResolvedValue({ id: 'e1', status: 'in_progress' }),
|
||||
}));
|
||||
|
||||
vi.mock('@/components/calendar/KanbanBoard', () => ({
|
||||
KanbanBoard: ({ board, loading }: any) => (
|
||||
<div data-testid="kanban-board-stub">
|
||||
{loading ? 'Loading...' : `Open: ${board.open.length}, In Progress: ${board.in_progress.length}, Done: ${board.done.length}`}
|
||||
</div>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('@/components/calendar/TaskDetailPanel', () => ({
|
||||
TaskDetailPanel: () => <div data-testid="task-detail-panel-stub">TaskDetailPanel</div>,
|
||||
}));
|
||||
|
||||
import { CalendarKanbanPage } from '@/pages/CalendarKanban';
|
||||
|
||||
describe('CalendarKanbanPage', () => {
|
||||
it('renders kanban page', async () => {
|
||||
render(<CalendarKanbanPage />);
|
||||
expect(screen.getByTestId('kanban-page')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders kanban board component', async () => {
|
||||
render(<CalendarKanbanPage />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('kanban-board-stub')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders board with tasks after loading', async () => {
|
||||
render(<CalendarKanbanPage />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/Open: 1, In Progress: 1, Done: 1/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders page title', async () => {
|
||||
render(<CalendarKanbanPage />);
|
||||
expect(screen.getByTestId('kanban-page')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render error when load succeeds', async () => {
|
||||
render(<CalendarKanbanPage />);
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('kanban-error')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,109 @@
|
||||
import React from 'react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
|
||||
vi.mock('@/api/calendar', () => ({
|
||||
fetchCalendars: vi.fn().mockResolvedValue([
|
||||
{ id: 'cal1', name: 'Personal', type: 'personal', color: '#3b82f6', owner_id: 'u1', shared: false, share_permissions: [] },
|
||||
{ id: 'cal2', name: 'Team', type: 'team', color: '#10b981', owner_id: 'u1', shared: true, share_permissions: [] },
|
||||
]),
|
||||
createCalendar: vi.fn().mockResolvedValue({ id: 'cal3', name: 'New', type: 'personal', color: '#000', owner_id: 'u1', shared: false, share_permissions: [] }),
|
||||
listEntries: vi.fn().mockResolvedValue([
|
||||
{ id: 'e1', calendar_id: 'cal1', entry_type: 'appointment', subtype: 'normal', title: 'Team Meeting', all_day: false, priority: 'medium', status: 'open', start: '2024-07-01T10:00:00Z', end: '2024-07-01T11:00:00Z', created_by: 'u1' },
|
||||
]),
|
||||
updateEntry: vi.fn().mockResolvedValue({}),
|
||||
deleteEntry: vi.fn().mockResolvedValue({}),
|
||||
}));
|
||||
|
||||
vi.mock('@/components/calendar/CalendarTree', () => ({
|
||||
CalendarTree: () => <div data-testid="calendar-tree-stub">CalendarTree</div>,
|
||||
}));
|
||||
vi.mock('@/components/calendar/MonthView', () => ({
|
||||
MonthView: () => <div data-testid="month-view-stub">MonthView</div>,
|
||||
}));
|
||||
vi.mock('@/components/calendar/WeekView', () => ({
|
||||
WeekView: () => <div data-testid="week-view-stub">WeekView</div>,
|
||||
}));
|
||||
vi.mock('@/components/calendar/DayView', () => ({
|
||||
DayView: () => <div data-testid="day-view-stub">DayView</div>,
|
||||
}));
|
||||
vi.mock('@/components/calendar/RangeView', () => ({
|
||||
RangeView: () => <div data-testid="range-view-stub">RangeView</div>,
|
||||
}));
|
||||
vi.mock('@/components/calendar/CalendarDetail', () => ({
|
||||
CalendarDetail: () => <div data-testid="calendar-detail-stub">CalendarDetail</div>,
|
||||
}));
|
||||
vi.mock('@/components/calendar/AppointmentModal', () => ({
|
||||
AppointmentModal: () => <div data-testid="appointment-modal-stub">AppointmentModal</div>,
|
||||
}));
|
||||
vi.mock('@/components/calendar/IcsControls', () => ({
|
||||
IcsControls: () => <div data-testid="ics-controls-stub">IcsControls</div>,
|
||||
}));
|
||||
vi.mock('@/components/calendar/SharingSettings', () => ({
|
||||
SharingSettings: () => <div data-testid="sharing-settings-stub">SharingSettings</div>,
|
||||
}));
|
||||
vi.mock('@/components/ui/ResizablePanel', () => ({
|
||||
ResizablePanel: ({ children, ...props }: any) => <div data-testid={props['data-testid']}>{children}</div>,
|
||||
}));
|
||||
vi.mock('@/components/ui/ConfirmDialog', () => ({
|
||||
ConfirmDialog: () => null,
|
||||
}));
|
||||
vi.mock('@/components/ui/Toast', () => ({
|
||||
useToast: () => ({ success: vi.fn(), error: vi.fn(), info: vi.fn() }),
|
||||
}));
|
||||
|
||||
import { CalendarPage } from '@/pages/Calendar';
|
||||
|
||||
describe('CalendarPage', () => {
|
||||
it('renders calendar page container', async () => {
|
||||
render(<CalendarPage />);
|
||||
expect(screen.getByTestId('calendar-page')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders calendar tree pane', async () => {
|
||||
render(<CalendarPage />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('calendar-tree-pane')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders calendar view pane', async () => {
|
||||
render(<CalendarPage />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('calendar-view-pane')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders calendar detail pane', async () => {
|
||||
render(<CalendarPage />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('calendar-detail-pane')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders CalendarTree component', async () => {
|
||||
render(<CalendarPage />);
|
||||
// CalendarTree is rendered inside both desktop and mobile panes
|
||||
await waitFor(() => {
|
||||
expect(screen.getAllByTestId('calendar-tree-stub').length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('renders MonthView by default', async () => {
|
||||
render(<CalendarPage />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('month-view-stub')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders mobile calendar tree pane', async () => {
|
||||
render(<CalendarPage />);
|
||||
expect(screen.getByTestId('mobile-calendar-tree-pane')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders mobile calendar view pane only after navigation', async () => {
|
||||
render(<CalendarPage />);
|
||||
// Mobile view starts on 'tree', so view pane should not be visible initially
|
||||
expect(screen.queryByTestId('mobile-calendar-view-pane')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user