UNPKG

input-otp-native

Version:

One time passcode Input For React Native/Expo. Unstyled and fully customizable.

289 lines (281 loc) 7.99 kB
"use strict"; import { act, renderHook } from '@testing-library/react-native'; import { useInput } from "./use-input.js"; describe('useInput', () => { const defaultProps = { maxLength: 4, onChange: jest.fn() }; beforeEach(() => { jest.clearAllMocks(); }); describe('Initialization', () => { test('initializes with default values', () => { const { result } = renderHook(() => useInput({ maxLength: 4 })); expect(result.current.value).toBe(''); expect(result.current.isFocused).toBe(false); expect(result.current.contextValue.slots).toHaveLength(4); }); test('initializes with default value', () => { const { result } = renderHook(() => useInput({ maxLength: 4, defaultValue: '123' })); expect(result.current.value).toBe('123'); expect(result.current.contextValue.slots).toHaveLength(4); }); }); describe('Value Changes', () => { test('updates value on valid input', () => { const onChange = jest.fn(); const { result } = renderHook(() => useInput({ maxLength: 4, onChange })); act(() => { result.current.handlers.onChangeText('123'); }); expect(result.current.value).toBe('123'); expect(onChange).toHaveBeenCalledWith('123'); }); test('limits input to maxLength', () => { const onChange = jest.fn(); const { result } = renderHook(() => useInput({ maxLength: 4, onChange })); act(() => { result.current.handlers.onChangeText('12345'); }); expect(result.current.value).toBe('1234'); expect(onChange).toHaveBeenCalledWith('1234'); }); test('validates input against pattern (string)', () => { const onChange = jest.fn(); const { result } = renderHook(() => useInput({ maxLength: 4, pattern: '[0-9]', onChange })); act(() => { result.current.handlers.onChangeText('abc'); }); expect(result.current.value).toBe(''); expect(onChange).not.toHaveBeenCalled(); }); test('validates input against pattern (RegExp string)', () => { const onChange = jest.fn(); const { result } = renderHook(() => useInput({ maxLength: 4, pattern: '^[0-9]+$', onChange })); act(() => { result.current.handlers.onChangeText('123'); }); expect(result.current.value).toBe('123'); expect(onChange).toHaveBeenCalledWith('123'); }); test('calls onComplete when maxLength is reached', () => { const onComplete = jest.fn(); const { result } = renderHook(() => useInput({ maxLength: 4, onComplete })); act(() => { result.current.handlers.onChangeText('1234'); }); expect(onComplete).toHaveBeenCalledWith('1234'); }); test('applies pasteTransformer on paste operations', () => { const onChange = jest.fn(); const pasteTransformer = jest.fn(text => text.replace(/\D/g, '')); const { result } = renderHook(() => useInput({ maxLength: 4, onChange, pasteTransformer })); // Simulate pasting "Code: 1234" act(() => { result.current.handlers.onChangeText('Code: 1234'); }); expect(pasteTransformer).toHaveBeenCalledWith('Code: 1234'); expect(result.current.value).toBe('1234'); expect(onChange).toHaveBeenCalledWith('1234'); }); test('does not apply pasteTransformer on normal typing', () => { const onChange = jest.fn(); const pasteTransformer = jest.fn(text => text.replace(/\D/g, '')); const { result } = renderHook(() => useInput({ maxLength: 4, onChange, pasteTransformer })); // Simulate typing "1" act(() => { result.current.handlers.onChangeText('1'); }); expect(pasteTransformer).not.toHaveBeenCalled(); expect(result.current.value).toBe('1'); expect(onChange).toHaveBeenCalledWith('1'); }); }); describe('Focus Management', () => { test('handles focus state', () => { const { result } = renderHook(() => useInput({ maxLength: 4 })); act(() => { result.current.handlers.onFocus(); }); expect(result.current.isFocused).toBe(true); act(() => { result.current.handlers.onBlur(); }); expect(result.current.isFocused).toBe(false); }); }); describe('Actions', () => { test('clear action resets value', () => { const { result } = renderHook(() => useInput({ maxLength: 4, defaultValue: '123' })); act(() => { result.current.actions.clear(); }); expect(result.current.value).toBe(''); }); }); describe('Slots', () => { test('generates correct slots with placeholder', () => { const { result } = renderHook(() => useInput({ maxLength: 4, placeholder: '0000' })); const firstSlot = result.current.contextValue.slots[0]; expect(firstSlot?.placeholderChar).toBe('0'); expect(firstSlot?.char).toBe(null); }); test('generates correct slots with value', () => { const { result } = renderHook(() => useInput({ maxLength: 4, defaultValue: '12' })); const slots = result.current.contextValue.slots; expect(slots[0]?.char).toBe('1'); expect(slots[1]?.char).toBe('2'); expect(slots[2]?.char).toBe(null); }); test('marks active slot correctly', () => { const { result } = renderHook(() => useInput({ maxLength: 4, defaultValue: '12' })); act(() => { result.current.handlers.onFocus(); }); const activeSlot = result.current.contextValue.slots[2]; expect(activeSlot?.isActive).toBe(true); expect(activeSlot?.hasFakeCaret).toBe(true); }); }); describe('pattern validation', () => { test('handles undefined pattern', () => { const { result } = renderHook(() => useInput({ ...defaultProps, pattern: undefined })); act(() => { result.current.handlers.onChangeText('123'); }); expect(result.current.value).toBe('123'); }); test('handles string pattern', () => { const { result } = renderHook(() => useInput({ ...defaultProps, pattern: '^[0-9]+$' })); // Test valid input act(() => { result.current.handlers.onChangeText('123'); }); expect(result.current.value).toBe('123'); // Test invalid input act(() => { result.current.handlers.onChangeText('abc'); }); expect(result.current.value).toBe('123'); // Value should not change }); test('handles RegExp pattern', () => { const { result } = renderHook(() => useInput({ ...defaultProps, pattern: /^[0-9]+$/ })); // Test valid input act(() => { result.current.handlers.onChangeText('123'); }); expect(result.current.value).toBe('123'); // Test invalid input act(() => { result.current.handlers.onChangeText('abc'); }); expect(result.current.value).toBe('123'); // Value should not change }); }); test('focus action focuses the input', () => { const mockFocus = jest.fn(); const { result } = renderHook(() => useInput({ ...defaultProps })); // Mock the inputRef.current result.current.inputRef.current = { focus: mockFocus, clear: jest.fn() }; act(() => { result.current.actions.focus(); }); expect(mockFocus).toHaveBeenCalled(); }); }); //# sourceMappingURL=use-input.test.js.map