add tests
This commit is contained in:
246
apps/website/components/actions/ActionList.test.tsx
Normal file
246
apps/website/components/actions/ActionList.test.tsx
Normal file
@@ -0,0 +1,246 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user