diff --git a/src/internal/components/TextInput.test.tsx b/src/internal/components/TextInput.test.tsx new file mode 100644 index 0000000000..f72f89ec68 --- /dev/null +++ b/src/internal/components/TextInput.test.tsx @@ -0,0 +1,81 @@ +import '@testing-library/jest-dom'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { act } from 'react'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { TextInput } from './TextInput'; + +const DELAY_MS = 100; + +const RenderTest = ({ + className = 'custom-class', + delayMs = DELAY_MS, + onChange = vi.fn(), + placeholder = 'Enter text', + setValue = vi.fn(), + value = 'test', + ...props +}) => ( + +); + +describe('TextInput', () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it('renders with default props', () => { + render(); + expect(screen.getByTestId('ockTextInput_Input')).toBeInTheDocument(); + }); + + it('handles value changes', () => { + const onChange = vi.fn(); + const { getByTestId } = render(); + + const input = getByTestId('ockTextInput_Input'); + act(() => { + fireEvent.change(input, { target: { value: '2' } }); + }); + + vi.advanceTimersByTime(DELAY_MS); + + expect(onChange).toHaveBeenCalledWith('2'); + }); + + it('applies custom className', () => { + render(); + expect(screen.getByTestId('ockTextInput_Input')).toHaveClass( + 'custom-class', + ); + }); + + it('handles placeholder text', () => { + render(); + expect(screen.getByPlaceholderText('Enter text')).toBeInTheDocument(); + }); + + it('handles disabled state', () => { + render(); + expect(screen.getByTestId('ockTextInput_Input')).toBeDisabled(); + }); + + it('handles inputMode', () => { + const { getByTestId } = render(); + expect(getByTestId('ockTextInput_Input')).toHaveAttribute( + 'inputMode', + 'decimal', + ); + }); +}); diff --git a/src/internal/components/TextInput.tsx b/src/internal/components/TextInput.tsx index 198b2ae30e..31f870aa58 100644 --- a/src/internal/components/TextInput.tsx +++ b/src/internal/components/TextInput.tsx @@ -1,5 +1,5 @@ import { useCallback } from 'react'; -import type { ChangeEvent } from 'react'; +import type { ChangeEvent, InputHTMLAttributes } from 'react'; import { useDebounce } from '../../core-react/internal/hooks/useDebounce'; type TextInputReact = { @@ -7,6 +7,8 @@ type TextInputReact = { className: string; delayMs: number; disabled?: boolean; + // specify 'decimal' to trigger numeric keyboards on mobile devices + inputMode?: InputHTMLAttributes['inputMode']; onBlur?: () => void; onChange: (s: string) => void; placeholder: string; @@ -24,6 +26,7 @@ export function TextInput({ onChange, placeholder, setValue, + inputMode, value, inputValidator = () => true, }: TextInputReact) { @@ -53,6 +56,7 @@ export function TextInput({ data-testid="ockTextInput_Input" type="text" className={className} + inputMode={inputMode} placeholder={placeholder} value={value} onBlur={onBlur}