Files
fast-next-template/frontend/tests/components/settings/SessionCard.test.tsx
Felipe Cardoso 96df7edf88 Refactor useAuth hook, settings components, and docs for formatting and readability improvements
- Consolidated multi-line arguments into single lines where appropriate in `useAuth`.
- Improved spacing and readability in data processing across components (`ProfileSettingsForm`, `PasswordChangeForm`, `SessionCard`).
- Applied consistent table and markdown formatting in design system docs (e.g., `README.md`, `08-ai-guidelines.md`, `00-quick-start.md`).
- Updated code snippets to ensure adherence to Prettier rules and streamlined JSX structures.
2025-11-10 11:03:45 +01:00

143 lines
4.5 KiB
TypeScript

/**
* Tests for SessionCard Component
*/
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { SessionCard } from '@/components/settings/SessionCard';
import type { Session } from '@/lib/api/hooks/useSession';
describe('SessionCard', () => {
const mockOnRevoke = jest.fn();
const currentSession: Session = {
id: '1',
device_name: 'Chrome on Mac',
ip_address: '192.168.1.1',
location_city: 'San Francisco',
location_country: 'USA',
last_used_at: '2024-01-01T12:00:00Z',
created_at: '2024-01-01T00:00:00Z',
expires_at: '2024-01-08T00:00:00Z',
is_current: true,
};
const otherSession: Session = {
...currentSession,
id: '2',
device_name: 'Firefox on Windows',
location_city: 'New York',
is_current: false,
};
beforeEach(() => {
jest.clearAllMocks();
});
it('renders session information', () => {
render(<SessionCard session={currentSession} onRevoke={mockOnRevoke} />);
expect(screen.getByText('Chrome on Mac')).toBeInTheDocument();
expect(screen.getByText(/San Francisco.*USA/)).toBeInTheDocument();
expect(screen.getByText('192.168.1.1')).toBeInTheDocument();
});
it('shows current session badge', () => {
render(<SessionCard session={currentSession} onRevoke={mockOnRevoke} />);
expect(screen.getByText('Current Session')).toBeInTheDocument();
});
it('does not show revoke button for current session', () => {
render(<SessionCard session={currentSession} onRevoke={mockOnRevoke} />);
expect(screen.queryByRole('button', { name: /revoke/i })).not.toBeInTheDocument();
});
it('shows revoke button for other sessions', () => {
render(<SessionCard session={otherSession} onRevoke={mockOnRevoke} />);
expect(screen.getByRole('button', { name: /revoke/i })).toBeInTheDocument();
});
it('opens confirmation dialog on revoke click', async () => {
render(<SessionCard session={otherSession} onRevoke={mockOnRevoke} />);
fireEvent.click(screen.getByRole('button', { name: /revoke/i }));
await waitFor(() => {
expect(screen.getByText('Revoke Session?')).toBeInTheDocument();
});
});
it('calls onRevoke when confirmed', async () => {
render(<SessionCard session={otherSession} onRevoke={mockOnRevoke} />);
fireEvent.click(screen.getByRole('button', { name: /revoke/i }));
await waitFor(() => {
expect(screen.getByText('Revoke Session?')).toBeInTheDocument();
});
const confirmButton = screen.getByRole('button', { name: /revoke session/i });
fireEvent.click(confirmButton);
await waitFor(() => {
expect(mockOnRevoke).toHaveBeenCalledWith('2');
});
});
it('closes dialog on cancel', async () => {
render(<SessionCard session={otherSession} onRevoke={mockOnRevoke} />);
fireEvent.click(screen.getByRole('button', { name: /revoke/i }));
await waitFor(() => {
expect(screen.getByText('Revoke Session?')).toBeInTheDocument();
});
fireEvent.click(screen.getByRole('button', { name: /cancel/i }));
await waitFor(() => {
expect(screen.queryByText('Revoke Session?')).not.toBeInTheDocument();
});
expect(mockOnRevoke).not.toHaveBeenCalled();
});
it('handles missing location gracefully', () => {
const sessionWithoutLocation: Session = {
...otherSession,
location_city: null,
location_country: null,
};
render(<SessionCard session={sessionWithoutLocation} onRevoke={mockOnRevoke} />);
expect(screen.queryByText(/San Francisco/)).not.toBeInTheDocument();
// Component hides location when unknown, so it should not be displayed
expect(screen.queryByText(/location/i)).not.toBeInTheDocument();
});
it('handles missing device name gracefully', () => {
const sessionWithoutDevice: Session = {
...otherSession,
device_name: null,
};
render(<SessionCard session={sessionWithoutDevice} onRevoke={mockOnRevoke} />);
expect(screen.getByText('Unknown device')).toBeInTheDocument();
});
it('disables revoke button while revoking', () => {
render(<SessionCard session={otherSession} onRevoke={mockOnRevoke} isRevoking />);
const revokeButton = screen.getByRole('button', { name: /revoke/i });
expect(revokeButton).toBeDisabled();
});
it('highlights current session with border', () => {
const { container } = render(<SessionCard session={currentSession} onRevoke={mockOnRevoke} />);
const card = container.querySelector('.border-primary');
expect(card).toBeInTheDocument();
});
});