Skip to content

Commit f7c6a19

Browse files
rubennortemeta-codesync[bot]
authored andcommitted
Port TextInput-test.js to Fantom and remove the legacy Jest test
Summary: Migrates the remaining meaningful coverage from `TextInput-test.js` (Jest with snapshots) over to `TextInput-itest.js` (Fantom) so we can rely on a single test file that exercises the real renderer instead of a heavily-mocked one. Changes in `TextInput-itest.js`: - Add a `focus()` test verifying that focusing a `TextInput` unfocuses any previously focused one (mirrors Jest's "should unfocus when other TextInput is focused"). - Add a top-level `has the correct displayName` test. - Add a new set of `props` describes that assert the props from the original Jest snapshot tests reach the mounting layer via `getRenderedOutput({props: [...]}).toJSX()`: - `id and nativeID`: `id` → `nativeID` mapping, `nativeID` pass-through, and `id` precedence over `nativeID`. - `testID`: pass-through. - `aria-label and accessibilityLabel`: `aria-label` → `accessibilityLabel` mapping and `accessibilityLabel` pass-through. - `aria-* and accessibilityState`: `aria-busy/checked/disabled/expanded/selected` mapped into `accessibilityState`. - `accessibilityRole`: pass-through. - `style`: `backgroundColor` propagated as a native color value. Tests intentionally NOT ported: - Inherited `HostInstance` method presence checks (`focus`, `blur`, `setNativeProps`, `measure`, `measureInWindow`, `measureLayout`): they are guaranteed by Flow typing on `ReactNativeElement`, exercised in `ReactNativeElement-itest.js`, and Flow's `method-unbinding` rule prevents the simple `toBeInstanceOf(Function)` check without `$FlowFixMe` (which is forbidden by project rules). - `focus() should not do anything if the TextInput is not editable`: `TextInputState.focusTextInput` reads `textField.currentProps?.editable`, but in the new architecture `currentProps` is not exposed on the public `ReactNativeElement` instance, so the check is effectively bypassed. The Jest test only passed by monkey-patching `currentProps`. Documenting this as expected behavior in Fantom would mask a real bug. - `should give precedence to textContentType when set`: `textContentType` is iOS-only and Fantom defaults to Android (`AndroidTextInput`). Files removed: - `Libraries/Components/TextInput/__tests__/TextInput-test.js` - `Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap` Changelog: [Internal] Differential Revision: D101977225
1 parent f437b2c commit f7c6a19

3 files changed

Lines changed: 173 additions & 673 deletions

File tree

packages/react-native/Libraries/Components/TextInput/__tests__/TextInput-itest.js

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,138 @@ describe('<TextInput>', () => {
148148
expect(blurEvent).toHaveBeenCalledTimes(1);
149149
});
150150
});
151+
152+
describe('id and nativeID', () => {
153+
it(`has 'id' propagated as 'nativeID' to the mounting layer`, () => {
154+
const root = Fantom.createRoot();
155+
156+
Fantom.runTask(() => {
157+
root.render(<TextInput id="alpha" />);
158+
});
159+
160+
expect(root.getRenderedOutput({props: ['nativeID']}).toJSX()).toEqual(
161+
<rn-androidTextInput nativeID="alpha" />,
162+
);
163+
});
164+
165+
it(`has 'nativeID' propagated correctly`, () => {
166+
const root = Fantom.createRoot();
167+
168+
Fantom.runTask(() => {
169+
root.render(<TextInput nativeID="alpha" />);
170+
});
171+
172+
expect(root.getRenderedOutput({props: ['nativeID']}).toJSX()).toEqual(
173+
<rn-androidTextInput nativeID="alpha" />,
174+
);
175+
});
176+
177+
it(`has a precedence of 'id' over 'nativeID'`, () => {
178+
const root = Fantom.createRoot();
179+
180+
Fantom.runTask(() => {
181+
root.render(<TextInput id="alpha" nativeID="gamma" />);
182+
});
183+
184+
expect(root.getRenderedOutput({props: ['nativeID']}).toJSX()).toEqual(
185+
<rn-androidTextInput nativeID="alpha" />,
186+
);
187+
});
188+
});
189+
190+
describe('testID', () => {
191+
it('is propagated to the mounting layer', () => {
192+
const root = Fantom.createRoot();
193+
194+
Fantom.runTask(() => {
195+
root.render(<TextInput testID="my-test-id" />);
196+
});
197+
198+
expect(root.getRenderedOutput({props: ['testID']}).toJSX()).toEqual(
199+
<rn-androidTextInput testID="my-test-id" />,
200+
);
201+
});
202+
});
203+
204+
describe('aria-label and accessibilityLabel', () => {
205+
it(`has 'aria-label' propagated as 'accessibilityLabel'`, () => {
206+
const root = Fantom.createRoot();
207+
208+
Fantom.runTask(() => {
209+
root.render(<TextInput aria-label="label" />);
210+
});
211+
212+
expect(
213+
root.getRenderedOutput({props: ['accessibilityLabel']}).toJSX(),
214+
).toEqual(<rn-androidTextInput accessibilityLabel="label" />);
215+
});
216+
217+
it(`has 'accessibilityLabel' propagated correctly`, () => {
218+
const root = Fantom.createRoot();
219+
220+
Fantom.runTask(() => {
221+
root.render(<TextInput accessibilityLabel="label" />);
222+
});
223+
224+
expect(
225+
root.getRenderedOutput({props: ['accessibilityLabel']}).toJSX(),
226+
).toEqual(<rn-androidTextInput accessibilityLabel="label" />);
227+
});
228+
});
229+
230+
describe('aria-* and accessibilityState', () => {
231+
it(`maps 'aria-*' state props to 'accessibilityState'`, () => {
232+
const root = Fantom.createRoot();
233+
234+
Fantom.runTask(() => {
235+
root.render(
236+
<TextInput
237+
aria-busy={true}
238+
aria-checked={true}
239+
aria-disabled={true}
240+
aria-expanded={true}
241+
aria-selected={true}
242+
/>,
243+
);
244+
});
245+
246+
expect(
247+
root.getRenderedOutput({props: ['accessibilityState']}).toJSX(),
248+
).toEqual(
249+
<rn-androidTextInput accessibilityState="{disabled:true,selected:true,checked:Checked,busy:true,expanded:true}" />,
250+
);
251+
});
252+
});
253+
254+
describe('accessibilityRole', () => {
255+
it('is propagated to the mounting layer', () => {
256+
const root = Fantom.createRoot();
257+
258+
Fantom.runTask(() => {
259+
root.render(<TextInput accessibilityRole="button" />);
260+
});
261+
262+
expect(
263+
root.getRenderedOutput({props: ['accessibilityRole']}).toJSX(),
264+
).toEqual(<rn-androidTextInput accessibilityRole="button" />);
265+
});
266+
});
267+
268+
describe('style', () => {
269+
it('propagates style values to the mounting layer', () => {
270+
const root = Fantom.createRoot();
271+
272+
Fantom.runTask(() => {
273+
root.render(<TextInput style={{backgroundColor: 'white'}} />);
274+
});
275+
276+
expect(
277+
root.getRenderedOutput({props: ['backgroundColor']}).toJSX(),
278+
).toEqual(
279+
<rn-androidTextInput backgroundColor="rgba(255, 255, 255, 1)" />,
280+
);
281+
});
282+
});
151283
});
152284

153285
describe('ref', () => {
@@ -276,6 +408,43 @@ describe('<TextInput>', () => {
276408
'Command {type: "AndroidTextInput", nativeID: "text-input", name: "focus"}',
277409
]);
278410
});
411+
412+
it('unfocuses any previously focused TextInput when a new one is focused', () => {
413+
const root = Fantom.createRoot();
414+
const ref1 = createRef<TextInputInstance>();
415+
const ref2 = createRef<TextInputInstance>();
416+
417+
Fantom.runTask(() => {
418+
root.render(
419+
<>
420+
<TextInput nativeID="text-input-1" ref={ref1} />
421+
<TextInput nativeID="text-input-2" ref={ref2} />
422+
</>,
423+
);
424+
});
425+
426+
const instance1 = nullthrows(ref1.current);
427+
const instance2 = nullthrows(ref2.current);
428+
429+
expect(instance1.isFocused()).toBe(false);
430+
expect(instance2.isFocused()).toBe(false);
431+
432+
Fantom.runTask(() => {
433+
instance1.focus();
434+
});
435+
436+
expect(instance1.isFocused()).toBe(true);
437+
expect(instance2.isFocused()).toBe(false);
438+
expect(TextInput.State.currentlyFocusedInput()).toBe(instance1);
439+
440+
Fantom.runTask(() => {
441+
instance2.focus();
442+
});
443+
444+
expect(instance1.isFocused()).toBe(false);
445+
expect(instance2.isFocused()).toBe(true);
446+
expect(TextInput.State.currentlyFocusedInput()).toBe(instance2);
447+
});
279448
});
280449

281450
describe('blur()', () => {
@@ -459,4 +628,8 @@ describe('<TextInput>', () => {
459628
});
460629
});
461630
});
631+
632+
it('has the correct displayName', () => {
633+
expect(TextInput.displayName).toBe('TextInput');
634+
});
462635
});

0 commit comments

Comments
 (0)