247 lines
8.3 KiB
TypeScript
247 lines
8.3 KiB
TypeScript
import { render, screen, fireEvent } from '@testing-library/react';
|
|
import { describe, it, expect } from 'vitest';
|
|
import { ActionList } from './ActionList';
|
|
import { ActionItem } from '@/lib/queries/ActionsPageQuery';
|
|
|
|
describe('ActionList', () => {
|
|
const mockActions: ActionItem[] = [
|
|
{
|
|
id: 'action-1',
|
|
timestamp: '2024-01-15T10:30:00Z',
|
|
type: 'USER_UPDATE',
|
|
initiator: 'John Doe',
|
|
status: 'COMPLETED',
|
|
details: 'Updated profile settings',
|
|
},
|
|
{
|
|
id: 'action-2',
|
|
timestamp: '2024-01-15T11:45:00Z',
|
|
type: 'ONBOARDING',
|
|
initiator: 'Jane Smith',
|
|
status: 'PENDING',
|
|
details: 'Started onboarding process',
|
|
},
|
|
{
|
|
id: 'action-3',
|
|
timestamp: '2024-01-15T12:00:00Z',
|
|
type: 'USER_UPDATE',
|
|
initiator: 'Bob Johnson',
|
|
status: 'FAILED',
|
|
details: 'Failed to update email',
|
|
},
|
|
{
|
|
id: 'action-4',
|
|
timestamp: '2024-01-15T13:15:00Z',
|
|
type: 'ONBOARDING',
|
|
initiator: 'Alice Brown',
|
|
status: 'IN_PROGRESS',
|
|
details: 'Completing verification',
|
|
},
|
|
];
|
|
|
|
describe('Rendering states', () => {
|
|
it('renders table headers', () => {
|
|
render(<ActionList actions={mockActions} />);
|
|
|
|
expect(screen.getByText('Timestamp')).toBeDefined();
|
|
expect(screen.getByText('Type')).toBeDefined();
|
|
expect(screen.getByText('Initiator')).toBeDefined();
|
|
expect(screen.getByText('Status')).toBeDefined();
|
|
expect(screen.getByText('Details')).toBeDefined();
|
|
});
|
|
|
|
it('renders all action rows', () => {
|
|
render(<ActionList actions={mockActions} />);
|
|
|
|
mockActions.forEach((action) => {
|
|
expect(screen.getByText(action.timestamp)).toBeDefined();
|
|
expect(screen.getAllByText(action.type).length).toBeGreaterThan(0);
|
|
expect(screen.getByText(action.initiator)).toBeDefined();
|
|
expect(screen.getByText(action.details)).toBeDefined();
|
|
});
|
|
});
|
|
|
|
it('renders action status badges', () => {
|
|
render(<ActionList actions={mockActions} />);
|
|
|
|
// Check that status badges are rendered for each action
|
|
expect(screen.getByText('COMPLETED')).toBeDefined();
|
|
expect(screen.getByText('PENDING')).toBeDefined();
|
|
expect(screen.getByText('FAILED')).toBeDefined();
|
|
expect(screen.getByText('IN PROGRESS')).toBeDefined();
|
|
});
|
|
|
|
it('renders empty table when no actions provided', () => {
|
|
render(<ActionList actions={[]} />);
|
|
|
|
// Table headers should still be visible
|
|
expect(screen.getByText('Timestamp')).toBeDefined();
|
|
expect(screen.getByText('Type')).toBeDefined();
|
|
expect(screen.getByText('Initiator')).toBeDefined();
|
|
expect(screen.getByText('Status')).toBeDefined();
|
|
expect(screen.getByText('Details')).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('Interaction behavior', () => {
|
|
it('renders clickable rows', () => {
|
|
render(<ActionList actions={mockActions} />);
|
|
|
|
// Check that rows have clickable attribute
|
|
const rows = screen.getAllByRole('row');
|
|
// Skip the header row
|
|
const dataRows = rows.slice(1);
|
|
|
|
dataRows.forEach((row) => {
|
|
expect(row).toBeDefined();
|
|
});
|
|
});
|
|
|
|
it('renders row with key based on action id', () => {
|
|
const { container } = render(<ActionList actions={mockActions} />);
|
|
|
|
// Verify that each row has a unique key
|
|
const rows = container.querySelectorAll('tbody tr');
|
|
expect(rows.length).toBe(mockActions.length);
|
|
|
|
mockActions.forEach((action, index) => {
|
|
const row = rows[index];
|
|
expect(row).toBeDefined();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Visual presentation', () => {
|
|
it('renders table structure correctly', () => {
|
|
const { container } = render(<ActionList actions={mockActions} />);
|
|
|
|
// Verify table structure
|
|
const table = container.querySelector('table');
|
|
expect(table).toBeDefined();
|
|
|
|
const thead = container.querySelector('thead');
|
|
expect(thead).toBeDefined();
|
|
|
|
const tbody = container.querySelector('tbody');
|
|
expect(tbody).toBeDefined();
|
|
});
|
|
|
|
it('renders timestamp in monospace font', () => {
|
|
render(<ActionList actions={mockActions} />);
|
|
|
|
// The timestamp should be rendered with monospace font
|
|
const timestamp = screen.getByText('2024-01-15T10:30:00Z');
|
|
expect(timestamp).toBeDefined();
|
|
});
|
|
|
|
it('renders type with medium weight', () => {
|
|
render(<ActionList actions={mockActions} />);
|
|
|
|
// The type should be rendered with medium weight
|
|
const types = screen.getAllByText('USER_UPDATE');
|
|
expect(types.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it('renders initiator with low variant', () => {
|
|
render(<ActionList actions={mockActions} />);
|
|
|
|
// The initiator should be rendered with low variant
|
|
const initiator = screen.getByText('John Doe');
|
|
expect(initiator).toBeDefined();
|
|
});
|
|
|
|
it('renders details with low variant', () => {
|
|
render(<ActionList actions={mockActions} />);
|
|
|
|
// The details should be rendered with low variant
|
|
const details = screen.getByText('Updated profile settings');
|
|
expect(details).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('Edge cases', () => {
|
|
it('handles single action', () => {
|
|
const singleAction = [mockActions[0]];
|
|
render(<ActionList actions={singleAction} />);
|
|
|
|
expect(screen.getByText(singleAction[0].timestamp)).toBeDefined();
|
|
expect(screen.getByText(singleAction[0].type)).toBeDefined();
|
|
expect(screen.getByText(singleAction[0].initiator)).toBeDefined();
|
|
expect(screen.getByText(singleAction[0].details)).toBeDefined();
|
|
});
|
|
|
|
it('handles actions with long details', () => {
|
|
const longDetailsAction: ActionItem = {
|
|
id: 'action-long',
|
|
timestamp: '2024-01-15T14:00:00Z',
|
|
type: 'USER_UPDATE',
|
|
initiator: 'Long Name User',
|
|
status: 'COMPLETED',
|
|
details: 'This is a very long details text that might wrap to multiple lines and should still be displayed correctly in the table',
|
|
};
|
|
|
|
render(<ActionList actions={[longDetailsAction]} />);
|
|
|
|
expect(screen.getByText(longDetailsAction.details)).toBeDefined();
|
|
});
|
|
|
|
it('handles actions with special characters in details', () => {
|
|
const specialDetailsAction: ActionItem = {
|
|
id: 'action-special',
|
|
timestamp: '2024-01-15T15:00:00Z',
|
|
type: 'USER_UPDATE',
|
|
initiator: 'Special User',
|
|
status: 'COMPLETED',
|
|
details: 'Updated settings & preferences (admin)',
|
|
};
|
|
|
|
render(<ActionList actions={[specialDetailsAction]} />);
|
|
|
|
expect(screen.getByText(specialDetailsAction.details)).toBeDefined();
|
|
});
|
|
|
|
it('handles actions with unicode characters', () => {
|
|
const unicodeAction: ActionItem = {
|
|
id: 'action-unicode',
|
|
timestamp: '2024-01-15T16:00:00Z',
|
|
type: 'USER_UPDATE',
|
|
initiator: 'Über User',
|
|
status: 'COMPLETED',
|
|
details: 'Updated profile with emoji 🚀',
|
|
};
|
|
|
|
render(<ActionList actions={[unicodeAction]} />);
|
|
|
|
expect(screen.getByText(unicodeAction.details)).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('Status badge integration', () => {
|
|
it('renders ActionStatusBadge for each action', () => {
|
|
render(<ActionList actions={mockActions} />);
|
|
|
|
// Each action should have a status badge
|
|
const completedBadge = screen.getByText('COMPLETED');
|
|
const pendingBadge = screen.getByText('PENDING');
|
|
const failedBadge = screen.getByText('FAILED');
|
|
const inProgressBadge = screen.getByText('IN PROGRESS');
|
|
|
|
expect(completedBadge).toBeDefined();
|
|
expect(pendingBadge).toBeDefined();
|
|
expect(failedBadge).toBeDefined();
|
|
expect(inProgressBadge).toBeDefined();
|
|
});
|
|
|
|
it('renders correct badge variant for each status', () => {
|
|
render(<ActionList actions={mockActions} />);
|
|
|
|
// Verify that badges are rendered with correct variants
|
|
// This is verified by the ActionStatusBadge component tests
|
|
expect(screen.getByText('COMPLETED')).toBeDefined();
|
|
expect(screen.getByText('PENDING')).toBeDefined();
|
|
expect(screen.getByText('FAILED')).toBeDefined();
|
|
expect(screen.getByText('IN PROGRESS')).toBeDefined();
|
|
});
|
|
});
|
|
});
|