362 lines
10 KiB
TypeScript
362 lines
10 KiB
TypeScript
/**
|
|
* AdminUsersTable Component Tests
|
|
*
|
|
* Tests for the AdminUsersTable component that displays users in a table
|
|
* with selection, status management, and deletion capabilities.
|
|
*/
|
|
|
|
import React from 'react';
|
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
import { AdminUsersTable } from './AdminUsersTable';
|
|
import { describe, it, expect, vi } from 'vitest';
|
|
|
|
// Mock the DateDisplay component
|
|
vi.mock('@/lib/display-objects/DateDisplay', () => ({
|
|
DateDisplay: {
|
|
formatShort: (date: string) => new Date(date).toLocaleDateString(),
|
|
},
|
|
}));
|
|
|
|
// Mock the AdminUsersViewData
|
|
vi.mock('@/lib/view-data/AdminUsersViewData', () => ({
|
|
AdminUsersViewData: {},
|
|
}));
|
|
|
|
// Mock the Button component
|
|
vi.mock('@/ui/Button', () => ({
|
|
Button: ({ children, onClick, disabled }: any) => (
|
|
<button onClick={onClick} disabled={disabled} data-testid="button">
|
|
{children}
|
|
</button>
|
|
),
|
|
}));
|
|
|
|
// Mock the IconButton component
|
|
vi.mock('@/ui/IconButton', () => ({
|
|
IconButton: ({ onClick, disabled, icon, title }: any) => (
|
|
<button onClick={onClick} disabled={disabled} data-testid="icon-button" title={title}>
|
|
{title}
|
|
</button>
|
|
),
|
|
}));
|
|
|
|
// Mock the SimpleCheckbox component
|
|
vi.mock('@/ui/SimpleCheckbox', () => ({
|
|
SimpleCheckbox: ({ checked, onChange, 'aria-label': ariaLabel }: any) => (
|
|
<input
|
|
type="checkbox"
|
|
checked={checked}
|
|
onChange={onChange}
|
|
aria-label={ariaLabel}
|
|
data-testid="checkbox"
|
|
/>
|
|
),
|
|
}));
|
|
|
|
// Mock the Badge component
|
|
vi.mock('@/ui/Badge', () => ({
|
|
Badge: ({ children }: any) => <span data-testid="badge">{children}</span>,
|
|
}));
|
|
|
|
// Mock the Box component
|
|
vi.mock('@/ui/Box', () => ({
|
|
Box: ({ children }: any) => <div>{children}</div>,
|
|
}));
|
|
|
|
// Mock the Group component
|
|
vi.mock('@/ui/Group', () => ({
|
|
Group: ({ children }: any) => <div>{children}</div>,
|
|
}));
|
|
|
|
// Mock the DriverIdentity component
|
|
vi.mock('@/ui/DriverIdentity', () => ({
|
|
DriverIdentity: ({ driver, meta }: any) => (
|
|
<div data-testid="driver-identity">
|
|
<span>{driver.name}</span>
|
|
<span>{meta}</span>
|
|
</div>
|
|
),
|
|
}));
|
|
|
|
// Mock the Table components
|
|
vi.mock('@/ui/Table', () => ({
|
|
Table: ({ children }: any) => <table>{children}</table>,
|
|
TableHead: ({ children }: any) => <thead>{children}</thead>,
|
|
TableBody: ({ children }: any) => <tbody>{children}</tbody>,
|
|
TableHeader: ({ children, w, textAlign }: any) => <th style={{ width: w, textAlign }}>{children}</th>,
|
|
TableRow: ({ children, variant }: any) => <tr data-variant={variant}>{children}</tr>,
|
|
TableCell: ({ children }: any) => <td>{children}</td>,
|
|
}));
|
|
|
|
// Mock the Text component
|
|
vi.mock('@/ui/Text', () => ({
|
|
Text: ({ children, size, variant }: any) => (
|
|
<span data-size={size} data-variant={variant}>{children}</span>
|
|
),
|
|
}));
|
|
|
|
// Mock the UserStatusTag component
|
|
vi.mock('./UserStatusTag', () => ({
|
|
UserStatusTag: ({ status }: any) => <span data-testid="status-tag">{status}</span>,
|
|
}));
|
|
|
|
describe('AdminUsersTable', () => {
|
|
const mockUsers = [
|
|
{
|
|
id: '1',
|
|
displayName: 'John Doe',
|
|
email: 'john@example.com',
|
|
roles: ['admin'],
|
|
status: 'active',
|
|
lastLoginAt: '2024-01-15T10:30:00Z',
|
|
},
|
|
{
|
|
id: '2',
|
|
displayName: 'Jane Smith',
|
|
email: 'jane@example.com',
|
|
roles: ['user'],
|
|
status: 'suspended',
|
|
lastLoginAt: '2024-01-14T15:45:00Z',
|
|
},
|
|
{
|
|
id: '3',
|
|
displayName: 'Bob Johnson',
|
|
email: 'bob@example.com',
|
|
roles: ['user'],
|
|
status: 'active',
|
|
lastLoginAt: null,
|
|
},
|
|
];
|
|
|
|
const defaultProps = {
|
|
users: mockUsers,
|
|
selectedUserIds: [],
|
|
onSelectUser: vi.fn(),
|
|
onSelectAll: vi.fn(),
|
|
onUpdateStatus: vi.fn(),
|
|
onDeleteUser: vi.fn(),
|
|
deletingUserId: null,
|
|
};
|
|
|
|
it('should render table headers', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getByText('User')).toBeTruthy();
|
|
expect(screen.getByText('Roles')).toBeTruthy();
|
|
expect(screen.getByText('Status')).toBeTruthy();
|
|
expect(screen.getByText('Last Login')).toBeTruthy();
|
|
expect(screen.getByText('Actions')).toBeTruthy();
|
|
});
|
|
|
|
it('should render user rows', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getByText('John Doe')).toBeTruthy();
|
|
expect(screen.getByText('john@example.com')).toBeTruthy();
|
|
expect(screen.getByText('Jane Smith')).toBeTruthy();
|
|
expect(screen.getByText('jane@example.com')).toBeTruthy();
|
|
expect(screen.getByText('Bob Johnson')).toBeTruthy();
|
|
expect(screen.getByText('bob@example.com')).toBeTruthy();
|
|
});
|
|
|
|
it('should render user roles', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getByText('admin')).toBeTruthy();
|
|
expect(screen.getByText('user')).toBeTruthy();
|
|
});
|
|
|
|
it('should render user status tags', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getAllByTestId('status-tag')).toHaveLength(3);
|
|
});
|
|
|
|
it('should render last login dates', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getByText('1/15/2024')).toBeTruthy();
|
|
expect(screen.getByText('1/14/2024')).toBeTruthy();
|
|
expect(screen.getByText('Never')).toBeTruthy();
|
|
});
|
|
|
|
it('should render select all checkbox', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getByLabelText('Select all users')).toBeTruthy();
|
|
});
|
|
|
|
it('should render individual user checkboxes', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getByLabelText('Select user John Doe')).toBeTruthy();
|
|
expect(screen.getByLabelText('Select user Jane Smith')).toBeTruthy();
|
|
expect(screen.getByLabelText('Select user Bob Johnson')).toBeTruthy();
|
|
});
|
|
|
|
it('should render suspend button for active users', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getByText('Suspend')).toBeTruthy();
|
|
});
|
|
|
|
it('should render activate button for suspended users', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getByText('Activate')).toBeTruthy();
|
|
});
|
|
|
|
it('should render delete button for all users', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getAllByTitle('Delete')).toHaveLength(3);
|
|
});
|
|
|
|
it('should render more button for all users', () => {
|
|
render(<AdminUsersTable {...defaultProps} />);
|
|
|
|
expect(screen.getAllByTitle('More')).toHaveLength(3);
|
|
});
|
|
|
|
it('should highlight selected rows', () => {
|
|
const props = {
|
|
...defaultProps,
|
|
selectedUserIds: ['1', '3'],
|
|
};
|
|
|
|
render(<AdminUsersTable {...props} />);
|
|
|
|
// Check that selected rows have highlight variant
|
|
const rows = screen.getAllByRole('row');
|
|
expect(rows[1]).toHaveAttribute('data-variant', 'highlight');
|
|
expect(rows[3]).toHaveAttribute('data-variant', 'highlight');
|
|
});
|
|
|
|
it('should disable delete button when deleting', () => {
|
|
const props = {
|
|
...defaultProps,
|
|
deletingUserId: '1',
|
|
};
|
|
|
|
render(<AdminUsersTable {...props} />);
|
|
|
|
const deleteButtons = screen.getAllByTitle('Delete');
|
|
expect(deleteButtons[0]).toBeDisabled();
|
|
});
|
|
|
|
it('should call onSelectUser when checkbox is clicked', () => {
|
|
const onSelectUser = vi.fn();
|
|
const props = {
|
|
...defaultProps,
|
|
onSelectUser,
|
|
};
|
|
|
|
render(<AdminUsersTable {...props} />);
|
|
|
|
const checkboxes = screen.getAllByTestId('checkbox');
|
|
fireEvent.click(checkboxes[1]); // Click first user checkbox
|
|
|
|
expect(onSelectUser).toHaveBeenCalledWith('1');
|
|
});
|
|
|
|
it('should call onSelectAll when select all checkbox is clicked', () => {
|
|
const onSelectAll = vi.fn();
|
|
const props = {
|
|
...defaultProps,
|
|
onSelectAll,
|
|
};
|
|
|
|
render(<AdminUsersTable {...props} />);
|
|
|
|
const selectAllCheckbox = screen.getByLabelText('Select all users');
|
|
fireEvent.click(selectAllCheckbox);
|
|
|
|
expect(onSelectAll).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should call onUpdateStatus when suspend button is clicked', () => {
|
|
const onUpdateStatus = vi.fn();
|
|
const props = {
|
|
...defaultProps,
|
|
onUpdateStatus,
|
|
};
|
|
|
|
render(<AdminUsersTable {...props} />);
|
|
|
|
const suspendButtons = screen.getAllByText('Suspend');
|
|
fireEvent.click(suspendButtons[0]);
|
|
|
|
expect(onUpdateStatus).toHaveBeenCalledWith('1', 'suspended');
|
|
});
|
|
|
|
it('should call onUpdateStatus when activate button is clicked', () => {
|
|
const onUpdateStatus = vi.fn();
|
|
const props = {
|
|
...defaultProps,
|
|
onUpdateStatus,
|
|
};
|
|
|
|
render(<AdminUsersTable {...props} />);
|
|
|
|
const activateButtons = screen.getAllByText('Activate');
|
|
fireEvent.click(activateButtons[0]);
|
|
|
|
expect(onUpdateStatus).toHaveBeenCalledWith('2', 'active');
|
|
});
|
|
|
|
it('should call onDeleteUser when delete button is clicked', () => {
|
|
const onDeleteUser = vi.fn();
|
|
const props = {
|
|
...defaultProps,
|
|
onDeleteUser,
|
|
};
|
|
|
|
render(<AdminUsersTable {...props} />);
|
|
|
|
const deleteButtons = screen.getAllByTitle('Delete');
|
|
fireEvent.click(deleteButtons[0]);
|
|
|
|
expect(onDeleteUser).toHaveBeenCalledWith('1');
|
|
});
|
|
|
|
it('should render empty table when no users', () => {
|
|
const props = {
|
|
...defaultProps,
|
|
users: [],
|
|
};
|
|
|
|
render(<AdminUsersTable {...props} />);
|
|
|
|
// Should render table headers but no rows
|
|
expect(screen.getByText('User')).toBeTruthy();
|
|
expect(screen.getByText('Roles')).toBeTruthy();
|
|
expect(screen.getByText('Status')).toBeTruthy();
|
|
expect(screen.getByText('Last Login')).toBeTruthy();
|
|
expect(screen.getByText('Actions')).toBeTruthy();
|
|
});
|
|
|
|
it('should render with all users selected', () => {
|
|
const props = {
|
|
...defaultProps,
|
|
selectedUserIds: ['1', '2', '3'],
|
|
};
|
|
|
|
render(<AdminUsersTable {...props} />);
|
|
|
|
const selectAllCheckbox = screen.getByLabelText('Select all users');
|
|
expect(selectAllCheckbox).toBeChecked();
|
|
});
|
|
|
|
it('should render with some users selected', () => {
|
|
const props = {
|
|
...defaultProps,
|
|
selectedUserIds: ['1', '2'],
|
|
};
|
|
|
|
render(<AdminUsersTable {...props} />);
|
|
|
|
const selectAllCheckbox = screen.getByLabelText('Select all users');
|
|
expect(selectAllCheckbox).not.toBeChecked();
|
|
});
|
|
});
|