Skip to content

Commit 2d0df36

Browse files
[CMSDS-3663] Removes usage of legacy Children API from Autocomplete utility (#3817)
* Initial commit * Casts the result of getTextFieldChild as React.ReactElement any * Mute console errors
1 parent b7ec83e commit 2d0df36

File tree

3 files changed

+73
-6
lines changed

3 files changed

+73
-6
lines changed

packages/design-system/src/components/Autocomplete/Autocomplete.test.tsx

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,71 @@ describe('Autocomplete', () => {
346346
expect(child).toHaveClass('additional-class');
347347
});
348348

349+
describe('getTextFieldChild', () => {
350+
it('renders correctly when a single TextField is provided', () => {
351+
renderAutocomplete({
352+
children: <TextField label="Autocomplete field" name="autocomplete_field" />,
353+
});
354+
355+
const input = screen.getByLabelText('Autocomplete field');
356+
expect(input).toBeInTheDocument();
357+
358+
expect(input.tagName).toBe('INPUT');
359+
360+
expect(screen.getByRole('combobox', { name: /autocomplete field/i })).toBeInTheDocument();
361+
});
362+
363+
it('renders only the last TextField when multiple are provided', () => {
364+
renderAutocomplete({
365+
children: [
366+
<TextField key="1" label="First field" name="first_field" />,
367+
<TextField key="2" label="Second field" name="second_field" />,
368+
],
369+
});
370+
371+
expect(screen.queryByLabelText('First field')).not.toBeInTheDocument();
372+
expect(screen.getByLabelText('Second field')).toBeInTheDocument();
373+
});
374+
375+
it('renders correctly when children include one TextField and one non-TextField element', () => {
376+
renderAutocomplete({
377+
children: [
378+
<div key="1" data-testid="non-text-field">
379+
Not a TextField
380+
</div>,
381+
<TextField key="2" label="Valid field" name="valid_field" />,
382+
],
383+
});
384+
385+
const input = screen.getByLabelText('Valid field');
386+
expect(input).toBeInTheDocument();
387+
388+
expect(screen.queryByTestId('non-text-field')).not.toBeInTheDocument();
389+
});
390+
391+
describe('error cases', () => {
392+
beforeEach(() => {
393+
jest.spyOn(console, 'error').mockImplementation(() => {});
394+
});
395+
396+
afterEach(() => {
397+
(console.error as jest.Mock).mockRestore();
398+
});
399+
400+
it('throws an error when no TextField child is provided', () => {
401+
expect(() =>
402+
renderAutocomplete({
403+
children: <div>Not a text field</div>,
404+
})
405+
).toThrow();
406+
});
407+
408+
it('throws an error when children are missing entirely', () => {
409+
expect(() => renderAutocomplete({ children: undefined })).toThrow();
410+
});
411+
});
412+
});
413+
349414
describe('default props', () => {
350415
describe('ariaClearLabel deprecation', () => {
351416
const originalEnv = process.env.NODE_ENV;

packages/design-system/src/components/Autocomplete/Autocomplete.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ export const Autocomplete = (props: AutocompleteProps) => {
228228
statusMessage = renderStatusMessage(noResultsMessage ?? t('autocomplete.noResultsMessage'));
229229
}
230230

231-
const textField = getTextFieldChild(children);
231+
const textField = getTextFieldChild(children) as React.ReactElement<any>;
232232
const size = textField.props.size;
233233
const labelId = textField.props.labelId ?? `${id}__label`;
234234

packages/design-system/src/components/Autocomplete/utils.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isValidElement, Children, ReactElement, ReactNode } from 'react';
1+
import { isValidElement, ReactElement, ReactNode } from 'react';
22
import {
33
AutocompleteProps,
44
AutocompleteItem,
@@ -58,13 +58,15 @@ function isTextField(child?: ReactNode): child is ReactElement {
5858
return child.type === TextField || componentName === 'TextField';
5959
}
6060

61-
export function getTextFieldChild(children: ReactNode): ReactElement<any> | undefined {
62-
let textField: ReactElement<any> | undefined;
63-
Children.forEach(children, (child) => {
61+
export function getTextFieldChild(children: ReactNode): ReactElement | undefined {
62+
const all = Array.isArray(children) ? children : [children];
63+
64+
let textField;
65+
for (const child of all) {
6466
if (isTextField(child)) {
6567
textField = child;
6668
}
67-
});
69+
}
6870
return textField;
6971
}
7072

0 commit comments

Comments
 (0)