Files
fotospiel-app/resources/js/admin/mobile/__tests__/EventsPage.test.tsx
Codex Agent e1221e0466
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled
Clarify photo task wording in admin UI
2026-01-20 08:49:34 +01:00

175 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React from 'react';
import { describe, expect, it, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
const navigateMock = vi.fn();
const authState = {
user: { role: 'tenant_admin' },
};
vi.mock('react-router-dom', () => ({
useNavigate: () => navigateMock,
}));
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => {
const translations: Record<string, string> = {
'events.list.title': 'Your events',
'events.list.subtitle': 'Plan memorable moments. Manage everything around your events here.',
'events.list.overview.title': 'Overview',
'events.list.overview.empty': 'No events yet create your first one to get started.',
'events.list.filters.all': 'All',
'events.list.filters.upcoming': 'Upcoming',
'events.list.filters.draft': 'Draft',
'events.list.filters.past': 'Past',
'events.list.actions.create': 'New event',
'events.list.actions.open': 'Open event',
'events.list.empty.filtered': 'No events match this filter.',
'events.list.empty.filteredHint': 'Try a different status or clear your search.',
'events.list.stats.photos': 'Photos',
'events.list.stats.guests': 'Guests',
'events.list.stats.tasks': 'Photo tasks',
'events.workspace.fields.status': 'Status',
'events.detail.pickEvent': 'Select event',
'events.detail.dateTbd': 'Date tbd',
'events.detail.locationPlaceholder': 'Location',
'events.placeholders.untitled': 'Untitled event',
'events.errors.loadFailed': 'Event konnte nicht geladen werden.',
};
return translations[key] ?? key;
},
i18n: {
language: 'en',
},
}),
}));
vi.mock('../../api', () => ({
getEvents: vi.fn().mockResolvedValue([
{
id: 1,
name: 'Demo Event',
slug: 'demo-event',
event_date: '2026-02-19',
settings: {},
},
]),
}));
vi.mock('../../auth/tokens', () => ({
isAuthError: () => false,
}));
vi.mock('../../auth/context', () => ({
useAuth: () => authState,
}));
vi.mock('../../lib/apiError', () => ({
getApiErrorMessage: () => 'error',
}));
vi.mock('../../lib/eventFilters', () => ({
buildEventStatusCounts: () => ({ all: 1, upcoming: 1, draft: 0, past: 0 }),
filterEventsByStatus: (events: any[]) => events,
resolveEventStatusKey: () => 'upcoming',
}));
vi.mock('../../lib/eventListStats', () => ({
buildEventListStats: () => ({ photos: 2, guests: 3, tasks: 4 }),
}));
vi.mock('../hooks/useBackNavigation', () => ({
useBackNavigation: () => undefined,
}));
vi.mock('../components/MobileShell', () => ({
MobileShell: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
HeaderActionButton: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}));
vi.mock('../components/Primitives', () => ({
PillBadge: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
CTAButton: ({ label }: { label: string }) => <button type="button">{label}</button>,
FloatingActionButton: ({ label }: { label: string }) => <div>{label}</div>,
SkeletonCard: () => <div>Loading...</div>,
}));
vi.mock('../components/FormControls', () => ({
MobileInput: (props: React.InputHTMLAttributes<HTMLInputElement>) => <input {...props} />,
}));
vi.mock('@tamagui/card', () => ({
Card: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}));
vi.mock('@tamagui/scroll-view', () => ({
ScrollView: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}));
vi.mock('@tamagui/react-native-web-lite', () => ({
Pressable: ({ children, onPress }: { children: React.ReactNode; onPress?: () => void }) => (
<button type="button" onClick={onPress}>
{children}
</button>
),
}));
vi.mock('@tamagui/toggle-group', () => ({
ToggleGroup: Object.assign(({ children }: { children: React.ReactNode }) => <div>{children}</div>, {
Item: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}),
}));
vi.mock('@tamagui/separator', () => ({
Separator: () => <div />,
}));
vi.mock('@tamagui/stacks', () => ({
YStack: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
XStack: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}));
vi.mock('@tamagui/text', () => ({
SizableText: ({ children }: { children: React.ReactNode }) => <span>{children}</span>,
}));
vi.mock('../theme', () => ({
useAdminTheme: () => ({
text: '#111827',
muted: '#6b7280',
subtle: '#94a3b8',
border: '#e5e7eb',
primary: '#ff5a5f',
danger: '#dc2626',
surface: '#ffffff',
surfaceMuted: '#f9fafb',
accentSoft: '#eef2ff',
accent: '#6366f1',
shadow: 'rgba(15,23,42,0.12)',
}),
}));
import MobileEventsPage from '../EventsPage';
describe('MobileEventsPage', () => {
it('renders filters and event list', async () => {
render(<MobileEventsPage />);
expect(await screen.findByText('Overview')).toBeInTheDocument();
expect(screen.getByText('Status')).toBeInTheDocument();
expect(screen.getByText('Demo Event')).toBeInTheDocument();
});
it('hides create actions for members', async () => {
authState.user = { role: 'member' };
render(<MobileEventsPage />);
expect(await screen.findByText('Demo Event')).toBeInTheDocument();
expect(screen.queryByText('New event')).not.toBeInTheDocument();
authState.user = { role: 'tenant_admin' };
});
});