305 lines
9.3 KiB
TypeScript
305 lines
9.3 KiB
TypeScript
import React from 'react';
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { render, screen } from '@testing-library/react';
|
|
import { MemoryRouter, Navigate } from 'react-router-dom';
|
|
import { AppRouter } from './index';
|
|
import { useAuthStore } from '@/features/auth/store/authStore';
|
|
|
|
// Mock the stores
|
|
vi.mock('@/features/auth/store/authStore', () => ({
|
|
useAuthStore: vi.fn(),
|
|
}));
|
|
|
|
// Mock PublicRoute: redirect to dashboard if auth, else render children
|
|
vi.mock('./PublicRoute', () => ({
|
|
PublicRoute: ({ children }: { children: React.ReactNode }) => {
|
|
const store = useAuthStore();
|
|
const isAuth = (store as any)?.isAuthenticated === true;
|
|
const isLoading = (store as any)?.isLoading === true;
|
|
if (isLoading) return <div>Loading...</div>;
|
|
if (isAuth) return <Navigate to="/dashboard" replace />;
|
|
return <>{children}</>;
|
|
},
|
|
}));
|
|
|
|
// Mock ProtectedRoute + ProtectedLayoutRoute: redirect to login if not auth, else render layout + children
|
|
vi.mock('@/components/auth/ProtectedRoute', () => ({
|
|
ProtectedRoute: ({ children }: { children: React.ReactNode }) => {
|
|
const store = useAuthStore();
|
|
const isAuth = (store as any)?.isAuthenticated === true;
|
|
const isLoading = (store as any)?.isLoading === true;
|
|
if (isLoading) return <div>Loading...</div>;
|
|
if (!isAuth) return <Navigate to="/login" replace />;
|
|
return <>{children}</>;
|
|
},
|
|
}));
|
|
|
|
vi.mock('./ProtectedLayoutRoute', () => ({
|
|
ProtectedLayoutRoute: ({ children }: { children: React.ReactNode }) => (
|
|
<div data-testid="layout">{children}</div>
|
|
),
|
|
}));
|
|
|
|
// Mock lazy components (all exports used by routeConfig)
|
|
vi.mock('@/components/ui/LazyComponent', () => ({
|
|
LazyLogin: () => <div>Login Page</div>,
|
|
LazyRegister: () => <div>Register Page</div>,
|
|
LazyForgotPassword: () => <div>Forgot Password Page</div>,
|
|
LazyVerifyEmail: () => <div>Verify Email Page</div>,
|
|
LazyResetPassword: () => <div>Reset Password Page</div>,
|
|
LazyDashboard: () => <div>Dashboard Page</div>,
|
|
LazyChat: () => <div>Chat Page</div>,
|
|
LazyLibrary: () => <div>Library Page</div>,
|
|
LazyProfile: () => <div>Profile Page</div>,
|
|
LazySettings: () => <div>Settings Page</div>,
|
|
LazySessions: () => <div>Sessions Page</div>,
|
|
LazyNotFound: () => <div>404 Not Found</div>,
|
|
LazyServerError: () => <div>500 Server Error</div>,
|
|
LazyUserProfile: () => <div>User Profile Page</div>,
|
|
LazyRoles: () => <div>Roles Page</div>,
|
|
LazyTrackDetail: () => <div>Track Detail Page</div>,
|
|
LazyPlaylistRoutes: () => <div>Playlists Page</div>,
|
|
LazyMarketplace: () => <div>Marketplace Page</div>,
|
|
LazySearch: () => <div>Search Page</div>,
|
|
LazyNotifications: () => <div>Notifications Page</div>,
|
|
LazyAnalytics: () => <div>Analytics Page</div>,
|
|
LazyWebhooks: () => <div>Webhooks Page</div>,
|
|
LazyAdminDashboard: () => <div>Admin Page</div>,
|
|
LazyDesignSystemDemo: () => <div>Design System</div>,
|
|
LazySocial: () => <div>Social Page</div>,
|
|
LazyGear: () => <div>Gear Page</div>,
|
|
LazyLive: () => <div>Live Page</div>,
|
|
LazyEducation: () => <div>Education Page</div>,
|
|
LazyQueue: () => <div>Queue Page</div>,
|
|
LazyDeveloper: () => <div>Developer Page</div>,
|
|
LazySellerDashboard: () => <div>Seller Page</div>,
|
|
LazyWishlist: () => <div>Wishlist Page</div>,
|
|
LazyPurchases: () => <div>Purchases Page</div>,
|
|
}));
|
|
|
|
// Mock DashboardLayout (used by ProtectedLayoutRoute)
|
|
vi.mock('@/components/layout/DashboardLayout', () => ({
|
|
DashboardLayout: ({ children }: { children: React.ReactNode }) => (
|
|
<div data-testid="layout">{children}</div>
|
|
),
|
|
}));
|
|
|
|
// Mock LoadingSpinner
|
|
vi.mock('@/components/ui/loading-spinner', () => ({
|
|
LoadingSpinner: () => <div>Loading...</div>,
|
|
}));
|
|
|
|
describe('AppRouter', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('Public Routes', () => {
|
|
it('should render login page for /login route when not authenticated', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: false,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/login']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
expect(screen.getByText('Login Page')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should redirect to dashboard when authenticated user tries to access login', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: true,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/login']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
// Should redirect to dashboard (mocked as Dashboard Page)
|
|
expect(screen.getByText('Dashboard Page')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should render register page for /register route when not authenticated', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: false,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/register']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
expect(screen.getByText('Register Page')).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('Protected Routes', () => {
|
|
it('should render dashboard page when authenticated', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: true,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/dashboard']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
expect(screen.getByTestId('layout')).toBeInTheDocument();
|
|
expect(screen.getByText('Dashboard Page')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should redirect to login when not authenticated user tries to access protected route', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: false,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/dashboard']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
// Should redirect to login
|
|
expect(screen.getByText('Login Page')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should show loading spinner when checking authentication', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: false,
|
|
isLoading: true,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/dashboard']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should render chat page when authenticated', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: true,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/chat']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
expect(screen.getByTestId('layout')).toBeInTheDocument();
|
|
expect(screen.getByText('Chat Page')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should render library page when authenticated', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: true,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/library']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
expect(screen.getByTestId('layout')).toBeInTheDocument();
|
|
expect(screen.getByText('Library Page')).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('Error Routes', () => {
|
|
it('should render 404 page for /404 route', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: false,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/404']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
expect(screen.getByText('404 Not Found')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should render 500 page for /500 route', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: false,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/500']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
expect(screen.getByText('500 Server Error')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should redirect to 404 for unknown routes', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: false,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/unknown-route']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
expect(screen.getByText('404 Not Found')).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('Default Routes', () => {
|
|
it('should redirect root path to dashboard when authenticated', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: true,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
expect(screen.getByText('Dashboard Page')).toBeInTheDocument();
|
|
});
|
|
|
|
it('should redirect root path to login when not authenticated', () => {
|
|
vi.mocked(useAuthStore).mockReturnValue({
|
|
isAuthenticated: false,
|
|
isLoading: false,
|
|
} as any);
|
|
|
|
render(
|
|
<MemoryRouter initialEntries={['/']}>
|
|
<AppRouter />
|
|
</MemoryRouter>,
|
|
);
|
|
|
|
// Should redirect to dashboard, which then redirects to login
|
|
expect(screen.getByText('Login Page')).toBeInTheDocument();
|
|
});
|
|
});
|
|
});
|