add tests
Some checks failed
Contract Testing / contract-tests (push) Failing after 6m7s
Contract Testing / contract-snapshot (push) Failing after 4m46s

This commit is contained in:
2026-01-22 11:52:42 +01:00
parent 40bc15ff61
commit fb1221701d
112 changed files with 30625 additions and 1059 deletions

View File

@@ -0,0 +1,361 @@
/**
* 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();
});
});