mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 15:44:21 +00:00
Add tests for AdminDashboard, AdminStatsTab, AdminUsersTab, and AdminWorkspacesTab components
This commit is contained in:
110
app/src/components/settings/admin/AdminDashboard.test.tsx
Normal file
110
app/src/components/settings/admin/AdminDashboard.test.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render as rtlRender, screen, fireEvent } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MantineProvider } from '@mantine/core';
|
||||
import AdminDashboard from './AdminDashboard';
|
||||
import { UserRole, type User } from '@/types/models';
|
||||
|
||||
// Mock the auth context
|
||||
const mockCurrentUser: User = {
|
||||
id: 1,
|
||||
email: 'admin@example.com',
|
||||
displayName: 'Admin User',
|
||||
role: UserRole.Admin,
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
lastWorkspaceId: 1,
|
||||
};
|
||||
|
||||
vi.mock('../../../contexts/AuthContext', () => ({
|
||||
useAuth: () => ({
|
||||
user: mockCurrentUser,
|
||||
}),
|
||||
}));
|
||||
|
||||
// Mock the sub-components
|
||||
vi.mock('./AdminUsersTab', () => ({
|
||||
default: ({ currentUser }: { currentUser: User }) => (
|
||||
<div data-testid="admin-users-tab">Users Tab - {currentUser.email}</div>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('./AdminWorkspacesTab', () => ({
|
||||
default: () => <div data-testid="admin-workspaces-tab">Workspaces Tab</div>,
|
||||
}));
|
||||
|
||||
vi.mock('./AdminStatsTab', () => ({
|
||||
default: () => <div data-testid="admin-stats-tab">Stats Tab</div>,
|
||||
}));
|
||||
|
||||
// Helper wrapper component for testing
|
||||
const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<MantineProvider defaultColorScheme="light">{children}</MantineProvider>
|
||||
);
|
||||
|
||||
// Custom render function
|
||||
const render = (ui: React.ReactElement) => {
|
||||
return rtlRender(ui, { wrapper: TestWrapper });
|
||||
};
|
||||
|
||||
describe('AdminDashboard', () => {
|
||||
const mockOnClose = vi.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('renders modal with all tabs', () => {
|
||||
render(<AdminDashboard opened={true} onClose={mockOnClose} />);
|
||||
|
||||
expect(screen.getByText('Admin Dashboard')).toBeInTheDocument();
|
||||
expect(screen.getByRole('tab', { name: /users/i })).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('tab', { name: /workspaces/i })
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('tab', { name: /statistics/i })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows users tab by default', () => {
|
||||
render(<AdminDashboard opened={true} onClose={mockOnClose} />);
|
||||
|
||||
expect(screen.getByTestId('admin-users-tab')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('Users Tab - admin@example.com')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('switches to workspaces tab when clicked', () => {
|
||||
render(<AdminDashboard opened={true} onClose={mockOnClose} />);
|
||||
|
||||
fireEvent.click(screen.getByRole('tab', { name: /workspaces/i }));
|
||||
|
||||
expect(screen.getByTestId('admin-workspaces-tab')).toBeInTheDocument();
|
||||
expect(screen.getByText('Workspaces Tab')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('switches to statistics tab when clicked', () => {
|
||||
render(<AdminDashboard opened={true} onClose={mockOnClose} />);
|
||||
|
||||
fireEvent.click(screen.getByRole('tab', { name: /statistics/i }));
|
||||
|
||||
expect(screen.getByTestId('admin-stats-tab')).toBeInTheDocument();
|
||||
expect(screen.getByText('Stats Tab')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('passes current user to users tab', () => {
|
||||
render(<AdminDashboard opened={true} onClose={mockOnClose} />);
|
||||
|
||||
// Should pass current user to AdminUsersTab
|
||||
expect(
|
||||
screen.getByText('Users Tab - admin@example.com')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render when closed', () => {
|
||||
render(<AdminDashboard opened={false} onClose={mockOnClose} />);
|
||||
|
||||
expect(screen.queryByText('Admin Dashboard')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
126
app/src/components/settings/admin/AdminStatsTab.test.tsx
Normal file
126
app/src/components/settings/admin/AdminStatsTab.test.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render as rtlRender, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MantineProvider } from '@mantine/core';
|
||||
import AdminStatsTab from './AdminStatsTab';
|
||||
import type { SystemStats } from '@/types/models';
|
||||
|
||||
// Mock the admin data hook
|
||||
vi.mock('../../../hooks/useAdminData', () => ({
|
||||
useAdminData: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock the formatBytes utility
|
||||
vi.mock('../../../utils/formatBytes', () => ({
|
||||
formatBytes: (bytes: number) => `${bytes} bytes`,
|
||||
}));
|
||||
|
||||
// Helper wrapper component for testing
|
||||
const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<MantineProvider defaultColorScheme="light">{children}</MantineProvider>
|
||||
);
|
||||
|
||||
// Custom render function
|
||||
const render = (ui: React.ReactElement) => {
|
||||
return rtlRender(ui, { wrapper: TestWrapper });
|
||||
};
|
||||
|
||||
describe('AdminStatsTab', () => {
|
||||
const mockStats: SystemStats = {
|
||||
totalUsers: 150,
|
||||
activeUsers: 120,
|
||||
totalWorkspaces: 85,
|
||||
totalFiles: 2500,
|
||||
totalSize: 1073741824, // 1GB in bytes
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
const { useAdminData } = await import('../../../hooks/useAdminData');
|
||||
vi.mocked(useAdminData).mockReturnValue({
|
||||
data: mockStats,
|
||||
loading: false,
|
||||
error: null,
|
||||
reload: vi.fn(),
|
||||
});
|
||||
});
|
||||
|
||||
it('renders statistics table with all metrics', () => {
|
||||
render(<AdminStatsTab />);
|
||||
|
||||
expect(screen.getByText('System Statistics')).toBeInTheDocument();
|
||||
expect(screen.getByText('Total Users')).toBeInTheDocument();
|
||||
expect(screen.getByText('Active Users')).toBeInTheDocument();
|
||||
expect(screen.getByText('Total Workspaces')).toBeInTheDocument();
|
||||
expect(screen.getByText('Total Files')).toBeInTheDocument();
|
||||
expect(screen.getByText('Total Storage Size')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays correct statistics values', () => {
|
||||
render(<AdminStatsTab />);
|
||||
|
||||
expect(screen.getByText('150')).toBeInTheDocument();
|
||||
expect(screen.getByText('120')).toBeInTheDocument();
|
||||
expect(screen.getByText('85')).toBeInTheDocument();
|
||||
expect(screen.getByText('2500')).toBeInTheDocument();
|
||||
expect(screen.getByText('1073741824 bytes')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows loading state', async () => {
|
||||
const { useAdminData } = await import('../../../hooks/useAdminData');
|
||||
vi.mocked(useAdminData).mockReturnValue({
|
||||
data: {} as SystemStats,
|
||||
loading: true,
|
||||
error: null,
|
||||
reload: vi.fn(),
|
||||
});
|
||||
|
||||
render(<AdminStatsTab />);
|
||||
|
||||
// Mantine LoadingOverlay should be visible
|
||||
expect(
|
||||
document.querySelector('.mantine-LoadingOverlay-root')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows error state', async () => {
|
||||
const { useAdminData } = await import('../../../hooks/useAdminData');
|
||||
vi.mocked(useAdminData).mockReturnValue({
|
||||
data: {} as SystemStats,
|
||||
loading: false,
|
||||
error: 'Failed to load statistics',
|
||||
reload: vi.fn(),
|
||||
});
|
||||
|
||||
render(<AdminStatsTab />);
|
||||
|
||||
expect(screen.getByText('Error')).toBeInTheDocument();
|
||||
expect(screen.getByText('Failed to load statistics')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('handles zero values correctly', async () => {
|
||||
const zeroStats: SystemStats = {
|
||||
totalUsers: 0,
|
||||
activeUsers: 0,
|
||||
totalWorkspaces: 0,
|
||||
totalFiles: 0,
|
||||
totalSize: 0,
|
||||
};
|
||||
|
||||
const { useAdminData } = await import('../../../hooks/useAdminData');
|
||||
vi.mocked(useAdminData).mockReturnValue({
|
||||
data: zeroStats,
|
||||
loading: false,
|
||||
error: null,
|
||||
reload: vi.fn(),
|
||||
});
|
||||
|
||||
render(<AdminStatsTab />);
|
||||
|
||||
// Should display zeros without issues
|
||||
const zeros = screen.getAllByText('0');
|
||||
expect(zeros.length).toBeGreaterThan(0);
|
||||
expect(screen.getByText('0 bytes')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
288
app/src/components/settings/admin/AdminUsersTab.test.tsx
Normal file
288
app/src/components/settings/admin/AdminUsersTab.test.tsx
Normal file
@@ -0,0 +1,288 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import {
|
||||
render as rtlRender,
|
||||
screen,
|
||||
fireEvent,
|
||||
waitFor,
|
||||
} from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MantineProvider } from '@mantine/core';
|
||||
import AdminUsersTab from './AdminUsersTab';
|
||||
import { UserRole, type User } from '@/types/models';
|
||||
|
||||
// Mock the user admin hook
|
||||
const mockCreate = vi.fn();
|
||||
const mockUpdate = vi.fn();
|
||||
const mockDelete = vi.fn();
|
||||
|
||||
vi.mock('../../../hooks/useUserAdmin', () => ({
|
||||
useUserAdmin: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock notifications
|
||||
vi.mock('@mantine/notifications', () => ({
|
||||
notifications: {
|
||||
show: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
// Mock the user modals
|
||||
vi.mock('../../modals/user/CreateUserModal', () => ({
|
||||
default: ({
|
||||
opened,
|
||||
onCreateUser,
|
||||
}: {
|
||||
opened: boolean;
|
||||
onCreateUser: (userData: {
|
||||
email: string;
|
||||
password: string;
|
||||
displayName: string;
|
||||
role: UserRole;
|
||||
}) => Promise<boolean>;
|
||||
}) =>
|
||||
opened ? (
|
||||
<div data-testid="create-user-modal">
|
||||
<button
|
||||
onClick={() =>
|
||||
void onCreateUser({
|
||||
email: 'new@example.com',
|
||||
password: 'pass',
|
||||
displayName: 'New User',
|
||||
role: UserRole.Editor,
|
||||
})
|
||||
}
|
||||
data-testid="create-user-button"
|
||||
>
|
||||
Create User
|
||||
</button>
|
||||
</div>
|
||||
) : null,
|
||||
}));
|
||||
|
||||
vi.mock('../../modals/user/EditUserModal', () => ({
|
||||
default: ({
|
||||
opened,
|
||||
onEditUser,
|
||||
user,
|
||||
}: {
|
||||
opened: boolean;
|
||||
onEditUser: (
|
||||
userId: number,
|
||||
userData: { email: string }
|
||||
) => Promise<boolean>;
|
||||
user: User | null;
|
||||
}) =>
|
||||
opened ? (
|
||||
<div data-testid="edit-user-modal">
|
||||
<span data-testid="edit-user-email">{user?.email}</span>
|
||||
<button
|
||||
onClick={() =>
|
||||
void onEditUser(user?.id || 0, { email: 'updated@example.com' })
|
||||
}
|
||||
data-testid="edit-user-button"
|
||||
>
|
||||
Update User
|
||||
</button>
|
||||
</div>
|
||||
) : null,
|
||||
}));
|
||||
|
||||
vi.mock('../../modals/user/DeleteUserModal', () => ({
|
||||
default: ({
|
||||
opened,
|
||||
onConfirm,
|
||||
}: {
|
||||
opened: boolean;
|
||||
onConfirm: () => Promise<void>;
|
||||
}) =>
|
||||
opened ? (
|
||||
<div data-testid="delete-user-modal">
|
||||
<button
|
||||
onClick={() => void onConfirm()}
|
||||
data-testid="delete-user-button"
|
||||
>
|
||||
Delete User
|
||||
</button>
|
||||
</div>
|
||||
) : null,
|
||||
}));
|
||||
|
||||
// Helper wrapper component for testing
|
||||
const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<MantineProvider defaultColorScheme="light">{children}</MantineProvider>
|
||||
);
|
||||
|
||||
// Custom render function
|
||||
const render = (ui: React.ReactElement) => {
|
||||
return rtlRender(ui, { wrapper: TestWrapper });
|
||||
};
|
||||
|
||||
describe('AdminUsersTab', () => {
|
||||
const mockCurrentUser: User = {
|
||||
id: 1,
|
||||
email: 'admin@example.com',
|
||||
displayName: 'Admin User',
|
||||
role: UserRole.Admin,
|
||||
createdAt: '2024-01-01T00:00:00Z',
|
||||
lastWorkspaceId: 1,
|
||||
};
|
||||
|
||||
const mockUsers: User[] = [
|
||||
mockCurrentUser,
|
||||
{
|
||||
id: 2,
|
||||
email: 'editor@example.com',
|
||||
displayName: 'Editor User',
|
||||
role: UserRole.Editor,
|
||||
createdAt: '2024-01-15T00:00:00Z',
|
||||
lastWorkspaceId: 2,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
email: 'viewer@example.com',
|
||||
displayName: 'Viewer User',
|
||||
role: UserRole.Viewer,
|
||||
createdAt: '2024-02-01T00:00:00Z',
|
||||
lastWorkspaceId: 3,
|
||||
},
|
||||
];
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
mockCreate.mockResolvedValue(true);
|
||||
mockUpdate.mockResolvedValue(true);
|
||||
mockDelete.mockResolvedValue(true);
|
||||
|
||||
const { useUserAdmin } = await import('../../../hooks/useUserAdmin');
|
||||
vi.mocked(useUserAdmin).mockReturnValue({
|
||||
users: mockUsers,
|
||||
loading: false,
|
||||
error: null,
|
||||
create: mockCreate,
|
||||
update: mockUpdate,
|
||||
delete: mockDelete,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders users table with all users', () => {
|
||||
render(<AdminUsersTab currentUser={mockCurrentUser} />);
|
||||
|
||||
expect(screen.getByText('User Management')).toBeInTheDocument();
|
||||
expect(screen.getByText('admin@example.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('editor@example.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('viewer@example.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('Admin User')).toBeInTheDocument();
|
||||
expect(screen.getByText('Editor User')).toBeInTheDocument();
|
||||
expect(screen.getByText('Viewer User')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows create user button', () => {
|
||||
render(<AdminUsersTab currentUser={mockCurrentUser} />);
|
||||
|
||||
expect(
|
||||
screen.getByRole('button', { name: /create user/i })
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('opens create user modal when create button is clicked', () => {
|
||||
render(<AdminUsersTab currentUser={mockCurrentUser} />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /create user/i }));
|
||||
|
||||
expect(screen.getByTestId('create-user-modal')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('creates new user successfully', async () => {
|
||||
render(<AdminUsersTab currentUser={mockCurrentUser} />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: /create user/i }));
|
||||
fireEvent.click(screen.getByTestId('create-user-button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockCreate).toHaveBeenCalledWith({
|
||||
email: 'new@example.com',
|
||||
password: 'pass',
|
||||
displayName: 'New User',
|
||||
role: UserRole.Editor,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('opens edit modal when edit button is clicked', () => {
|
||||
render(<AdminUsersTab currentUser={mockCurrentUser} />);
|
||||
|
||||
const editButtons = screen.getAllByLabelText(/edit/i);
|
||||
expect(editButtons[0]).toBeDefined();
|
||||
fireEvent.click(editButtons[0]!); // Click first edit button
|
||||
|
||||
expect(screen.getByTestId('edit-user-modal')).toBeInTheDocument();
|
||||
expect(screen.getByTestId('edit-user-email')).toHaveTextContent(
|
||||
'admin@example.com'
|
||||
);
|
||||
});
|
||||
|
||||
it('updates user successfully', async () => {
|
||||
render(<AdminUsersTab currentUser={mockCurrentUser} />);
|
||||
|
||||
const editButtons = screen.getAllByLabelText(/edit/i);
|
||||
expect(editButtons[0]).toBeDefined();
|
||||
fireEvent.click(editButtons[0]!);
|
||||
fireEvent.click(screen.getByTestId('edit-user-button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockUpdate).toHaveBeenCalledWith(1, {
|
||||
email: 'updated@example.com',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('prevents deleting current user', () => {
|
||||
render(<AdminUsersTab currentUser={mockCurrentUser} />);
|
||||
|
||||
const deleteButtons = screen.getAllByLabelText(/delete/i);
|
||||
const currentUserDeleteButton = deleteButtons[0]; // First user is current user
|
||||
|
||||
expect(currentUserDeleteButton).toBeDefined();
|
||||
expect(currentUserDeleteButton).toBeDisabled();
|
||||
});
|
||||
|
||||
it('allows deleting other users', () => {
|
||||
render(<AdminUsersTab currentUser={mockCurrentUser} />);
|
||||
|
||||
const deleteButtons = screen.getAllByLabelText(/delete/i);
|
||||
expect(deleteButtons[1]).toBeDefined();
|
||||
fireEvent.click(deleteButtons[1]!); // Click delete for second user
|
||||
|
||||
expect(screen.getByTestId('delete-user-modal')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('deletes user successfully', async () => {
|
||||
render(<AdminUsersTab currentUser={mockCurrentUser} />);
|
||||
|
||||
const deleteButtons = screen.getAllByLabelText(/delete/i);
|
||||
expect(deleteButtons[1]).toBeDefined();
|
||||
fireEvent.click(deleteButtons[1]!);
|
||||
fireEvent.click(screen.getByTestId('delete-user-button'));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockDelete).toHaveBeenCalledWith(2); // Second user's ID
|
||||
});
|
||||
});
|
||||
|
||||
it('shows error state when loading fails', async () => {
|
||||
const { useUserAdmin } = await import('../../../hooks/useUserAdmin');
|
||||
vi.mocked(useUserAdmin).mockReturnValue({
|
||||
users: [],
|
||||
loading: false,
|
||||
error: 'Failed to load users',
|
||||
create: mockCreate,
|
||||
update: mockUpdate,
|
||||
delete: mockDelete,
|
||||
});
|
||||
|
||||
render(<AdminUsersTab currentUser={mockCurrentUser} />);
|
||||
|
||||
expect(screen.getByText('Error')).toBeInTheDocument();
|
||||
expect(screen.getByText('Failed to load users')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -86,6 +86,7 @@ const AdminUsersTab: React.FC<AdminUsersTabProps> = ({ currentUser }) => {
|
||||
<Group gap="xs" justify="flex-end">
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
aria-label="Edit user"
|
||||
color="blue"
|
||||
onClick={() => setEditModalData(user)}
|
||||
>
|
||||
@@ -93,6 +94,7 @@ const AdminUsersTab: React.FC<AdminUsersTabProps> = ({ currentUser }) => {
|
||||
</ActionIcon>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
aria-label="Delete user"
|
||||
color="red"
|
||||
onClick={() => handleDeleteClick(user)}
|
||||
disabled={user.id === currentUser.id}
|
||||
@@ -125,6 +127,7 @@ const AdminUsersTab: React.FC<AdminUsersTabProps> = ({ currentUser }) => {
|
||||
</Text>
|
||||
<Button
|
||||
leftSection={<IconPlus size={16} />}
|
||||
aria-label="Create user"
|
||||
onClick={() => setCreateModalOpened(true)}
|
||||
>
|
||||
Create User
|
||||
|
||||
140
app/src/components/settings/admin/AdminWorkspacesTab.test.tsx
Normal file
140
app/src/components/settings/admin/AdminWorkspacesTab.test.tsx
Normal file
@@ -0,0 +1,140 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render as rtlRender, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { MantineProvider } from '@mantine/core';
|
||||
import AdminWorkspacesTab from './AdminWorkspacesTab';
|
||||
import type { WorkspaceStats } from '@/types/models';
|
||||
|
||||
// Mock the admin data hook
|
||||
vi.mock('../../../hooks/useAdminData', () => ({
|
||||
useAdminData: vi.fn(),
|
||||
}));
|
||||
|
||||
// Mock the formatBytes utility
|
||||
vi.mock('../../../utils/formatBytes', () => ({
|
||||
formatBytes: (bytes: number) => `${bytes} bytes`,
|
||||
}));
|
||||
|
||||
// Helper wrapper component for testing
|
||||
const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<MantineProvider defaultColorScheme="light">{children}</MantineProvider>
|
||||
);
|
||||
|
||||
// Custom render function
|
||||
const render = (ui: React.ReactElement) => {
|
||||
return rtlRender(ui, { wrapper: TestWrapper });
|
||||
};
|
||||
|
||||
describe('AdminWorkspacesTab', () => {
|
||||
const mockWorkspaces: WorkspaceStats[] = [
|
||||
{
|
||||
workspaceID: 1,
|
||||
userID: 1,
|
||||
userEmail: 'user1@example.com',
|
||||
workspaceName: 'Project Alpha',
|
||||
workspaceCreatedAt: '2024-01-15T10:30:00Z',
|
||||
fileCountStats: {
|
||||
totalFiles: 25,
|
||||
totalSize: 1048576, // 1MB
|
||||
},
|
||||
},
|
||||
{
|
||||
workspaceID: 2,
|
||||
userID: 2,
|
||||
userEmail: 'user2@example.com',
|
||||
workspaceName: 'Project Beta',
|
||||
workspaceCreatedAt: '2024-02-20T14:45:00Z',
|
||||
fileCountStats: {
|
||||
totalFiles: 42,
|
||||
totalSize: 2097152, // 2MB
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
const { useAdminData } = await import('../../../hooks/useAdminData');
|
||||
vi.mocked(useAdminData).mockReturnValue({
|
||||
data: mockWorkspaces,
|
||||
loading: false,
|
||||
error: null,
|
||||
reload: vi.fn(),
|
||||
});
|
||||
});
|
||||
|
||||
it('renders workspace table with all columns', () => {
|
||||
render(<AdminWorkspacesTab />);
|
||||
|
||||
expect(screen.getByText('Workspace Management')).toBeInTheDocument();
|
||||
expect(screen.getByText('Owner')).toBeInTheDocument();
|
||||
expect(screen.getByText('Name')).toBeInTheDocument();
|
||||
expect(screen.getByText('Created At')).toBeInTheDocument();
|
||||
expect(screen.getByText('Total Files')).toBeInTheDocument();
|
||||
expect(screen.getByText('Total Size')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('displays workspace data correctly', () => {
|
||||
render(<AdminWorkspacesTab />);
|
||||
|
||||
expect(screen.getByText('user1@example.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('Project Alpha')).toBeInTheDocument();
|
||||
expect(screen.getByText('1/15/2024')).toBeInTheDocument();
|
||||
expect(screen.getByText('25')).toBeInTheDocument();
|
||||
expect(screen.getByText('1048576 bytes')).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText('user2@example.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('Project Beta')).toBeInTheDocument();
|
||||
expect(screen.getByText('2/20/2024')).toBeInTheDocument();
|
||||
expect(screen.getByText('42')).toBeInTheDocument();
|
||||
expect(screen.getByText('2097152 bytes')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows loading state', async () => {
|
||||
const { useAdminData } = await import('../../../hooks/useAdminData');
|
||||
vi.mocked(useAdminData).mockReturnValue({
|
||||
data: [],
|
||||
loading: true,
|
||||
error: null,
|
||||
reload: vi.fn(),
|
||||
});
|
||||
|
||||
render(<AdminWorkspacesTab />);
|
||||
|
||||
expect(
|
||||
document.querySelector('.mantine-LoadingOverlay-root')
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows error state', async () => {
|
||||
const { useAdminData } = await import('../../../hooks/useAdminData');
|
||||
vi.mocked(useAdminData).mockReturnValue({
|
||||
data: [],
|
||||
loading: false,
|
||||
error: 'Failed to load workspaces',
|
||||
reload: vi.fn(),
|
||||
});
|
||||
|
||||
render(<AdminWorkspacesTab />);
|
||||
|
||||
expect(screen.getByText('Error')).toBeInTheDocument();
|
||||
expect(screen.getByText('Failed to load workspaces')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('handles empty workspace list', async () => {
|
||||
const { useAdminData } = await import('../../../hooks/useAdminData');
|
||||
vi.mocked(useAdminData).mockReturnValue({
|
||||
data: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
reload: vi.fn(),
|
||||
});
|
||||
|
||||
render(<AdminWorkspacesTab />);
|
||||
|
||||
expect(screen.getByText('Workspace Management')).toBeInTheDocument();
|
||||
// Table headers should still be present
|
||||
expect(screen.getByText('Owner')).toBeInTheDocument();
|
||||
expect(screen.getByText('Name')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user