/** * Admin Feature Flow Tests * * These tests verify routing, guards, navigation, cross-screen state, and user flows * for the admin module. They run with real frontend and mocked contracts. * * Contracts are defined in apps/website/lib/types/generated * * @file apps/website/tests/flows/admin.test.ts */ import { test, expect } from '@playwright/test'; import { WebsiteAuthManager } from '../../../tests/shared/website/WebsiteAuthManager'; import { WebsiteRouteManager } from '../../../tests/shared/website/WebsiteRouteManager'; import { ConsoleErrorCapture } from '../../../tests/shared/website/ConsoleErrorCapture'; import { HttpDiagnostics } from '../../../tests/shared/website/HttpDiagnostics'; import { RouteContractSpec } from '../../../tests/shared/website/RouteContractSpec'; import { RouteScenarioMatrix } from '../../../tests/shared/website/RouteScenarioMatrix'; test.describe('Admin Feature Flow', () => { test.describe('Admin Dashboard Navigation', () => { test('should redirect to login when accessing admin routes without authentication', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); // Navigate to admin route without authentication await page.goto(routeManager.getRoute('/admin')); // Verify redirect to login page await expect(page).toHaveURL(/.*\/auth\/login/); // Check return URL parameter const url = new URL(page.url()); expect(url.searchParams.get('returnUrl')).toBe('/admin'); }); test('should redirect to login when accessing admin users route without authentication', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); // Navigate to admin users route without authentication await page.goto(routeManager.getRoute('/admin/users')); // Verify redirect to login page await expect(page).toHaveURL(/.*\/auth\/login/); // Check return URL parameter const url = new URL(page.url()); expect(url.searchParams.get('returnUrl')).toBe('/admin/users'); }); test('should redirect to login when accessing admin routes with invalid role', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); // Login as regular user (non-admin) await authManager.loginAsUser(); // Navigate to admin route await page.goto(routeManager.getRoute('/admin')); // Verify redirect to appropriate error page or dashboard // Regular users should be redirected away from admin routes await expect(page).not.toHaveURL(/.*\/admin/); }); test('should allow access to admin dashboard with valid admin role', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); // Login as admin user await authManager.loginAsAdmin(); // Navigate to admin dashboard await page.goto(routeManager.getRoute('/admin')); // Verify dashboard loads successfully await expect(page).toHaveURL(/.*\/admin/); // Check for expected dashboard elements await expect(page.locator('h1')).toContainText(/admin/i); await expect(page.locator('[data-testid="admin-dashboard"]')).toBeVisible(); }); test('should navigate from admin dashboard to users management', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); // Login as admin await authManager.loginAsAdmin(); // Navigate to admin dashboard await page.goto(routeManager.getRoute('/admin')); // Click users link/button await page.locator('[data-testid="users-link"]').click(); // Verify navigation to /admin/users await expect(page).toHaveURL(/.*\/admin\/users/); }); test('should navigate back from users to dashboard', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); // Login as admin await authManager.loginAsAdmin(); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Click back/dashboard link await page.locator('[data-testid="back-to-dashboard"]').click(); // Verify navigation to /admin await expect(page).toHaveURL(/.*\/admin/); }); }); describe('Admin Dashboard Data Flow', () => { test('should load and display dashboard statistics', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock AdminDashboardPageQuery response const mockDashboardData = { totalUsers: 150, activeUsers: 120, pendingUsers: 25, suspendedUsers: 5, totalRevenue: 12500, recentActivity: [ { id: '1', action: 'User created', timestamp: '2024-01-15T10:00:00Z' }, { id: '2', action: 'User updated', timestamp: '2024-01-15T09:30:00Z' }, ], }; await routeContractSpec.mockApiCall('AdminDashboardPageQuery', mockDashboardData); // Navigate to admin dashboard await page.goto(routeManager.getRoute('/admin')); // Verify stats are displayed await expect(page.locator('[data-testid="total-users"]')).toContainText('150'); await expect(page.locator('[data-testid="active-users"]')).toContainText('120'); await expect(page.locator('[data-testid="pending-users"]')).toContainText('25'); await expect(page.locator('[data-testid="suspended-users"]')).toContainText('5'); // Check for proper data formatting (e.g., currency formatting) await expect(page.locator('[data-testid="total-revenue"]')).toContainText('$12,500'); }); test('should handle dashboard data loading errors', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); const consoleErrorCapture = new ConsoleErrorCapture(page); // Login as admin await authManager.loginAsAdmin(); // Mock AdminDashboardPageQuery to return error await routeContractSpec.mockApiCall('AdminDashboardPageQuery', { error: 'Internal Server Error', status: 500, }); // Navigate to admin dashboard await page.goto(routeManager.getRoute('/admin')); // Verify error banner is displayed await expect(page.locator('[data-testid="error-banner"]')).toBeVisible(); // Check error message content await expect(page.locator('[data-testid="error-message"]')).toContainText(/error/i); // Verify console error was captured const errors = consoleErrorCapture.getErrors(); expect(errors.length).toBeGreaterThan(0); }); test('should refresh dashboard data on refresh button click', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock initial dashboard data const mockDashboardData = { totalUsers: 150, activeUsers: 120, pendingUsers: 25, suspendedUsers: 5, totalRevenue: 12500, recentActivity: [], }; await routeContractSpec.mockApiCall('AdminDashboardPageQuery', mockDashboardData); // Navigate to admin dashboard await page.goto(routeManager.getRoute('/admin')); // Mock refreshed data const refreshedData = { ...mockDashboardData, totalUsers: 155, activeUsers: 125, }; await routeContractSpec.mockApiCall('AdminDashboardPageQuery', refreshedData); // Click refresh button await page.locator('[data-testid="refresh-button"]').click(); // Verify loading state is shown await expect(page.locator('[data-testid="loading-spinner"]')).toBeVisible(); // Verify data is updated await expect(page.locator('[data-testid="total-users"]')).toContainText('155'); await expect(page.locator('[data-testid="active-users"]')).toContainText('125'); }); test('should handle dashboard access denied (403/401)', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock API to return 403 error await routeContractSpec.mockApiCall('AdminDashboardPageQuery', { error: 'Access Denied', status: 403, message: 'You must have Owner or Admin role to access this resource', }); // Navigate to admin dashboard await page.goto(routeManager.getRoute('/admin')); // Verify "Access Denied" error banner await expect(page.locator('[data-testid="access-denied-banner"]')).toBeVisible(); // Check message about Owner or Admin role await expect(page.locator('[data-testid="access-denied-message"]')).toContainText(/Owner or Admin/i); }); }); describe('Admin Users Management Flow', () => { test('should load and display users list', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock AdminUsersPageQuery response const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active', createdAt: '2024-01-15T10:00:00Z', }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active', createdAt: '2024-01-14T15:30:00Z', }, { id: 'user-3', email: 'bob@example.com', roles: ['user'], status: 'suspended', createdAt: '2024-01-10T09:00:00Z', }, ], total: 3, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Verify users are displayed in table/list await expect(page.locator('[data-testid="user-row-user-1"]')).toBeVisible(); await expect(page.locator('[data-testid="user-row-user-2"]')).toBeVisible(); await expect(page.locator('[data-testid="user-row-user-3"]')).toBeVisible(); // Check for expected user fields await expect(page.locator('[data-testid="user-email-user-1"]')).toContainText('john@example.com'); await expect(page.locator('[data-testid="user-roles-user-1"]')).toContainText('admin'); await expect(page.locator('[data-testid="user-status-user-1"]')).toContainText('active'); }); test('should handle users data loading errors', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); const consoleErrorCapture = new ConsoleErrorCapture(page); // Login as admin await authManager.loginAsAdmin(); // Mock AdminUsersPageQuery to return error await routeContractSpec.mockApiCall('AdminUsersPageQuery', { error: 'Internal Server Error', status: 500, }); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Verify error banner is displayed await expect(page.locator('[data-testid="error-banner"]')).toBeVisible(); // Verify console error was captured const errors = consoleErrorCapture.getErrors(); expect(errors.length).toBeGreaterThan(0); }); test('should filter users by search term', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock initial users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Mock filtered results const filteredData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', filteredData); // Enter search term in search input await page.locator('[data-testid="search-input"]').fill('john'); // Verify URL is updated with search parameter await expect(page).toHaveURL(/.*search=john/); // Verify filtered results await expect(page.locator('[data-testid="user-row-user-1"]')).toBeVisible(); await expect(page.locator('[data-testid="user-row-user-2"]')).not.toBeVisible(); }); test('should filter users by role', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock initial users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Mock filtered results const filteredData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', filteredData); // Select role filter await page.locator('[data-testid="role-filter"]').selectOption('admin'); // Verify URL is updated with role parameter await expect(page).toHaveURL(/.*role=admin/); // Verify filtered results await expect(page.locator('[data-testid="user-row-user-1"]')).toBeVisible(); await expect(page.locator('[data-testid="user-row-user-2"]')).not.toBeVisible(); }); test('should filter users by status', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock initial users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'suspended' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Mock filtered results const filteredData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', filteredData); // Select status filter await page.locator('[data-testid="status-filter"]').selectOption('active'); // Verify URL is updated with status parameter await expect(page).toHaveURL(/.*status=active/); // Verify filtered results await expect(page.locator('[data-testid="user-row-user-1"]')).toBeVisible(); await expect(page.locator('[data-testid="user-row-user-2"]')).not.toBeVisible(); }); test('should clear all filters', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock initial users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Apply search, role, and status filters await page.locator('[data-testid="search-input"]').fill('john'); await page.locator('[data-testid="role-filter"]').selectOption('admin'); await page.locator('[data-testid="status-filter"]').selectOption('active'); // Mock cleared filters data await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Click clear filters button await page.locator('[data-testid="clear-filters-button"]').click(); // Verify URL parameters are removed await expect(page).not.toHaveURL(/.*search=/); await expect(page).not.toHaveURL(/.*role=/); await expect(page).not.toHaveURL(/.*status=/); // Verify all users are shown again await expect(page.locator('[data-testid="user-row-user-1"]')).toBeVisible(); await expect(page.locator('[data-testid="user-row-user-2"]')).toBeVisible(); }); test('should select individual users', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Click checkbox for a user await page.locator('[data-testid="user-checkbox-user-1"]').click(); // Verify user is added to selectedUserIds // Check that the checkbox is checked await expect(page.locator('[data-testid="user-checkbox-user-1"]')).toBeChecked(); // Verify selection count is updated await expect(page.locator('[data-testid="selection-count"]')).toContainText('1'); }); test('should select all users', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Click select all checkbox await page.locator('[data-testid="select-all-checkbox"]').click(); // Verify all checkboxes are checked await expect(page.locator('[data-testid="user-checkbox-user-1"]')).toBeChecked(); await expect(page.locator('[data-testid="user-checkbox-user-2"]')).toBeChecked(); // Verify selection count is updated await expect(page.locator('[data-testid="selection-count"]')).toContainText('2'); }); test('should clear user selection', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Select multiple users await page.locator('[data-testid="user-checkbox-user-1"]').click(); await page.locator('[data-testid="user-checkbox-user-2"]').click(); // Click clear selection button await page.locator('[data-testid="clear-selection-button"]').click(); // Verify no checkboxes are checked await expect(page.locator('[data-testid="user-checkbox-user-1"]')).not.toBeChecked(); await expect(page.locator('[data-testid="user-checkbox-user-2"]')).not.toBeChecked(); // Verify selection count is cleared await expect(page.locator('[data-testid="selection-count"]')).toContainText('0'); }); test('should update user status', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Mock updateUserStatus action await routeContractSpec.mockApiCall('UpdateUserStatus', { success: true }); // Click status update for a user (e.g., suspend) await page.locator('[data-testid="status-action-user-1"]').click(); await page.locator('[data-testid="suspend-option"]').click(); // Verify action is called with correct parameters // This would be verified by checking the mock call count await expect(page.locator('[data-testid="success-toast"]')).toBeVisible(); // Verify router.refresh() is called (indicated by data refresh) await expect(page.locator('[data-testid="user-row-user-1"]')).toBeVisible(); }); test('should handle user status update errors', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Mock updateUserStatus to return error await routeContractSpec.mockApiCall('UpdateUserStatus', { error: 'Failed to update status', status: 500, }); // Attempt to update user status await page.locator('[data-testid="status-action-user-1"]').click(); await page.locator('[data-testid="suspend-option"]').click(); // Verify error message is displayed await expect(page.locator('[data-testid="error-toast"]')).toBeVisible(); // Verify loading state is cleared await expect(page.locator('[data-testid="loading-spinner"]')).not.toBeVisible(); }); test('should open delete confirmation dialog', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Click delete button for a user await page.locator('[data-testid="delete-button-user-1"]').click(); // Verify ConfirmDialog opens await expect(page.locator('[data-testid="confirm-dialog"]')).toBeVisible(); // Verify dialog content (title, description) await expect(page.locator('[data-testid="confirm-dialog-title"]')).toContainText(/delete/i); await expect(page.locator('[data-testid="confirm-dialog-description"]')).toContainText(/john@example.com/i); }); test('should cancel user deletion', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Open delete confirmation dialog await page.locator('[data-testid="delete-button-user-1"]').click(); // Click cancel/close await page.locator('[data-testid="cancel-button"]').click(); // Verify dialog closes await expect(page.locator('[data-testid="confirm-dialog"]')).not.toBeVisible(); // Verify delete action is NOT called // This would be verified by checking the mock call count }); test('should confirm and delete user', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Mock deleteUser action await routeContractSpec.mockApiCall('DeleteUser', { success: true }); // Open delete confirmation dialog await page.locator('[data-testid="delete-button-user-1"]').click(); // Click confirm/delete button await page.locator('[data-testid="confirm-delete-button"]').click(); // Verify deleteUser is called with correct userId // This would be verified by checking the mock call count // Verify router.refresh() is called (indicated by data refresh) await expect(page.locator('[data-testid="user-row-user-1"]')).not.toBeVisible(); // Verify dialog closes await expect(page.locator('[data-testid="confirm-dialog"]')).not.toBeVisible(); }); test('should handle user deletion errors', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Mock deleteUser to return error await routeContractSpec.mockApiCall('DeleteUser', { error: 'Failed to delete user', status: 500, }); // Open delete confirmation dialog await page.locator('[data-testid="delete-button-user-1"]').click(); // Click confirm/delete button await page.locator('[data-testid="confirm-delete-button"]').click(); // Verify error message is displayed await expect(page.locator('[data-testid="error-toast"]')).toBeVisible(); // Verify dialog remains open await expect(page.locator('[data-testid="confirm-dialog"]')).toBeVisible(); }); test('should refresh users list', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Mock refreshed data const refreshedData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', refreshedData); // Click refresh button await page.locator('[data-testid="refresh-button"]').click(); // Verify router.refresh() is called (indicated by data refresh) await expect(page.locator('[data-testid="user-row-user-2"]')).toBeVisible(); }); test('should handle users access denied (403/401)', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock API to return 403 error await routeContractSpec.mockApiCall('AdminUsersPageQuery', { error: 'Access Denied', status: 403, message: 'You must have Owner or Admin role to access this resource', }); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Verify "Access Denied" error banner await expect(page.locator('[data-testid="access-denied-banner"]')).toBeVisible(); // Check message about Owner or Admin role await expect(page.locator('[data-testid="access-denied-message"]')).toContainText(/Owner or Admin/i); }); }); describe('Admin Route Guard Integration', () => { test('should enforce role-based access control on admin routes', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Test regular user role await authManager.loginAsUser(); await page.goto(routeManager.getRoute('/admin')); await expect(page).not.toHaveURL(/.*\/admin/); // Test sponsor role await authManager.loginAsSponsor(); await page.goto(routeManager.getRoute('/admin')); await expect(page).not.toHaveURL(/.*\/admin/); // Test admin role await authManager.loginAsAdmin(); await page.goto(routeManager.getRoute('/admin')); await expect(page).toHaveURL(/.*\/admin/); // Test owner role await authManager.loginAsOwner(); await page.goto(routeManager.getRoute('/admin')); await expect(page).toHaveURL(/.*\/admin/); }); test('should handle session expiration during admin operations', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to /admin/users await page.goto(routeManager.getRoute('/admin/users')); // Mock session expiration await routeContractSpec.mockApiCall('UpdateUserStatus', { error: 'Unauthorized', status: 401, message: 'Session expired', }); // Attempt operation (update status) await page.locator('[data-testid="status-action-user-1"]').click(); await page.locator('[data-testid="suspend-option"]').click(); // Verify redirect to login await expect(page).toHaveURL(/.*\/auth\/login/); }); test('should maintain return URL after admin authentication', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Attempt to access /admin/users without auth await page.goto(routeManager.getRoute('/admin/users')); // Verify redirect to login with return URL await expect(page).toHaveURL(/.*\/auth\/login/); const url = new URL(page.url()); expect(url.searchParams.get('returnUrl')).toBe('/admin/users'); // Mock users data for after login const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, ], total: 1, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Login as admin await authManager.loginAsAdmin(); // Verify redirect back to /admin/users await expect(page).toHaveURL(/.*\/admin\/users/); }); }); describe('Admin Cross-Screen State Management', () => { test('should preserve filter state when navigating between admin pages', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Apply filters await page.locator('[data-testid="search-input"]').fill('john'); await page.locator('[data-testid="role-filter"]').selectOption('admin'); // Verify URL has filter parameters await expect(page).toHaveURL(/.*search=john.*role=admin/); // Navigate to admin dashboard await page.goto(routeManager.getRoute('/admin')); // Navigate back to admin users await page.goto(routeManager.getRoute('/admin/users')); // Verify filters are preserved in URL await expect(page).toHaveURL(/.*search=john.*role=admin/); // Verify filter inputs still show the values await expect(page.locator('[data-testid="search-input"]')).toHaveValue('john'); await expect(page.locator('[data-testid="role-filter"]')).toHaveValue('admin'); }); test('should preserve selection state during operations', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Select multiple users await page.locator('[data-testid="user-checkbox-user-1"]').click(); await page.locator('[data-testid="user-checkbox-user-2"]').click(); // Verify selection count await expect(page.locator('[data-testid="selection-count"]')).toContainText('2'); // Mock update status action await routeContractSpec.mockApiCall('UpdateUserStatus', { success: true }); // Update status of one selected user await page.locator('[data-testid="status-action-user-1"]').click(); await page.locator('[data-testid="suspend-option"]').click(); // Verify selection is maintained after operation await expect(page.locator('[data-testid="user-checkbox-user-1"]')).toBeChecked(); await expect(page.locator('[data-testid="user-checkbox-user-2"]')).toBeChecked(); await expect(page.locator('[data-testid="selection-count"]')).toContainText('2'); }); test('should handle concurrent admin operations', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock users data const mockUsersData = { users: [ { id: 'user-1', email: 'john@example.com', roles: ['admin'], status: 'active' }, { id: 'user-2', email: 'jane@example.com', roles: ['user'], status: 'active' }, ], total: 2, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', mockUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Select users await page.locator('[data-testid="user-checkbox-user-1"]').click(); // Mock multiple concurrent operations await routeContractSpec.mockApiCall('UpdateUserStatus', { success: true }); await routeContractSpec.mockApiCall('DeleteUser', { success: true }); // Start filter operation await page.locator('[data-testid="search-input"]').fill('john'); // Start update operation const updatePromise = page.locator('[data-testid="status-action-user-1"]').click() .then(() => page.locator('[data-testid="suspend-option"]').click()); // Start delete operation const deletePromise = page.locator('[data-testid="delete-button-user-2"]').click() .then(() => page.locator('[data-testid="confirm-delete-button"]').click()); // Wait for all operations to complete await Promise.all([updatePromise, deletePromise]); // Verify loading states are managed (no stuck spinners) await expect(page.locator('[data-testid="loading-spinner"]')).not.toBeVisible(); // Verify UI remains usable after concurrent operations await expect(page.locator('[data-testid="refresh-button"]')).toBeEnabled(); }); }); describe('Admin UI State Management', () => { test('should show loading states during data operations', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock delayed response for dashboard const mockDashboardData = { totalUsers: 150, activeUsers: 120, pendingUsers: 25, suspendedUsers: 5, totalRevenue: 12500, recentActivity: [], }; // Mock with delay to simulate loading state await routeContractSpec.mockApiCall('AdminDashboardPageQuery', mockDashboardData, { delay: 500 }); // Navigate to admin dashboard await page.goto(routeManager.getRoute('/admin')); // Verify loading spinner appears during data load await expect(page.locator('[data-testid="loading-spinner"]')).toBeVisible(); // Wait for loading to complete await expect(page.locator('[data-testid="loading-spinner"]')).not.toBeVisible(); // Verify data is displayed after loading await expect(page.locator('[data-testid="total-users"]')).toContainText('150'); }); test('should handle error states gracefully', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock various error scenarios await routeContractSpec.mockApiCall('AdminDashboardPageQuery', { error: 'Internal Server Error', status: 500, }); // Navigate to admin dashboard await page.goto(routeManager.getRoute('/admin')); // Verify error banner is displayed await expect(page.locator('[data-testid="error-banner"]')).toBeVisible(); // Verify error message content await expect(page.locator('[data-testid="error-message"]')).toContainText(/error/i); // Verify UI remains usable after errors await expect(page.locator('[data-testid="refresh-button"]')).toBeEnabled(); await expect(page.locator('[data-testid="navigation-menu"]')).toBeVisible(); // Verify error can be dismissed await page.locator('[data-testid="error-dismiss"]').click(); await expect(page.locator('[data-testid="error-banner"]')).not.toBeVisible(); }); test('should handle empty states', async ({ page }) => { const routeManager = new WebsiteRouteManager(page); const authManager = new WebsiteAuthManager(page); const routeContractSpec = new RouteContractSpec(page); // Login as admin await authManager.loginAsAdmin(); // Mock empty users list const emptyUsersData = { users: [], total: 0, page: 1, totalPages: 1, }; await routeContractSpec.mockApiCall('AdminUsersPageQuery', emptyUsersData); // Navigate to admin users await page.goto(routeManager.getRoute('/admin/users')); // Verify empty state message is shown await expect(page.locator('[data-testid="empty-state"]')).toBeVisible(); await expect(page.locator('[data-testid="empty-state-message"]')).toContainText(/no users/i); // Verify empty state has helpful actions await expect(page.locator('[data-testid="empty-state-refresh"]')).toBeVisible(); }); }); });