/** * Tests for Home Page * Tests for the new PragmaStack landing page */ import { render, screen, within, fireEvent } from '@testing-library/react'; import Home from '@/app/[locale]/page'; // Mock Next.js components jest.mock('next/image', () => ({ __esModule: true, default: (props: any) => { // eslint-disable-next-line @next/next/no-img-element return ; }, })); jest.mock('next/link', () => ({ __esModule: true, default: ({ children, href, ...props }: any) => { return ( {children} ); }, })); // Mock framer-motion to avoid animation issues in tests jest.mock('framer-motion', () => ({ motion: { div: ({ children, ...props }: any) =>
{children}
, h1: ({ children, ...props }: any) =>

{children}

, p: ({ children, ...props }: any) =>

{children}

, section: ({ children, ...props }: any) =>
{children}
, }, AnimatePresence: ({ children }: any) => <>{children}, useInView: () => true, // Always in view for tests })); // Mock react-syntax-highlighter to avoid ESM issues jest.mock('react-syntax-highlighter', () => ({ Prism: ({ children, ...props }: any) =>
{children}
, })); jest.mock('react-syntax-highlighter/dist/esm/styles/prism', () => ({ vscDarkPlus: {}, })); // Mock auth hooks jest.mock('@/lib/api/hooks/useAuth', () => ({ useIsAuthenticated: jest.fn(() => false), useLogout: jest.fn(() => ({ mutate: jest.fn(), })), })); // Mock Theme components jest.mock('@/components/theme', () => ({ ThemeToggle: () =>
Theme Toggle
, })); // Mock LocaleSwitcher jest.mock('@/components/i18n', () => ({ LocaleSwitcher: () =>
Locale Switcher
, })); // Mock DemoCredentialsModal jest.mock('@/components/home/DemoCredentialsModal', () => ({ DemoCredentialsModal: ({ open, onClose }: any) => open ? (
) : null, })); describe('HomePage', () => { describe('Page Structure', () => { it('renders without crashing', () => { render(); expect(screen.getByRole('banner')).toBeInTheDocument(); // header expect(screen.getByRole('main')).toBeInTheDocument(); expect(screen.getByRole('contentinfo')).toBeInTheDocument(); // footer }); it('renders header with logo', () => { render(); const header = screen.getByRole('banner'); expect(within(header).getByText('PragmaStack')).toBeInTheDocument(); }); it('renders footer with copyright', () => { render(); const footer = screen.getByRole('contentinfo'); expect(within(footer).getByText(/PragmaStack. MIT Licensed/i)).toBeInTheDocument(); }); }); describe('Hero Section', () => { it('renders main headline', () => { render(); expect(screen.getAllByText(/Everything You Need to Build/i)[0]).toBeInTheDocument(); expect(screen.getAllByText(/Modern Web Applications/i)[0]).toBeInTheDocument(); }); it('renders production-ready messaging', () => { render(); expect(screen.getByText(/Opinionated, secure, and production-ready/i)).toBeInTheDocument(); }); it('renders badges', () => { render(); expect(screen.getByText('MIT Licensed')).toBeInTheDocument(); expect(screen.getByText('OAuth 2.0 + i18n')).toBeInTheDocument(); expect(screen.getByText('Pragmatic by Design')).toBeInTheDocument(); }); }); describe('Context Section', () => { it('renders what you get message', () => { render(); expect(screen.getByText(/Stop Reinventing the Wheel/i)).toBeInTheDocument(); }); it('renders key features', () => { render(); expect(screen.getAllByText(/Clone & Deploy in < 5 minutes/i)[0]).toBeInTheDocument(); expect(screen.getAllByText(/OAuth 2\.0 \+ Social Login/i)[0]).toBeInTheDocument(); expect(screen.getAllByText(/i18n Ready \(EN, IT\)/i)[0]).toBeInTheDocument(); expect(screen.getAllByText(/Zero Commercial Dependencies/i)[0]).toBeInTheDocument(); }); }); describe('Feature Grid', () => { it('renders comprehensive features heading', () => { render(); expect(screen.getByText(/Comprehensive Features, No Assembly Required/i)).toBeInTheDocument(); }); it('renders all 6 feature cards', () => { render(); expect(screen.getAllByText('Authentication & Security')[0]).toBeInTheDocument(); expect(screen.getAllByText('Multi-Tenant Organizations')[0]).toBeInTheDocument(); expect(screen.getAllByText('Admin Dashboard')[0]).toBeInTheDocument(); expect(screen.getAllByText('Complete Documentation')[0]).toBeInTheDocument(); expect(screen.getAllByText('Production Ready')[0]).toBeInTheDocument(); expect(screen.getAllByText('Developer Experience')[0]).toBeInTheDocument(); }); it('has CTAs for each feature', () => { render(); expect(screen.getByRole('link', { name: /View Auth Flow/i })).toHaveAttribute( 'href', '/login' ); expect(screen.getByRole('link', { name: /See Organizations/i })).toHaveAttribute( 'href', '/admin/organizations' ); expect(screen.getByRole('link', { name: /Try Admin Panel/i })).toHaveAttribute( 'href', '/admin' ); }); }); describe('Demo Section', () => { it('renders demo section heading', () => { render(); expect(screen.getByText(/See It In Action/i)).toBeInTheDocument(); }); it('renders demo cards', () => { render(); expect(screen.getAllByText('Design System Hub')[0]).toBeInTheDocument(); expect(screen.getAllByText('Authentication Flow')[0]).toBeInTheDocument(); expect(screen.getAllByText('User Dashboard')[0]).toBeInTheDocument(); // Admin Dashboard appears in both Feature Grid and Demo Section, so use getAllByText const adminDashboards = screen.getAllByText('Admin Dashboard'); expect(adminDashboards.length).toBeGreaterThanOrEqual(1); }); it('displays demo credentials', () => { render(); const credentials = screen.getAllByText(/Demo Credentials:/i); expect(credentials.length).toBeGreaterThan(0); }); }); describe('Tech Stack Section', () => { it('renders tech stack heading', () => { render(); expect(screen.getByText(/A Stack You Can Trust/i)).toBeInTheDocument(); }); it('renders all technologies', () => { render(); expect(screen.getAllByText('FastAPI')[0]).toBeInTheDocument(); expect(screen.getAllByText('Next.js 16')[0]).toBeInTheDocument(); expect(screen.getAllByText('PostgreSQL')[0]).toBeInTheDocument(); expect(screen.getAllByText('TypeScript')[0]).toBeInTheDocument(); expect(screen.getAllByText('OAuth 2.0')[0]).toBeInTheDocument(); expect(screen.getAllByText('next-intl')[0]).toBeInTheDocument(); expect(screen.getAllByText('Playwright')[0]).toBeInTheDocument(); expect(screen.getAllByText('pytest')[0]).toBeInTheDocument(); }); }); describe('Philosophy Section', () => { it('renders why this template exists', () => { render(); expect(screen.getByText(/Why PragmaStack\?/i)).toBeInTheDocument(); }); it('renders what you wont find section', () => { render(); expect(screen.getByText(/What You Won't Find Here/i)).toBeInTheDocument(); expect(screen.getAllByText(/Vendor lock-in/i)[0]).toBeInTheDocument(); }); it('renders what you will find section', () => { render(); expect(screen.getByText(/What You Will Find/i)).toBeInTheDocument(); expect(screen.getByText(/Pragmatic Speed: Ship features, not config/i)).toBeInTheDocument(); }); }); describe('Quick Start Section', () => { it('renders quick start heading', () => { render(); expect(screen.getByText(/5-Minute Setup/i)).toBeInTheDocument(); }); }); describe('CTA Section', () => { it('renders final CTA', () => { render(); expect(screen.getByText(/Start Building,/i)).toBeInTheDocument(); expect(screen.getByText(/Not Boilerplating/i)).toBeInTheDocument(); }); it('has GitHub link', () => { render(); const githubLinks = screen.getAllByRole('link', { name: /GitHub/i }); expect(githubLinks.length).toBeGreaterThan(0); expect(githubLinks[0]).toHaveAttribute('href', expect.stringContaining('github.com')); }); }); describe('Navigation Links', () => { it('has login link', () => { render(); const loginLinks = screen.getAllByRole('link', { name: /Login/i }); expect(loginLinks.some((link) => link.getAttribute('href') === '/login')).toBe(true); }); it('has design system link', () => { render(); const devLinks = screen.getAllByRole('link', { name: /Design System/i }); expect(devLinks.some((link) => link.getAttribute('href') === '/dev')).toBe(true); }); it('has admin demo link', () => { render(); const adminLinks = screen.getAllByRole('link', { name: /Admin/i }); expect(adminLinks.some((link) => link.getAttribute('href') === '/admin')).toBe(true); }); }); describe('Demo Modal', () => { it('demo modal is initially closed', () => { render(); expect(screen.queryByTestId('demo-modal')).not.toBeInTheDocument(); }); it('opens demo modal when Try Demo button is clicked in header', () => { render(); const tryDemoButtons = screen.getAllByRole('button', { name: /try demo/i }); // Click the first Try Demo button (from header) fireEvent.click(tryDemoButtons[0]); expect(screen.getByTestId('demo-modal')).toBeInTheDocument(); }); it('closes demo modal when close button is clicked', () => { render(); // Open the modal const tryDemoButtons = screen.getAllByRole('button', { name: /try demo/i }); fireEvent.click(tryDemoButtons[0]); expect(screen.getByTestId('demo-modal')).toBeInTheDocument(); // Close the modal const closeButtons = screen.getAllByRole('button', { name: /close/i }); const modalCloseButton = closeButtons.find((btn) => btn.textContent === 'Close'); if (modalCloseButton) { fireEvent.click(modalCloseButton); } }); }); describe('Accessibility', () => { it('has proper heading hierarchy', () => { render(); const main = screen.getByRole('main'); const headings = within(main).getAllByRole('heading'); expect(headings.length).toBeGreaterThan(0); }); it('has external links with proper attributes', () => { render(); const githubLinks = screen.getAllByRole('link', { name: /GitHub/i }); const externalLink = githubLinks.find((link) => link.getAttribute('href')?.includes('github.com') ); expect(externalLink).toHaveAttribute('target', '_blank'); expect(externalLink).toHaveAttribute('rel', 'noopener noreferrer'); }); }); });