import { fireEvent, render } from '@testing-library/react-native'; import * as React from 'react'; import { Text } from 'react-native'; import * as UseFormField from '../hooks/useFormField'; import { ERROR_STYLE } from '../internal/error.style'; import * as UseChecks from '../internal/useChecks'; import { TextInput } from './TextInput'; beforeEach(() => { jest.clearAllMocks(); }); describe('TextInput', () => { it('register itself as form field by using the useFormField hook', () => { const useFormField = jest.spyOn(UseFormField, 'useFormField'); render( Test} hasValidation={false} returnKeyType="done" />, ); expect(useFormField.mock.calls[0][0]).toMatchObject({ ref: expect.objectContaining({ current: expect.any(Object) }), errorMessage: undefined, hasError: undefined, hasValidation: false, id: undefined, nextFieldId: undefined, nextFormFieldRef: undefined, }); }); it('renders the given labelComponent before the text input when labelPosition is undefined', () => { const renderAPI = render( labelComponent} returnKeyType="done" hasValidation={false} />, ); expect(renderAPI.toJSON()).toMatchInlineSnapshot(` Array [ labelComponent , , ] `); }); it('renders the given labelComponent after the text input when labelPosition is "afterInput"', () => { const renderAPI = render( labelComponent after} labelPosition="afterInput" returnKeyType="done" hasValidation={false} />, ); expect(renderAPI.toJSON()).toMatchInlineSnapshot(` Array [ , labelComponent after , ] `); }); it('renders the given errorComponent after the labelComponent when errorPosition is "belowLabel"', () => { const renderAPI = render( the labelComponent} returnKeyType="done" hasValidation={true} errorComponent={This is the errorComponent} errorPosition="belowLabel" hasError={true} />, ); expect(renderAPI.toJSON()).toMatchInlineSnapshot(` Array [ the labelComponent , This is the errorComponent , , ] `); }); it('renders the given errorComponent after the input when errorPosition is "afterInput"', () => { const renderAPI = render( the labelComponent} returnKeyType="done" hasValidation={true} errorComponent={This is the errorComponent} errorPosition="afterInput" hasError={true} />, ); expect(renderAPI.toJSON()).toMatchInlineSnapshot(` Array [ the labelComponent , , This is the errorComponent , ] `); }); it('hides the labelComponent from the screen readers', () => { const renderAPI = render( Test} labelPosition="afterInput" returnKeyType="done" hasValidation={false} />, ); expect(renderAPI.getByTestId('text').props.importantForAccessibility).toBe( 'no', ); expect( renderAPI.getByTestId('text').props.accessibilityElementsHidden, ).toBe(true); }); it('hides the errorComponent component from the screen readers', () => { const renderAPI = render( Test} labelPosition="afterInput" returnKeyType="done" hasValidation={true} errorComponent={ This is the errorComponent } errorPosition="afterInput" hasError={true} />, ); expect( renderAPI.getByTestId('errorComponent-test-id').props .importantForAccessibility, ).toBe('no'); expect( renderAPI.getByTestId('errorComponent-test-id').props .accessibilityElementsHidden, ).toBe(true); }); describe('returnKeyType', () => { it('sets the `returnKeyType="next"` if more fields have been registered', async () => { const isLastField = jest.fn().mockReturnValue(false); jest.spyOn(UseFormField, 'useFormField').mockReturnValue({ isLastField, } as any); const renderAPI = render( labelComponent} labelPosition="afterInput" testID="test-id" hasValidation={false} />, ); await fireEvent(renderAPI.getByTestId('test-id'), 'onLayout'); expect(renderAPI.getByTestId('test-id').props.returnKeyType).toEqual( 'next', ); }); it('sets the `returnKeyType="done"` if is last field registered', () => { const isLastField = jest.fn().mockReturnValue(true); jest.spyOn(UseFormField, 'useFormField').mockReturnValue({ isLastField, } as any); const renderAPI = render( labelComponent} labelPosition="afterInput" testID="test-id" hasValidation={false} />, ); fireEvent(renderAPI.getByTestId('test-id'), 'onLayout'); expect(renderAPI.getByTestId('test-id').props.returnKeyType).toEqual( 'done', ); }); it.each([true, false])( 'keeps the `returnKeyType` value passed as prop', async isLastFieldValue => { const isLastField = jest.fn().mockReturnValue(isLastFieldValue); jest.spyOn(UseFormField, 'useFormField').mockReturnValue({ isLastField, } as any); const renderAPI = render( labelComponent} labelPosition="afterInput" testID="test-id" returnKeyType="google" hasValidation={false} />, ); await fireEvent(renderAPI.getByTestId('test-id'), 'onLayout'); expect(renderAPI.getByTestId('test-id').props.returnKeyType).toEqual( 'google', ); }, ); }); describe('accessibilityLabel', () => { describe('Given no accessibility labelComponent is provided', () => { it('Then applies the given labelComponent content as accessibilityLabel', () => { const renderAPI = render( First name:} returnKeyType="done" testID="text-input" hasValidation={false} />, ); expect( renderAPI.getByTestId('text-input').props.accessibilityLabel, ).toBe('First name:'); }); it('strips the ending * from the labelComponent content before using as accessibility labelComponent', () => { const renderAPI = render( First name (required)*} returnKeyType="done" testID="text-input" hasValidation={false} />, ); expect( renderAPI.getByTestId('text-input').props.accessibilityLabel, ).toBe('First name (required)'); }); }); it('uses the accessibilityLabel only if provided', () => { const renderAPI = render( First name (required)*} returnKeyType="done" testID="text-input" accessibilityLabel="Please insert your first name" hasValidation={false} />, ); expect(renderAPI.getByTestId('text-input').props.accessibilityLabel).toBe( 'Please insert your first name', ); }); }); it('calls focusNextFormField onSubmitEditing event', () => { const focusNextFormField = jest.fn(); jest.spyOn(UseFormField, 'useFormField').mockReturnValue({ focusNextFormField, } as any); const fn = jest.fn(); const renderAPI = render( First name (required)*} returnKeyType="next" testID="text-input" accessibilityLabel="Please insert your first name" onSubmitEditing={fn} hasValidation={false} />, ); fireEvent( renderAPI.getByTestId('text-input'), 'onSubmitEditing', 'whatever', ); expect(fn).toHaveBeenCalledWith('whatever'); }); it('ignores the errorComponent message if hasError is not true', () => { const renderAPI = render( First name (required)*} returnKeyType="next" testID="text-input" accessibilityLabel="Please insert your first name" hasValidation={true} hasError={false} errorMessage={'This is the errorComponent'} errorComponent={<>} />, ); expect(renderAPI.getByTestId('text-input').props.accessibilityHint).toBe( '', ); }); it('when hasError uses the text from the errorComponent as part of the accessibilityHint', () => { const renderAPI = render( First name (required)*} returnKeyType="next" testID="text-input" accessibilityLabel="Please insert your first name" accessibilityHint="The hint" hasValidation={true} hasError={true} errorComponent={The first name cannot be blank} />, ); expect(renderAPI.getByTestId('text-input').props.accessibilityHint).toBe( 'The hint, The first name cannot be blank', ); }); it('when hasError uses the errorText, if specified, as part of the accessibilityHint', () => { const renderAPI = render( First name (required)*} returnKeyType="next" testID="text-input" accessibilityLabel="Please insert your first name" accessibilityHint="The hint" hasValidation={true} hasError={true} errorMessage="This text will be used" errorComponent={The first name cannot be blank} />, ); expect(renderAPI.getByTestId('text-input').props.accessibilityHint).toBe( 'The hint, This text will be used', ); }); it('apply the style returned by useFormField', () => { const focusNextFormField = jest.fn(); jest.spyOn(UseFormField, 'useFormField').mockReturnValue({ focusNextFormField, style: ERROR_STYLE, } as any); const renderAPI = render( First name (required)*} returnKeyType="next" testID="text-input" accessibilityLabel="Please insert your first name" hasValidation={false} />, ); expect(renderAPI.getByTestId('text-input').props.style).toEqual( ERROR_STYLE, ); }); describe('When __DEV__ is false', () => { let TextInputWithoutDev: typeof TextInput; let accessibilityLabelChecker: jest.Mock; let uppercaseChecker: jest.Mock; let onLayout: jest.Mock; let noUndefinedProperty: jest.Mock; beforeEach(function () { // @ts-ignore global.__DEV__ = false; accessibilityLabelChecker = jest.fn(); noUndefinedProperty = jest.fn(); uppercaseChecker = jest.fn(); onLayout = jest.fn(); // @ts-ignore jest.spyOn(UseChecks, 'useChecks').mockReturnValue({ noUppercaseStringChecker: accessibilityLabelChecker, noUndefinedProperty, uppercaseChecker, onLayout, } as any); TextInputWithoutDev = require('./TextInput').TextInput; }); it('does not perform any check', () => { render( First name (required)*} returnKeyType="next" testID="text-input" accessibilityLabel="Please insert your first name" hasValidation={false} />, ); expect(noUndefinedProperty).not.toHaveBeenCalled(); }); it('does not apply the debug style', () => { jest.spyOn(UseFormField, 'useFormField').mockReturnValue({ style: ERROR_STYLE, } as any); const { getByTestId } = render( First name (required)*} returnKeyType="next" testID="text-input" accessibilityLabel="Please insert your first name" hasValidation={false} />, ); expect(getByTestId('text-input').props.style).toEqual(undefined); }); }); }); jest.mock('../hooks/useFormField', () => { return { useFormField: jest.fn().mockReturnValue({}), }; }); jest.mock('../providers/AMAProvider', () => { const originalModule = jest.requireActual('../providers/AMAProvider'); return { ...originalModule, useAMAContext: () => { return { isScreenReaderEnabled: true, }; }, }; });