import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { AuthInput } from './AuthInput';
import { AuthButton } from './AuthButton';
import { AuthFormField } from './AuthFormField';
import { AuthErrorMessage } from './AuthErrorMessage';
describe('AuthInput', () => {
it('should render input with label', () => {
render();
expect(screen.getByLabelText('Email')).toBeInTheDocument();
});
it('should display error message when error prop is provided', () => {
render();
expect(screen.getByText('Invalid email')).toBeInTheDocument();
expect(screen.getByRole('alert')).toBeInTheDocument();
});
it('should have aria-invalid when error is present', () => {
render();
const input = screen.getByRole('textbox');
expect(input).toHaveAttribute('aria-invalid', 'true');
});
it('should apply error styles when error is present', () => {
render();
const input = screen.getByRole('textbox');
expect(input.className).toContain('border-red-500');
});
it('should handle user input', async () => {
const user = userEvent.setup();
const handleChange = vi.fn();
render(
,
);
const input = screen.getByLabelText('Email');
await user.type(input, 'test@example.com');
expect(handleChange).toHaveBeenCalled();
expect(input).toHaveValue('test@example.com');
});
it('should support all standard input props', () => {
render(
,
);
const input = screen.getByLabelText('Password');
expect(input).toHaveAttribute('type', 'password');
expect(input).toHaveAttribute('placeholder', 'Enter password');
expect(input).toBeRequired();
});
});
describe('AuthButton', () => {
it('should render button with children', () => {
render(Submit);
expect(screen.getByRole('button', { name: 'Submit' })).toBeInTheDocument();
});
it('should show loading state', () => {
render(Submit);
expect(screen.getByText('Chargement...')).toBeInTheDocument();
expect(screen.getByRole('button')).toBeDisabled();
expect(screen.getByRole('button')).toHaveAttribute('aria-busy', 'true');
});
it('should be disabled when loading', () => {
render(Submit);
expect(screen.getByRole('button')).toBeDisabled();
});
it('should be disabled when disabled prop is true', () => {
render(Submit);
expect(screen.getByRole('button')).toBeDisabled();
});
it('should apply primary variant styles by default', () => {
render(Submit);
const button = screen.getByRole('button');
expect(button.className).toContain('bg-blue-600');
});
it('should apply secondary variant styles', () => {
render(Cancel);
const button = screen.getByRole('button');
expect(button.className).toContain('bg-gray-200');
});
it('should handle click events', async () => {
const user = userEvent.setup();
const handleClick = vi.fn();
render(Click me);
const button = screen.getByRole('button');
await user.click(button);
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('should not trigger click when disabled', async () => {
const user = userEvent.setup();
const handleClick = vi.fn();
render(
Click me
,
);
const button = screen.getByRole('button');
await user.click(button);
expect(handleClick).not.toHaveBeenCalled();
});
});
describe('AuthFormField', () => {
it('should render label and children', () => {
render(
,
);
expect(screen.getByText('Email')).toBeInTheDocument();
});
it('should show required indicator', () => {
render(
,
);
const label = screen.getByText('Email');
expect(label.textContent).toContain('*');
});
it('should display error message', () => {
render(
,
);
expect(screen.getByText('Invalid email')).toBeInTheDocument();
expect(screen.getByRole('alert')).toBeInTheDocument();
});
it('should display help text when no error', () => {
render(
,
);
expect(screen.getByText('Enter your email address')).toBeInTheDocument();
});
it('should not display help text when error is present', () => {
render(
,
);
expect(screen.getByText('Invalid email')).toBeInTheDocument();
expect(
screen.queryByText('Enter your email address'),
).not.toBeInTheDocument();
});
});
describe('AuthErrorMessage', () => {
it('should render error message', () => {
render();
expect(screen.getByText('An error occurred')).toBeInTheDocument();
expect(screen.getByRole('alert')).toBeInTheDocument();
});
it('should not render when message is empty', () => {
const { container } = render();
expect(container.firstChild).toBeNull();
});
it('should have aria-live attribute', () => {
render();
const alert = screen.getByRole('alert');
expect(alert).toHaveAttribute('aria-live', 'polite');
});
it('should apply custom className', () => {
render();
const alert = screen.getByRole('alert');
expect(alert.className).toContain('custom-class');
});
it('should support custom id', () => {
render();
const alert = screen.getByRole('alert');
expect(alert).toHaveAttribute('id', 'custom-error-id');
});
});