diff --git a/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx b/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx index b2756e7b2d9..f3372a6045d 100644 --- a/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx +++ b/packages/grafana-ui/src/components/Input/AutoSizeInput.test.tsx @@ -1,5 +1,4 @@ import { screen, render, fireEvent, waitFor } from '@testing-library/react'; -import { useEffect, useState } from 'react'; import { measureText } from '../../utils/measureText'; @@ -130,28 +129,58 @@ describe('AutoSizeInput', () => { }); it('should update the input value if the value prop changes', () => { - // Wrapper component to control the `value` prop - const Wrapper = () => { - const [value, setValue] = useState('Initial'); - - // Simulate prop change after render - useEffect(() => { - setTimeout(() => setValue('Updated'), 100); // Update `value` after 100ms - }, []); - - return ; - }; - - render(); + const { rerender } = render(); + // Get a handle on the original input element (to catch if it's unmounted) + // And check the initial value const input: HTMLInputElement = screen.getByTestId('autosize-input'); - - // Check initial value expect(input.value).toBe('Initial'); - // Wait for the value to update - return waitFor(() => { - expect(input.value).toBe('Updated'); - }); + // Rerender and make sure it clears the input + rerender(); + expect(input.value).toBe('Updated'); + }); + + it('should clear the input when the value is changed to an empty string', () => { + const { rerender } = render(); + + // Get a handle on the original input element (to catch if it's unmounted) + // And check the initial value + const input: HTMLInputElement = screen.getByTestId('autosize-input'); + expect(input.value).toBe('Initial'); + + // Rerender and make sure it clears the input + rerender(); + expect(input.value).toBe(''); + }); + + it('should render string values as expected', () => { + render(); + + const input: HTMLInputElement = screen.getByTestId('autosize-input'); + expect(input.value).toBe('foo'); + }); + + it('should render undefined values as expected', () => { + render(); + + const input: HTMLInputElement = screen.getByTestId('autosize-input'); + expect(input.value).toBe(''); + }); + + it('should render null values as expected', () => { + // @ts-expect-error - look - the types forbid this, but we previously fixed an issue if the value is null + // so lets test it just in case https://github.com/grafana/grafana/pull/94078 + render(); + + const input: HTMLInputElement = screen.getByTestId('autosize-input'); + expect(input.value).toBe(''); + }); + + it('should render array values as expected', () => { + render(); + + const input: HTMLInputElement = screen.getByTestId('autosize-input'); + expect(input.value).toBe('hello,world'); }); }); diff --git a/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx b/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx index d1e61001de3..7d8eccee748 100644 --- a/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx +++ b/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useEffect, useMemo } from 'react'; import * as React from 'react'; import { measureText } from '../../utils/measureText'; @@ -26,21 +26,18 @@ export const AutoSizeInput = React.forwardRef((props, r value: controlledValue, ...restProps } = props; - // Initialize internal state const [value, setValue] = React.useState(controlledValue ?? defaultValue); - const [inputWidth, setInputWidth] = React.useState(minWidth); // Update internal state when controlled `value` prop changes useEffect(() => { - if (controlledValue) { - setValue(controlledValue); - } - }, [controlledValue]); + setValue(controlledValue ?? defaultValue); + }, [controlledValue, defaultValue]); // Update input width when `value`, `minWidth`, or `maxWidth` change - useEffect(() => { - setInputWidth(getWidthFor(value.toString(), minWidth, maxWidth)); + const inputWidth = useMemo(() => { + const valueString = typeof value === 'string' ? value : value.toString(); + return getWidthFor(valueString, minWidth, maxWidth); }, [value, minWidth, maxWidth]); return (