veza/apps/web/src/features/auth/components/AuthInput.test.tsx
2025-12-12 21:34:34 -05:00

217 lines
6.7 KiB
TypeScript

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(<AuthInput label="Email" id="email-input" />);
expect(screen.getByLabelText('Email')).toBeInTheDocument();
});
it('should display error message when error prop is provided', () => {
render(<AuthInput error="Invalid email" id="email-input" />);
expect(screen.getByText('Invalid email')).toBeInTheDocument();
expect(screen.getByRole('alert')).toBeInTheDocument();
});
it('should have aria-invalid when error is present', () => {
render(<AuthInput error="Error message" id="email-input" />);
const input = screen.getByRole('textbox');
expect(input).toHaveAttribute('aria-invalid', 'true');
});
it('should apply error styles when error is present', () => {
render(<AuthInput error="Error" id="email-input" />);
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(
<AuthInput
label="Email"
id="email-input"
onChange={handleChange}
type="email"
/>,
);
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(
<AuthInput
label="Password"
id="password-input"
type="password"
placeholder="Enter password"
required
/>,
);
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(<AuthButton>Submit</AuthButton>);
expect(screen.getByRole('button', { name: 'Submit' })).toBeInTheDocument();
});
it('should show loading state', () => {
render(<AuthButton loading>Submit</AuthButton>);
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(<AuthButton loading>Submit</AuthButton>);
expect(screen.getByRole('button')).toBeDisabled();
});
it('should be disabled when disabled prop is true', () => {
render(<AuthButton disabled>Submit</AuthButton>);
expect(screen.getByRole('button')).toBeDisabled();
});
it('should apply primary variant styles by default', () => {
render(<AuthButton>Submit</AuthButton>);
const button = screen.getByRole('button');
expect(button.className).toContain('bg-blue-600');
});
it('should apply secondary variant styles', () => {
render(<AuthButton variant="secondary">Cancel</AuthButton>);
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(<AuthButton onClick={handleClick}>Click me</AuthButton>);
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(
<AuthButton disabled onClick={handleClick}>
Click me
</AuthButton>,
);
const button = screen.getByRole('button');
await user.click(button);
expect(handleClick).not.toHaveBeenCalled();
});
});
describe('AuthFormField', () => {
it('should render label and children', () => {
render(
<AuthFormField label="Email">
<input type="email" />
</AuthFormField>,
);
expect(screen.getByText('Email')).toBeInTheDocument();
});
it('should show required indicator', () => {
render(
<AuthFormField label="Email" required>
<input type="email" />
</AuthFormField>,
);
const label = screen.getByText('Email');
expect(label.textContent).toContain('*');
});
it('should display error message', () => {
render(
<AuthFormField label="Email" error="Invalid email">
<input type="email" />
</AuthFormField>,
);
expect(screen.getByText('Invalid email')).toBeInTheDocument();
expect(screen.getByRole('alert')).toBeInTheDocument();
});
it('should display help text when no error', () => {
render(
<AuthFormField label="Email" helpText="Enter your email address">
<input type="email" />
</AuthFormField>,
);
expect(screen.getByText('Enter your email address')).toBeInTheDocument();
});
it('should not display help text when error is present', () => {
render(
<AuthFormField
label="Email"
error="Invalid email"
helpText="Enter your email address"
>
<input type="email" />
</AuthFormField>,
);
expect(screen.getByText('Invalid email')).toBeInTheDocument();
expect(
screen.queryByText('Enter your email address'),
).not.toBeInTheDocument();
});
});
describe('AuthErrorMessage', () => {
it('should render error message', () => {
render(<AuthErrorMessage message="An error occurred" />);
expect(screen.getByText('An error occurred')).toBeInTheDocument();
expect(screen.getByRole('alert')).toBeInTheDocument();
});
it('should not render when message is empty', () => {
const { container } = render(<AuthErrorMessage message="" />);
expect(container.firstChild).toBeNull();
});
it('should have aria-live attribute', () => {
render(<AuthErrorMessage message="Error" />);
const alert = screen.getByRole('alert');
expect(alert).toHaveAttribute('aria-live', 'polite');
});
it('should apply custom className', () => {
render(<AuthErrorMessage message="Error" className="custom-class" />);
const alert = screen.getByRole('alert');
expect(alert.className).toContain('custom-class');
});
it('should support custom id', () => {
render(<AuthErrorMessage message="Error" id="custom-error-id" />);
const alert = screen.getByRole('alert');
expect(alert).toHaveAttribute('id', 'custom-error-id');
});
});