import React from 'react'; import { describe, it, expect, vi } from 'vitest'; import { render, fireEvent } from '@testing-library/react'; import { PixelPasswordInput } from '../../forms/PixelPasswordInput'; describe('PixelPasswordInput', () => { it('renders type=password by default with the Show toggle', () => { const { container, getByRole } = render(); const input = container.querySelector('input') as HTMLInputElement; expect(input.type).toBe('password'); const toggle = getByRole('button', { name: 'Show' }); expect(toggle.getAttribute('aria-pressed')).toBe('false'); }); it('toggle flips visibility: type becomes text, label becomes Hide', () => { const { container, getByRole } = render(); const input = container.querySelector('input') as HTMLInputElement; const toggle = getByRole('button', { name: 'Show' }); fireEvent.click(toggle); expect(input.type).toBe('text'); expect(toggle.getAttribute('aria-label')).toBe('Hide'); expect(toggle.getAttribute('aria-pressed')).toBe('true'); fireEvent.click(toggle); expect(input.type).toBe('password'); expect(toggle.getAttribute('aria-label')).toBe('Show'); }); it('honors custom toggleLabels', () => { const { getByRole } = render( , ); const toggle = getByRole('button', { name: 'Ver' }); fireEvent.click(toggle); expect(toggle.getAttribute('aria-label')).toBe('Ocultar'); }); it('fires onChange as the user types (uncontrolled)', () => { const onChange = vi.fn(); const { container } = render(); const input = container.querySelector('input') as HTMLInputElement; fireEvent.change(input, { target: { value: 'hunter2' } }); expect(onChange).toHaveBeenCalledTimes(1); expect(input.value).toBe('hunter2'); }); it('disabled disables both the input and the visibility toggle', () => { const { container, getByRole } = render(); expect((container.querySelector('input') as HTMLInputElement).disabled).toBe(true); expect((getByRole('button', { name: 'Show' }) as HTMLButtonElement).disabled).toBe(true); }); it('renders label and hint via FieldShell', () => { const { getByText } = render( , ); expect(getByText('Password')).toBeTruthy(); expect(getByText('Min 8 chars')).toBeTruthy(); }); it('error sets aria-invalid and the red border class', () => { const { container, getByText } = render( , ); const input = container.querySelector('input') as HTMLInputElement; expect(input.getAttribute('aria-invalid')).toBe('true'); expect(input.className).toContain('border-retro-red/60'); expect(getByText('Too short')).toBeTruthy(); }); it('toggle is excluded from the Tab order (tabIndex=-1)', () => { const { getByRole } = render(); expect((getByRole('button', { name: 'Show' }) as HTMLButtonElement).tabIndex).toBe(-1); }); it('forwards ref to the native input', () => { const ref = React.createRef(); render(); expect(ref.current).toBeInstanceOf(HTMLInputElement); expect(ref.current!.type).toBe('password'); }); });