diff --git a/frontend/src/middleware.disabled.ts b/frontend/src/middleware.disabled.ts
deleted file mode 100644
index f801a26..0000000
--- a/frontend/src/middleware.disabled.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { NextResponse } from 'next/server';
-import type { NextRequest } from 'next/server';
-import createMiddleware from 'next-intl/middleware';
-import { routing } from './lib/i18n/routing';
-
-// Create next-intl middleware for locale handling
-const intlMiddleware = createMiddleware(routing);
-
-export function middleware(request: NextRequest) {
- const { pathname } = request.nextUrl;
-
- // Block access to /dev routes in production (handles both /dev and /[locale]/dev)
- // Match: /dev, /en/dev, /it/dev, etc.
- if (pathname === '/dev' || pathname.match(/^\/[a-z]{2}\/dev($|\/)/)) {
- const isProduction = process.env.NODE_ENV === 'production';
-
- if (isProduction) {
- // Return 404 in production
- return new NextResponse(null, { status: 404 });
- }
- }
-
- // Handle locale routing with next-intl
- return intlMiddleware(request);
-}
-
-export const config = {
- // Match all pathnames except for:
- // - API routes (/api/*)
- // - Static files (/_next/*, /favicon.ico, etc.)
- // - Files in public folder (images, fonts, etc.)
- matcher: [
- // Match all pathnames except for
- '/((?!api|_next|_vercel|.*\\..*).*)',
- // However, match all pathnames within /api/
- // that don't end with a file extension
- '/api/(.*)',
- ],
-};
diff --git a/frontend/tests/app/admin/page.test.tsx b/frontend/tests/app/admin/page.test.tsx
index 69613de..d2ae918 100644
--- a/frontend/tests/app/admin/page.test.tsx
+++ b/frontend/tests/app/admin/page.test.tsx
@@ -5,10 +5,26 @@
import { render, screen } from '@testing-library/react';
import AdminPage from '@/app/[locale]/admin/page';
-import { useAdminStats } from '@/lib/api/hooks/useAdmin';
+import { getAdminStats } from '@/lib/api/admin';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+
+// Mock the API client
+jest.mock('@/lib/api/admin');
// Mock the useAdminStats hook
-jest.mock('@/lib/api/hooks/useAdmin');
+jest.mock('@/lib/api/hooks/useAdmin', () => ({
+ useAdminStats: () => ({
+ data: {
+ totalUsers: 100,
+ activeUsers: 80,
+ totalOrganizations: 20,
+ totalSessions: 30,
+ },
+ isLoading: false,
+ isError: false,
+ error: null,
+ }),
+}));
// Mock chart components
jest.mock('@/components/charts', () => ({
@@ -22,23 +38,31 @@ jest.mock('@/components/charts', () => ({
UserStatusChart: () =>
User Status Chart
,
}));
-const mockUseAdminStats = useAdminStats as jest.MockedFunction;
+const mockGetAdminStats = getAdminStats as jest.MockedFunction;
// Helper function to render with default mocked stats
function renderWithMockedStats() {
- mockUseAdminStats.mockReturnValue({
+ mockGetAdminStats.mockResolvedValue({
data: {
- totalUsers: 100,
- activeUsers: 80,
- totalOrganizations: 20,
- totalSessions: 30,
+ user_growth: [],
+ organization_distribution: [],
+ user_status: [],
},
- isLoading: false,
- isError: false,
- error: null,
} as any);
- return render();
+ const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ retry: false,
+ },
+ },
+ });
+
+ return render(
+
+
+
+ );
}
describe('AdminPage', () => {
diff --git a/frontend/tests/app/page.test.tsx b/frontend/tests/app/page.test.tsx
index 64303ed..a303c3d 100644
--- a/frontend/tests/app/page.test.tsx
+++ b/frontend/tests/app/page.test.tsx
@@ -47,6 +47,34 @@ 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', () => {
@@ -60,7 +88,6 @@ describe('HomePage', () => {
render();
const header = screen.getByRole('banner');
expect(within(header).getByText('PragmaStack')).toBeInTheDocument();
- expect(within(header).getByText('Template')).toBeInTheDocument();
});
it('renders footer with copyright', () => {
@@ -79,30 +106,26 @@ describe('HomePage', () => {
it('renders production-ready messaging', () => {
render();
- expect(screen.getByText(/Production-ready FastAPI/i)).toBeInTheDocument();
+ expect(screen.getByText(/Opinionated, secure, and production-ready/i)).toBeInTheDocument();
});
- it('renders test coverage stats', () => {
+ it('renders badges', () => {
render();
- const coverageTexts = screen.getAllByText('97%');
- expect(coverageTexts.length).toBeGreaterThan(0);
- expect(screen.getAllByText(/Test Coverage/i)[0]).toBeInTheDocument();
- const testCountTexts = screen.getAllByText('743');
- expect(testCountTexts.length).toBeGreaterThan(0);
- expect(screen.getAllByText(/Passing Tests/i)[0]).toBeInTheDocument();
+ expect(screen.getByText('Comprehensive Tests')).toBeInTheDocument();
+ expect(screen.getByText('Pragmatic by Design')).toBeInTheDocument();
});
});
describe('Context Section', () => {
it('renders what you get message', () => {
render();
- expect(screen.getByText(/What You Get Out of the Box/i)).toBeInTheDocument();
+ 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(/97% Test Coverage \(743 tests\)/i)[0]).toBeInTheDocument();
+ expect(screen.getAllByText(/Comprehensive Test Suite/i)[0]).toBeInTheDocument();
expect(screen.getAllByText(/12\+ Documentation Guides/i)[0]).toBeInTheDocument();
expect(screen.getAllByText(/Zero Commercial Dependencies/i)[0]).toBeInTheDocument();
});
@@ -167,7 +190,7 @@ describe('HomePage', () => {
describe('Tech Stack Section', () => {
it('renders tech stack heading', () => {
render();
- expect(screen.getByText(/Modern, Type-Safe, Production-Grade Stack/i)).toBeInTheDocument();
+ expect(screen.getByText(/A Stack You Can Trust/i)).toBeInTheDocument();
});
it('renders all technologies', () => {
@@ -186,7 +209,7 @@ describe('HomePage', () => {
describe('Philosophy Section', () => {
it('renders why this template exists', () => {
render();
- expect(screen.getByText(/Why This Template Exists/i)).toBeInTheDocument();
+ expect(screen.getByText(/Why PragmaStack\?/i)).toBeInTheDocument();
});
it('renders what you wont find section', () => {
@@ -198,7 +221,7 @@ describe('HomePage', () => {
it('renders what you will find section', () => {
render();
expect(screen.getByText(/What You Will Find/i)).toBeInTheDocument();
- expect(screen.getByText(/Production patterns that actually work/i)).toBeInTheDocument();
+ expect(screen.getByText(/Pragmatic Speed: Ship features, not config/i)).toBeInTheDocument();
});
});
diff --git a/frontend/tests/components/auth/LoginForm.test.tsx b/frontend/tests/components/auth/LoginForm.test.tsx
index d16985a..856bdb0 100644
--- a/frontend/tests/components/auth/LoginForm.test.tsx
+++ b/frontend/tests/components/auth/LoginForm.test.tsx
@@ -32,11 +32,15 @@ jest.mock('@/lib/api/hooks/useAuth', () => ({
useLogin: () => mockUseLogin(),
}));
+// Mock router
// Mock router
jest.mock('next/navigation', () => ({
useRouter: () => ({
push: jest.fn(),
}),
+ useSearchParams: () => ({
+ get: jest.fn(),
+ }),
}));
// Mock auth store
diff --git a/frontend/tests/components/home/DemoCredentialsModal.test.tsx b/frontend/tests/components/home/DemoCredentialsModal.test.tsx
index aacecda..cee71bd 100644
--- a/frontend/tests/components/home/DemoCredentialsModal.test.tsx
+++ b/frontend/tests/components/home/DemoCredentialsModal.test.tsx
@@ -156,10 +156,16 @@ describe('DemoCredentialsModal', () => {
render();
const loginAsUserLink = screen.getByRole('link', { name: /login as user/i });
- expect(loginAsUserLink).toHaveAttribute('href', '/login');
+ expect(loginAsUserLink).toHaveAttribute(
+ 'href',
+ '/login?email=demo@example.com&password=Demo123!'
+ );
const loginAsAdminLink = screen.getByRole('link', { name: /login as admin/i });
- expect(loginAsAdminLink).toHaveAttribute('href', '/login');
+ expect(loginAsAdminLink).toHaveAttribute(
+ 'href',
+ '/login?email=admin@example.com&password=Admin123!'
+ );
});
it('calls onClose when login link is clicked', () => {
diff --git a/frontend/tests/components/home/Header.test.tsx b/frontend/tests/components/home/Header.test.tsx
index 9e61ea3..fd7361e 100644
--- a/frontend/tests/components/home/Header.test.tsx
+++ b/frontend/tests/components/home/Header.test.tsx
@@ -27,6 +27,24 @@ jest.mock('@/components/home/DemoCredentialsModal', () => ({
) : null,
}));
+// 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
,
+}));
+
describe('Header', () => {
it('renders logo', () => {
render(
@@ -38,7 +56,6 @@ describe('Header', () => {
);
expect(screen.getByText('PragmaStack')).toBeInTheDocument();
- expect(screen.getByText('Template')).toBeInTheDocument();
});
it('logo links to homepage', () => {
@@ -50,7 +67,7 @@ describe('Header', () => {
/>
);
- const logoLink = screen.getByRole('link', { name: /pragmastack template/i });
+ const logoLink = screen.getByRole('link', { name: /PragmaStack/i });
expect(logoLink).toHaveAttribute('href', '/');
});
diff --git a/frontend/tests/components/home/HeroSection.test.tsx b/frontend/tests/components/home/HeroSection.test.tsx
index 48c7576..2fdbd18 100644
--- a/frontend/tests/components/home/HeroSection.test.tsx
+++ b/frontend/tests/components/home/HeroSection.test.tsx
@@ -47,8 +47,8 @@ describe('HeroSection', () => {
);
expect(screen.getByText('MIT Licensed')).toBeInTheDocument();
- expect(screen.getAllByText('97% Test Coverage')[0]).toBeInTheDocument();
- expect(screen.getByText('Production Ready')).toBeInTheDocument();
+ expect(screen.getByText('Comprehensive Tests')).toBeInTheDocument();
+ expect(screen.getByText('Pragmatic by Design')).toBeInTheDocument();
});
it('renders main headline', () => {
@@ -60,8 +60,8 @@ describe('HeroSection', () => {
/>
);
- expect(screen.getAllByText(/Everything You Need to Build/i)[0]).toBeInTheDocument();
- expect(screen.getAllByText(/Modern Web Applications/i)[0]).toBeInTheDocument();
+ expect(screen.getByText(/The Pragmatic/i)).toBeInTheDocument();
+ expect(screen.getByText(/Full-Stack Template/i)).toBeInTheDocument();
});
it('renders subheadline with key messaging', () => {
@@ -73,7 +73,7 @@ describe('HeroSection', () => {
/>
);
- expect(screen.getByText(/Production-ready FastAPI \+ Next.js template/i)).toBeInTheDocument();
+ expect(screen.getByText(/Opinionated, secure, and production-ready/i)).toBeInTheDocument();
expect(screen.getByText(/Start building features on day one/i)).toBeInTheDocument();
});
@@ -118,26 +118,6 @@ describe('HeroSection', () => {
expect(componentsLink).toHaveAttribute('href', '/dev');
});
- it('displays test coverage stats', () => {
- render(
-
- );
-
- const coverageTexts = screen.getAllByText('97%');
- expect(coverageTexts.length).toBeGreaterThan(0);
-
- const testCountTexts = screen.getAllByText('743');
- expect(testCountTexts.length).toBeGreaterThan(0);
- expect(screen.getAllByText(/Passing Tests/i)[0]).toBeInTheDocument();
-
- expect(screen.getByText('0')).toBeInTheDocument();
- expect(screen.getByText(/Flaky Tests/i)).toBeInTheDocument();
- });
-
it('calls onOpenDemoModal when Try Live Demo button is clicked', () => {
const mockOnOpenDemoModal = jest.fn();
render();
diff --git a/frontend/tests/components/home/StatsSection.test.tsx b/frontend/tests/components/home/StatsSection.test.tsx
index c23f1e3..4ecbbb8 100644
--- a/frontend/tests/components/home/StatsSection.test.tsx
+++ b/frontend/tests/components/home/StatsSection.test.tsx
@@ -35,21 +35,25 @@ describe('StatsSection', () => {
it('renders all stat cards', () => {
render();
- expect(screen.getByText('Test Coverage')).toBeInTheDocument();
- expect(screen.getByText('Passing Tests')).toBeInTheDocument();
- expect(screen.getByText('Flaky Tests')).toBeInTheDocument();
- expect(screen.getByText('API Endpoints')).toBeInTheDocument();
+ expect(screen.getByText('Open Source')).toBeInTheDocument();
+ expect(screen.getByText('Type Safe')).toBeInTheDocument();
+ expect(screen.getByText('Doc Guides')).toBeInTheDocument();
+ expect(screen.getByText('Magic')).toBeInTheDocument();
});
it('displays stat descriptions', () => {
render();
expect(
- screen.getByText(/Comprehensive testing across backend and frontend/i)
+ screen.getByText(/MIT Licensed. No hidden costs or vendor lock-in/i)
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText(/End-to-end type safety with TypeScript & Pydantic/i)
+ ).toBeInTheDocument();
+ expect(screen.getByText(/Comprehensive documentation for every feature/i)).toBeInTheDocument();
+ expect(
+ screen.getByText(/Explicit is better than implicit. No hidden logic/i)
).toBeInTheDocument();
- expect(screen.getByText(/Backend, frontend unit, and E2E tests/i)).toBeInTheDocument();
- expect(screen.getByText(/Production-stable test suite/i)).toBeInTheDocument();
- expect(screen.getByText(/Fully documented with OpenAPI/i)).toBeInTheDocument();
});
it('renders animated counters with correct suffixes', () => {
@@ -69,7 +73,7 @@ describe('StatsSection', () => {
// After animation, we should see the final values
// The component should eventually show the stat values
- const statsSection = screen.getByText('Test Coverage').parentElement;
+ const statsSection = screen.getByText('Open Source').parentElement;
expect(statsSection).toBeInTheDocument();
});
@@ -78,17 +82,17 @@ describe('StatsSection', () => {
// Icons are rendered via lucide-react components
// We can verify the stat cards are rendered with proper structure
- const testCoverageCard = screen.getByText('Test Coverage').closest('div');
- expect(testCoverageCard).toBeInTheDocument();
+ const openSourceCard = screen.getByText('Open Source').closest('div');
+ expect(openSourceCard).toBeInTheDocument();
- const passingTestsCard = screen.getByText('Passing Tests').closest('div');
- expect(passingTestsCard).toBeInTheDocument();
+ const typeSafeCard = screen.getByText('Type Safe').closest('div');
+ expect(typeSafeCard).toBeInTheDocument();
- const flakyTestsCard = screen.getByText('Flaky Tests').closest('div');
- expect(flakyTestsCard).toBeInTheDocument();
+ const docGuidesCard = screen.getByText('Doc Guides').closest('div');
+ expect(docGuidesCard).toBeInTheDocument();
- const apiEndpointsCard = screen.getByText('API Endpoints').closest('div');
- expect(apiEndpointsCard).toBeInTheDocument();
+ const magicCard = screen.getByText('Magic').closest('div');
+ expect(magicCard).toBeInTheDocument();
});
describe('Accessibility', () => {
@@ -102,7 +106,7 @@ describe('StatsSection', () => {
it('has descriptive labels for stats', () => {
render();
- const statLabels = ['Test Coverage', 'Passing Tests', 'Flaky Tests', 'API Endpoints'];
+ const statLabels = ['Open Source', 'Type Safe', 'Doc Guides', 'Magic'];
statLabels.forEach((label) => {
expect(screen.getByText(label)).toBeInTheDocument();