Files
fast-next-template/frontend/tests/app/admin/layout.test.tsx
Felipe Cardoso 9c72fe87f9 Add admin UX improvements, constants refactor, and comprehensive tests
- Introduced constants for admin hooks: `STATS_FETCH_LIMIT`, `DEFAULT_PAGE_LIMIT`, and `STATS_REFETCH_INTERVAL` to enhance readability and maintainability.
- Updated query guards to ensure data fetching is restricted to superusers.
- Enhanced accessibility across admin components by adding `aria-hidden` attributes and improving focus-visible styles.
- Simplified `useAdminStats`, `useAdminUsers`, and `useAdminOrganizations` with shared constants.
- Added 403 Forbidden page with proper structure, styling, and tests.
- Implemented new tests for admin hooks, DashboardStats, AdminLayout, and ForbiddenPage for better coverage.
2025-11-06 10:08:43 +01:00

170 lines
4.6 KiB
TypeScript

/**
* Tests for Admin Layout
* Verifies layout rendering, auth guard, and accessibility features
*/
import { render, screen } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import AdminLayout from '@/app/admin/layout';
import { useAuth } from '@/lib/auth/AuthContext';
// Mock dependencies
jest.mock('@/lib/auth/AuthContext');
jest.mock('@/components/layout/Header', () => ({
Header: () => <header data-testid="header">Header</header>,
}));
jest.mock('@/components/layout/Footer', () => ({
Footer: () => <footer data-testid="footer">Footer</footer>,
}));
jest.mock('@/components/admin/AdminSidebar', () => ({
AdminSidebar: () => <aside data-testid="sidebar">Sidebar</aside>,
}));
jest.mock('@/components/admin/Breadcrumbs', () => ({
Breadcrumbs: () => <div data-testid="breadcrumbs">Breadcrumbs</div>,
}));
// Mock next/navigation
jest.mock('next/navigation', () => ({
useRouter: () => ({
push: jest.fn(),
replace: jest.fn(),
prefetch: jest.fn(),
}),
usePathname: () => '/admin',
}));
const mockUseAuth = useAuth as jest.MockedFunction<typeof useAuth>;
describe('AdminLayout', () => {
let queryClient: QueryClient;
beforeEach(() => {
queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
},
},
});
jest.clearAllMocks();
});
const wrapper = ({ children }: { children: React.ReactNode }) => (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
it('renders layout with all components for superuser', () => {
mockUseAuth.mockReturnValue({
user: { is_superuser: true } as any,
isAuthenticated: true,
isLoading: false,
login: jest.fn(),
logout: jest.fn(),
});
render(
<AdminLayout>
<div>Test Content</div>
</AdminLayout>,
{ wrapper }
);
expect(screen.getByTestId('header')).toBeInTheDocument();
expect(screen.getByTestId('footer')).toBeInTheDocument();
expect(screen.getByTestId('sidebar')).toBeInTheDocument();
expect(screen.getByTestId('breadcrumbs')).toBeInTheDocument();
expect(screen.getByText('Test Content')).toBeInTheDocument();
});
it('renders skip link with correct attributes', () => {
mockUseAuth.mockReturnValue({
user: { is_superuser: true } as any,
isAuthenticated: true,
isLoading: false,
login: jest.fn(),
logout: jest.fn(),
});
render(
<AdminLayout>
<div>Test Content</div>
</AdminLayout>,
{ wrapper }
);
const skipLink = screen.getByText('Skip to main content');
expect(skipLink).toBeInTheDocument();
expect(skipLink).toHaveAttribute('href', '#main-content');
expect(skipLink).toHaveClass('sr-only');
});
it('renders main element with id', () => {
mockUseAuth.mockReturnValue({
user: { is_superuser: true } as any,
isAuthenticated: true,
isLoading: false,
login: jest.fn(),
logout: jest.fn(),
});
const { container } = render(
<AdminLayout>
<div>Test Content</div>
</AdminLayout>,
{ wrapper }
);
const mainElement = container.querySelector('#main-content');
expect(mainElement).toBeInTheDocument();
expect(mainElement?.tagName).toBe('MAIN');
});
it('renders children inside main content area', () => {
mockUseAuth.mockReturnValue({
user: { is_superuser: true } as any,
isAuthenticated: true,
isLoading: false,
login: jest.fn(),
logout: jest.fn(),
});
render(
<AdminLayout>
<div data-testid="child-content">Child Content</div>
</AdminLayout>,
{ wrapper }
);
const mainElement = screen.getByTestId('child-content').closest('main');
expect(mainElement).toHaveAttribute('id', 'main-content');
});
it('applies correct layout structure classes', () => {
mockUseAuth.mockReturnValue({
user: { is_superuser: true } as any,
isAuthenticated: true,
isLoading: false,
login: jest.fn(),
logout: jest.fn(),
});
const { container } = render(
<AdminLayout>
<div>Test Content</div>
</AdminLayout>,
{ wrapper }
);
// Check root container has min-height class
const rootDiv = container.querySelector('.min-h-screen');
expect(rootDiv).toBeInTheDocument();
expect(rootDiv).toHaveClass('flex', 'flex-col');
// Check main content area has flex and overflow classes
const mainElement = container.querySelector('#main-content');
expect(mainElement).toHaveClass('flex-1', 'overflow-y-auto');
});
});