Skip to content

Commit d47e1ba

Browse files
author
Nicolas Gallagher
committed
Add unit tests for web compat View, Text, TextInput
* Test the props compat with web. * Test the styles compat with web. * Avoid empty objects for accessibilityState/Value.
1 parent 12b028a commit d47e1ba

9 files changed

Lines changed: 843 additions & 132 deletions

File tree

Libraries/Components/TextInput/TextInput.js

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import type {TextInputType} from './TextInput.flow';
1919

2020
import usePressability from '../../Pressability/usePressability';
2121
import flattenStyle from '../../StyleSheet/flattenStyle';
22-
import processLayoutProps from '../../StyleSheet/processStyles';
22+
import processStyles from '../../StyleSheet/processStyles';
2323
import StyleSheet, {
2424
type ColorValue,
2525
type TextStyleProp,
@@ -1073,6 +1073,15 @@ const emptyFunctionThatReturnsTrue = () => true;
10731073
*
10741074
*/
10751075
function InternalTextInput(props: Props): React.Node {
1076+
const {
1077+
'aria-busy': ariaBusy,
1078+
'aria-checked': ariaChecked,
1079+
'aria-disabled': ariaDisabled,
1080+
'aria-expanded': ariaExpanded,
1081+
'aria-selected': ariaSelected,
1082+
accessibilityState,
1083+
} = props;
1084+
10761085
const inputRef = useRef<null | React.ElementRef<HostComponent<mixed>>>(null);
10771086

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

1396-
const _accessibilityState = {
1397-
busy: props['aria-busy'] ?? props.accessibilityState?.busy,
1398-
checked: props['aria-checked'] ?? props.accessibilityState?.checked,
1399-
disabled: props['aria-disabled'] ?? props.accessibilityState?.disabled,
1400-
expanded: props['aria-expanded'] ?? props.accessibilityState?.expanded,
1401-
selected: props['aria-selected'] ?? props.accessibilityState?.selected,
1402-
};
1405+
let _accessibilityState;
1406+
if (
1407+
accessibilityState != null ||
1408+
ariaBusy != null ||
1409+
ariaChecked != null ||
1410+
ariaDisabled != null ||
1411+
ariaExpanded != null ||
1412+
ariaSelected != null
1413+
) {
1414+
_accessibilityState = {
1415+
busy: ariaBusy ?? accessibilityState?.busy,
1416+
checked: ariaChecked ?? accessibilityState?.checked,
1417+
disabled: ariaDisabled ?? accessibilityState?.disabled,
1418+
expanded: ariaExpanded ?? accessibilityState?.expanded,
1419+
selected: ariaSelected ?? accessibilityState?.selected,
1420+
};
1421+
}
14031422

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

14151434
style = flattenStyle(style);
1416-
style = processLayoutProps(style);
1435+
style = processStyles(style);
14171436

14181437
const useOnChangeSync =
14191438
(props.unstable_onChangeSync || props.unstable_onChangeTextSync) &&
@@ -1424,8 +1443,8 @@ function InternalTextInput(props: Props): React.Node {
14241443
ref={_setNativeRef}
14251444
{...props}
14261445
{...eventHandlers}
1427-
accessible={accessible}
14281446
accessibilityState={_accessibilityState}
1447+
accessible={accessible}
14291448
submitBehavior={submitBehavior}
14301449
caretHidden={caretHidden}
14311450
dataDetectorTypes={props.dataDetectorTypes}
@@ -1447,7 +1466,7 @@ function InternalTextInput(props: Props): React.Node {
14471466
);
14481467
} else if (Platform.OS === 'android') {
14491468
let style = flattenStyle(props.style);
1450-
style = processLayoutProps(style);
1469+
style = processStyles(style);
14511470

14521471
const autoCapitalize = props.autoCapitalize || 'sentences';
14531472
const _accessibilityLabelledBy =
@@ -1476,9 +1495,9 @@ function InternalTextInput(props: Props): React.Node {
14761495
ref={_setNativeRef}
14771496
{...props}
14781497
{...eventHandlers}
1479-
accessible={accessible}
14801498
accessibilityState={_accessibilityState}
14811499
accessibilityLabelledBy={_accessibilityLabelledBy}
1500+
accessible={accessible}
14821501
autoCapitalize={autoCapitalize}
14831502
submitBehavior={submitBehavior}
14841503
caretHidden={caretHidden}
@@ -1656,6 +1675,8 @@ const ExportedForwardRef: React.AbstractComponent<
16561675
);
16571676
});
16581677

1678+
ExportedForwardRef.displayName = 'TextInput';
1679+
16591680
/**
16601681
* Switch to `deprecated-react-native-prop-types` for compatibility with future
16611682
* releases. This is deprecated and will be removed in the future.

Libraries/Components/TextInput/__tests__/TextInput-test.js

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,278 @@ describe('TextInput tests', () => {
179179
);
180180
});
181181
});
182+
183+
describe('TextInput', () => {
184+
it('default render', () => {
185+
const instance = ReactTestRenderer.create(<TextInput />);
186+
187+
expect(instance.toJSON()).toMatchInlineSnapshot(`
188+
<RCTSinglelineTextInputView
189+
accessible={true}
190+
allowFontScaling={true}
191+
focusable={true}
192+
forwardedRef={null}
193+
mostRecentEventCount={0}
194+
onBlur={[Function]}
195+
onChange={[Function]}
196+
onChangeSync={null}
197+
onClick={[Function]}
198+
onFocus={[Function]}
199+
onResponderGrant={[Function]}
200+
onResponderMove={[Function]}
201+
onResponderRelease={[Function]}
202+
onResponderTerminate={[Function]}
203+
onResponderTerminationRequest={[Function]}
204+
onScroll={[Function]}
205+
onSelectionChange={[Function]}
206+
onSelectionChangeShouldSetResponder={[Function]}
207+
onStartShouldSetResponder={[Function]}
208+
rejectResponderTermination={true}
209+
selection={null}
210+
style={Object {}}
211+
submitBehavior="blurAndSubmit"
212+
text=""
213+
underlineColorAndroid="transparent"
214+
/>
215+
`);
216+
});
217+
218+
it('has displayName', () => {
219+
expect(TextInput.displayName).toEqual('TextInput');
220+
});
221+
});
222+
223+
describe('TextInput compat with web', () => {
224+
it('renders core props', () => {
225+
const props = {
226+
id: 'id',
227+
tabIndex: 0,
228+
testID: 'testID',
229+
};
230+
231+
const instance = ReactTestRenderer.create(<TextInput {...props} />);
232+
233+
expect(instance.toJSON()).toMatchInlineSnapshot(`
234+
<RCTSinglelineTextInputView
235+
accessible={true}
236+
allowFontScaling={true}
237+
focusable={true}
238+
forwardedRef={null}
239+
id="id"
240+
mostRecentEventCount={0}
241+
onBlur={[Function]}
242+
onChange={[Function]}
243+
onChangeSync={null}
244+
onClick={[Function]}
245+
onFocus={[Function]}
246+
onResponderGrant={[Function]}
247+
onResponderMove={[Function]}
248+
onResponderRelease={[Function]}
249+
onResponderTerminate={[Function]}
250+
onResponderTerminationRequest={[Function]}
251+
onScroll={[Function]}
252+
onSelectionChange={[Function]}
253+
onSelectionChangeShouldSetResponder={[Function]}
254+
onStartShouldSetResponder={[Function]}
255+
rejectResponderTermination={true}
256+
selection={null}
257+
style={Object {}}
258+
submitBehavior="blurAndSubmit"
259+
tabIndex={0}
260+
testID="testID"
261+
text=""
262+
underlineColorAndroid="transparent"
263+
/>
264+
`);
265+
});
266+
267+
it('renders "aria-*" props', () => {
268+
const props = {
269+
'aria-activedescendant': 'activedescendant',
270+
'aria-atomic': true,
271+
'aria-autocomplete': 'list',
272+
'aria-busy': true,
273+
'aria-checked': true,
274+
'aria-columncount': 5,
275+
'aria-columnindex': 3,
276+
'aria-columnspan': 2,
277+
'aria-controls': 'controls',
278+
'aria-current': 'current',
279+
'aria-describedby': 'describedby',
280+
'aria-details': 'details',
281+
'aria-disabled': true,
282+
'aria-errormessage': 'errormessage',
283+
'aria-expanded': true,
284+
'aria-flowto': 'flowto',
285+
'aria-haspopup': true,
286+
'aria-hidden': true,
287+
'aria-invalid': true,
288+
'aria-keyshortcuts': 'Cmd+S',
289+
'aria-label': 'label',
290+
'aria-labelledby': 'labelledby',
291+
'aria-level': 3,
292+
'aria-live': 'polite',
293+
'aria-modal': true,
294+
'aria-multiline': true,
295+
'aria-multiselectable': true,
296+
'aria-orientation': 'portrait',
297+
'aria-owns': 'owns',
298+
'aria-placeholder': 'placeholder',
299+
'aria-posinset': 5,
300+
'aria-pressed': true,
301+
'aria-readonly': true,
302+
'aria-required': true,
303+
role: 'main',
304+
'aria-roledescription': 'roledescription',
305+
'aria-rowcount': 5,
306+
'aria-rowindex': 3,
307+
'aria-rowspan': 3,
308+
'aria-selected': true,
309+
'aria-setsize': 5,
310+
'aria-sort': 'ascending',
311+
'aria-valuemax': 5,
312+
'aria-valuemin': 0,
313+
'aria-valuenow': 3,
314+
'aria-valuetext': '3',
315+
};
316+
317+
const instance = ReactTestRenderer.create(<TextInput {...props} />);
318+
319+
expect(instance.toJSON()).toMatchInlineSnapshot(`
320+
<RCTSinglelineTextInputView
321+
accessibilityState={
322+
Object {
323+
"busy": true,
324+
"checked": true,
325+
"disabled": true,
326+
"expanded": true,
327+
"selected": true,
328+
}
329+
}
330+
accessible={true}
331+
allowFontScaling={true}
332+
aria-activedescendant="activedescendant"
333+
aria-atomic={true}
334+
aria-autocomplete="list"
335+
aria-busy={true}
336+
aria-checked={true}
337+
aria-columncount={5}
338+
aria-columnindex={3}
339+
aria-columnspan={2}
340+
aria-controls="controls"
341+
aria-current="current"
342+
aria-describedby="describedby"
343+
aria-details="details"
344+
aria-disabled={true}
345+
aria-errormessage="errormessage"
346+
aria-expanded={true}
347+
aria-flowto="flowto"
348+
aria-haspopup={true}
349+
aria-hidden={true}
350+
aria-invalid={true}
351+
aria-keyshortcuts="Cmd+S"
352+
aria-label="label"
353+
aria-labelledby="labelledby"
354+
aria-level={3}
355+
aria-live="polite"
356+
aria-modal={true}
357+
aria-multiline={true}
358+
aria-multiselectable={true}
359+
aria-orientation="portrait"
360+
aria-owns="owns"
361+
aria-placeholder="placeholder"
362+
aria-posinset={5}
363+
aria-pressed={true}
364+
aria-readonly={true}
365+
aria-required={true}
366+
aria-roledescription="roledescription"
367+
aria-rowcount={5}
368+
aria-rowindex={3}
369+
aria-rowspan={3}
370+
aria-selected={true}
371+
aria-setsize={5}
372+
aria-sort="ascending"
373+
aria-valuemax={5}
374+
aria-valuemin={0}
375+
aria-valuenow={3}
376+
aria-valuetext="3"
377+
focusable={true}
378+
forwardedRef={null}
379+
mostRecentEventCount={0}
380+
onBlur={[Function]}
381+
onChange={[Function]}
382+
onChangeSync={null}
383+
onClick={[Function]}
384+
onFocus={[Function]}
385+
onResponderGrant={[Function]}
386+
onResponderMove={[Function]}
387+
onResponderRelease={[Function]}
388+
onResponderTerminate={[Function]}
389+
onResponderTerminationRequest={[Function]}
390+
onScroll={[Function]}
391+
onSelectionChange={[Function]}
392+
onSelectionChangeShouldSetResponder={[Function]}
393+
onStartShouldSetResponder={[Function]}
394+
rejectResponderTermination={true}
395+
role="main"
396+
selection={null}
397+
style={Object {}}
398+
submitBehavior="blurAndSubmit"
399+
text=""
400+
underlineColorAndroid="transparent"
401+
/>
402+
`);
403+
});
404+
405+
it('renders styles', () => {
406+
const style = {
407+
display: 'flex',
408+
flex: 1,
409+
backgroundColor: 'white',
410+
marginInlineStart: 10,
411+
userSelect: 'none',
412+
verticalAlign: 'middle',
413+
};
414+
415+
const instance = ReactTestRenderer.create(<TextInput style={style} />);
416+
417+
expect(instance.toJSON()).toMatchInlineSnapshot(`
418+
<RCTSinglelineTextInputView
419+
accessible={true}
420+
allowFontScaling={true}
421+
focusable={true}
422+
forwardedRef={null}
423+
mostRecentEventCount={0}
424+
onBlur={[Function]}
425+
onChange={[Function]}
426+
onChangeSync={null}
427+
onClick={[Function]}
428+
onFocus={[Function]}
429+
onResponderGrant={[Function]}
430+
onResponderMove={[Function]}
431+
onResponderRelease={[Function]}
432+
onResponderTerminate={[Function]}
433+
onResponderTerminationRequest={[Function]}
434+
onScroll={[Function]}
435+
onSelectionChange={[Function]}
436+
onSelectionChangeShouldSetResponder={[Function]}
437+
onStartShouldSetResponder={[Function]}
438+
rejectResponderTermination={true}
439+
selection={null}
440+
style={
441+
Object {
442+
"backgroundColor": "white",
443+
"display": "flex",
444+
"flex": 1,
445+
"marginStart": 10,
446+
"textAlignVertical": "center",
447+
"userSelect": "none",
448+
}
449+
}
450+
submitBehavior="blurAndSubmit"
451+
text=""
452+
underlineColorAndroid="transparent"
453+
/>
454+
`);
455+
});
456+
});

0 commit comments

Comments
 (0)