Skip to content

Commit

Permalink
Add unit tests for web compat View, Text, TextInput
Browse files Browse the repository at this point in the history
* Test the props compat with web.
* Test the styles compat with web.
* Avoid empty objects for accessibilityState/Value.
  • Loading branch information
necolas committed Nov 11, 2022
1 parent 12b028a commit d47e1ba
Show file tree
Hide file tree
Showing 9 changed files with 843 additions and 132 deletions.
45 changes: 33 additions & 12 deletions Libraries/Components/TextInput/TextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type {TextInputType} from './TextInput.flow';

import usePressability from '../../Pressability/usePressability';
import flattenStyle from '../../StyleSheet/flattenStyle';
import processLayoutProps from '../../StyleSheet/processStyles';
import processStyles from '../../StyleSheet/processStyles';
import StyleSheet, {
type ColorValue,
type TextStyleProp,
Expand Down Expand Up @@ -1073,6 +1073,15 @@ const emptyFunctionThatReturnsTrue = () => true;
*
*/
function InternalTextInput(props: Props): React.Node {
const {
'aria-busy': ariaBusy,
'aria-checked': ariaChecked,
'aria-disabled': ariaDisabled,
'aria-expanded': ariaExpanded,
'aria-selected': ariaSelected,
accessibilityState,
} = props;

const inputRef = useRef<null | React.ElementRef<HostComponent<mixed>>>(null);

// Android sends a "onTextChanged" event followed by a "onSelectionChanged" event, for
Expand Down Expand Up @@ -1393,13 +1402,23 @@ function InternalTextInput(props: Props): React.Node {
// so omitting onBlur and onFocus pressability handlers here.
const {onBlur, onFocus, ...eventHandlers} = usePressability(config) || {};

const _accessibilityState = {
busy: props['aria-busy'] ?? props.accessibilityState?.busy,
checked: props['aria-checked'] ?? props.accessibilityState?.checked,
disabled: props['aria-disabled'] ?? props.accessibilityState?.disabled,
expanded: props['aria-expanded'] ?? props.accessibilityState?.expanded,
selected: props['aria-selected'] ?? props.accessibilityState?.selected,
};
let _accessibilityState;
if (
accessibilityState != null ||
ariaBusy != null ||
ariaChecked != null ||
ariaDisabled != null ||
ariaExpanded != null ||
ariaSelected != null
) {
_accessibilityState = {
busy: ariaBusy ?? accessibilityState?.busy,
checked: ariaChecked ?? accessibilityState?.checked,
disabled: ariaDisabled ?? accessibilityState?.disabled,
expanded: ariaExpanded ?? accessibilityState?.expanded,
selected: ariaSelected ?? accessibilityState?.selected,
};
}

if (Platform.OS === 'ios') {
const RCTTextInputView =
Expand All @@ -1413,7 +1432,7 @@ function InternalTextInput(props: Props): React.Node {
: props.style;

style = flattenStyle(style);
style = processLayoutProps(style);
style = processStyles(style);

const useOnChangeSync =
(props.unstable_onChangeSync || props.unstable_onChangeTextSync) &&
Expand All @@ -1424,8 +1443,8 @@ function InternalTextInput(props: Props): React.Node {
ref={_setNativeRef}
{...props}
{...eventHandlers}
accessible={accessible}
accessibilityState={_accessibilityState}
accessible={accessible}
submitBehavior={submitBehavior}
caretHidden={caretHidden}
dataDetectorTypes={props.dataDetectorTypes}
Expand All @@ -1447,7 +1466,7 @@ function InternalTextInput(props: Props): React.Node {
);
} else if (Platform.OS === 'android') {
let style = flattenStyle(props.style);
style = processLayoutProps(style);
style = processStyles(style);

const autoCapitalize = props.autoCapitalize || 'sentences';
const _accessibilityLabelledBy =
Expand Down Expand Up @@ -1476,9 +1495,9 @@ function InternalTextInput(props: Props): React.Node {
ref={_setNativeRef}
{...props}
{...eventHandlers}
accessible={accessible}
accessibilityState={_accessibilityState}
accessibilityLabelledBy={_accessibilityLabelledBy}
accessible={accessible}
autoCapitalize={autoCapitalize}
submitBehavior={submitBehavior}
caretHidden={caretHidden}
Expand Down Expand Up @@ -1656,6 +1675,8 @@ const ExportedForwardRef: React.AbstractComponent<
);
});

ExportedForwardRef.displayName = 'TextInput';

/**
* Switch to `deprecated-react-native-prop-types` for compatibility with future
* releases. This is deprecated and will be removed in the future.
Expand Down
275 changes: 275 additions & 0 deletions Libraries/Components/TextInput/__tests__/TextInput-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,278 @@ describe('TextInput tests', () => {
);
});
});

describe('TextInput', () => {
it('default render', () => {
const instance = ReactTestRenderer.create(<TextInput />);

expect(instance.toJSON()).toMatchInlineSnapshot(`
<RCTSinglelineTextInputView
accessible={true}
allowFontScaling={true}
focusable={true}
forwardedRef={null}
mostRecentEventCount={0}
onBlur={[Function]}
onChange={[Function]}
onChangeSync={null}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onScroll={[Function]}
onSelectionChange={[Function]}
onSelectionChangeShouldSetResponder={[Function]}
onStartShouldSetResponder={[Function]}
rejectResponderTermination={true}
selection={null}
style={Object {}}
submitBehavior="blurAndSubmit"
text=""
underlineColorAndroid="transparent"
/>
`);
});

it('has displayName', () => {
expect(TextInput.displayName).toEqual('TextInput');
});
});

describe('TextInput compat with web', () => {
it('renders core props', () => {
const props = {
id: 'id',
tabIndex: 0,
testID: 'testID',
};

const instance = ReactTestRenderer.create(<TextInput {...props} />);

expect(instance.toJSON()).toMatchInlineSnapshot(`
<RCTSinglelineTextInputView
accessible={true}
allowFontScaling={true}
focusable={true}
forwardedRef={null}
id="id"
mostRecentEventCount={0}
onBlur={[Function]}
onChange={[Function]}
onChangeSync={null}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onScroll={[Function]}
onSelectionChange={[Function]}
onSelectionChangeShouldSetResponder={[Function]}
onStartShouldSetResponder={[Function]}
rejectResponderTermination={true}
selection={null}
style={Object {}}
submitBehavior="blurAndSubmit"
tabIndex={0}
testID="testID"
text=""
underlineColorAndroid="transparent"
/>
`);
});

it('renders "aria-*" props', () => {
const props = {
'aria-activedescendant': 'activedescendant',
'aria-atomic': true,
'aria-autocomplete': 'list',
'aria-busy': true,
'aria-checked': true,
'aria-columncount': 5,
'aria-columnindex': 3,
'aria-columnspan': 2,
'aria-controls': 'controls',
'aria-current': 'current',
'aria-describedby': 'describedby',
'aria-details': 'details',
'aria-disabled': true,
'aria-errormessage': 'errormessage',
'aria-expanded': true,
'aria-flowto': 'flowto',
'aria-haspopup': true,
'aria-hidden': true,
'aria-invalid': true,
'aria-keyshortcuts': 'Cmd+S',
'aria-label': 'label',
'aria-labelledby': 'labelledby',
'aria-level': 3,
'aria-live': 'polite',
'aria-modal': true,
'aria-multiline': true,
'aria-multiselectable': true,
'aria-orientation': 'portrait',
'aria-owns': 'owns',
'aria-placeholder': 'placeholder',
'aria-posinset': 5,
'aria-pressed': true,
'aria-readonly': true,
'aria-required': true,
role: 'main',
'aria-roledescription': 'roledescription',
'aria-rowcount': 5,
'aria-rowindex': 3,
'aria-rowspan': 3,
'aria-selected': true,
'aria-setsize': 5,
'aria-sort': 'ascending',
'aria-valuemax': 5,
'aria-valuemin': 0,
'aria-valuenow': 3,
'aria-valuetext': '3',
};

const instance = ReactTestRenderer.create(<TextInput {...props} />);

expect(instance.toJSON()).toMatchInlineSnapshot(`
<RCTSinglelineTextInputView
accessibilityState={
Object {
"busy": true,
"checked": true,
"disabled": true,
"expanded": true,
"selected": true,
}
}
accessible={true}
allowFontScaling={true}
aria-activedescendant="activedescendant"
aria-atomic={true}
aria-autocomplete="list"
aria-busy={true}
aria-checked={true}
aria-columncount={5}
aria-columnindex={3}
aria-columnspan={2}
aria-controls="controls"
aria-current="current"
aria-describedby="describedby"
aria-details="details"
aria-disabled={true}
aria-errormessage="errormessage"
aria-expanded={true}
aria-flowto="flowto"
aria-haspopup={true}
aria-hidden={true}
aria-invalid={true}
aria-keyshortcuts="Cmd+S"
aria-label="label"
aria-labelledby="labelledby"
aria-level={3}
aria-live="polite"
aria-modal={true}
aria-multiline={true}
aria-multiselectable={true}
aria-orientation="portrait"
aria-owns="owns"
aria-placeholder="placeholder"
aria-posinset={5}
aria-pressed={true}
aria-readonly={true}
aria-required={true}
aria-roledescription="roledescription"
aria-rowcount={5}
aria-rowindex={3}
aria-rowspan={3}
aria-selected={true}
aria-setsize={5}
aria-sort="ascending"
aria-valuemax={5}
aria-valuemin={0}
aria-valuenow={3}
aria-valuetext="3"
focusable={true}
forwardedRef={null}
mostRecentEventCount={0}
onBlur={[Function]}
onChange={[Function]}
onChangeSync={null}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onScroll={[Function]}
onSelectionChange={[Function]}
onSelectionChangeShouldSetResponder={[Function]}
onStartShouldSetResponder={[Function]}
rejectResponderTermination={true}
role="main"
selection={null}
style={Object {}}
submitBehavior="blurAndSubmit"
text=""
underlineColorAndroid="transparent"
/>
`);
});

it('renders styles', () => {
const style = {
display: 'flex',
flex: 1,
backgroundColor: 'white',
marginInlineStart: 10,
userSelect: 'none',
verticalAlign: 'middle',
};

const instance = ReactTestRenderer.create(<TextInput style={style} />);

expect(instance.toJSON()).toMatchInlineSnapshot(`
<RCTSinglelineTextInputView
accessible={true}
allowFontScaling={true}
focusable={true}
forwardedRef={null}
mostRecentEventCount={0}
onBlur={[Function]}
onChange={[Function]}
onChangeSync={null}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onScroll={[Function]}
onSelectionChange={[Function]}
onSelectionChangeShouldSetResponder={[Function]}
onStartShouldSetResponder={[Function]}
rejectResponderTermination={true}
selection={null}
style={
Object {
"backgroundColor": "white",
"display": "flex",
"flex": 1,
"marginStart": 10,
"textAlignVertical": "center",
"userSelect": "none",
}
}
submitBehavior="blurAndSubmit"
text=""
underlineColorAndroid="transparent"
/>
`);
});
});

0 comments on commit d47e1ba

Please sign in to comment.