2026-01-07 09:31:02 +00:00
|
|
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
|
|
|
import { describe, it, expect, vi } from 'vitest';
|
|
|
|
|
import { Input, SearchInput } from './input';
|
|
|
|
|
import { Search } from 'lucide-react';
|
|
|
|
|
|
|
|
|
|
describe('Input Component', () => {
|
|
|
|
|
it('renders with default props', () => {
|
|
|
|
|
render(<Input placeholder="Enter text" />);
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
const input = screen.getByPlaceholderText('Enter text');
|
|
|
|
|
expect(input).toBeInTheDocument();
|
refactor: Phase 3a — Global color class migration to SUMI semantics
- Replace all kodo-* color classes across ~100 TSX files:
kodo-void → background, kodo-ink → card, kodo-graphite → muted,
kodo-steel → muted-foreground, kodo-cyan → primary, kodo-magenta → destructive,
kodo-lime → success, kodo-red → destructive, kodo-gold → warning
- Replace cyan-500, magenta-500, lime-500 default Tailwind colors with
semantic equivalents (primary, destructive, success)
- Fix WaveformVisualizer hardcoded hex colors to SUMI values
- Delete global-effects.css (conflicting, redundant with index.css)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 00:51:49 +00:00
|
|
|
expect(input).toHaveClass('bg-muted');
|
2026-01-07 09:31:02 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('renders with label', () => {
|
|
|
|
|
render(<Input label="Username" id="username" />);
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
const label = screen.getByText('Username');
|
|
|
|
|
expect(label).toBeInTheDocument();
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
const input = screen.getByRole('textbox');
|
|
|
|
|
expect(input).toBeInTheDocument();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('renders with icon', () => {
|
|
|
|
|
const icon = <Search className="w-4 h-4" />;
|
|
|
|
|
render(<Input icon={icon} placeholder="Search" />);
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
const input = screen.getByPlaceholderText('Search');
|
|
|
|
|
expect(input).toBeInTheDocument();
|
|
|
|
|
expect(input).toHaveClass('pl-11');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('handles onChange event', () => {
|
|
|
|
|
const handleChange = vi.fn();
|
|
|
|
|
render(<Input onChange={handleChange} />);
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
const input = screen.getByRole('textbox');
|
|
|
|
|
fireEvent.change(input, { target: { value: 'test' } });
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
expect(handleChange).toHaveBeenCalledTimes(1);
|
|
|
|
|
expect(input).toHaveValue('test');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('applies custom className', () => {
|
|
|
|
|
render(<Input className="custom-class" />);
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
const input = screen.getByRole('textbox');
|
|
|
|
|
expect(input).toHaveClass('custom-class');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('handles disabled state', () => {
|
|
|
|
|
render(<Input disabled />);
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
const input = screen.getByRole('textbox');
|
|
|
|
|
expect(input).toBeDisabled();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('handles different input types', () => {
|
|
|
|
|
const { rerender } = render(<Input type="email" />);
|
|
|
|
|
let input = screen.getByRole('textbox');
|
|
|
|
|
expect(input).toHaveAttribute('type', 'email');
|
|
|
|
|
|
|
|
|
|
rerender(<Input type="password" />);
|
|
|
|
|
input = screen.getByDisplayValue('');
|
|
|
|
|
expect(input).toHaveAttribute('type', 'password');
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('SearchInput Component', () => {
|
|
|
|
|
it('renders search input', () => {
|
|
|
|
|
render(<SearchInput placeholder="Search platform..." />);
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
const input = screen.getByPlaceholderText('Search platform...');
|
|
|
|
|
expect(input).toBeInTheDocument();
|
|
|
|
|
expect(input).toHaveAttribute('type', 'search');
|
|
|
|
|
expect(input).toHaveClass('rounded-full');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('handles onChange event', () => {
|
|
|
|
|
const handleChange = vi.fn();
|
|
|
|
|
render(<SearchInput onChange={handleChange} />);
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
const input = screen.getByRole('searchbox');
|
|
|
|
|
fireEvent.change(input, { target: { value: 'test query' } });
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
expect(handleChange).toHaveBeenCalledTimes(1);
|
|
|
|
|
expect(input).toHaveValue('test query');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('applies custom className', () => {
|
|
|
|
|
render(<SearchInput className="custom-search" />);
|
2026-01-13 18:47:57 +00:00
|
|
|
|
2026-01-07 09:31:02 +00:00
|
|
|
const input = screen.getByRole('searchbox');
|
|
|
|
|
expect(input).toHaveClass('custom-search');
|
|
|
|
|
});
|
|
|
|
|
});
|