mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
TextField
component updates (#16424)
* Updating showClearButton prop name and making component dumber * Docs update * Adding missing proptype * Fixing casing on tests * Replacing clear button placeholder with ButtonIcon and docs update * Fixing linting issues * Adding note about controlled only for showClearButton to work and fixing some tests * Updating test to include controlled testing setup function for clearButton tests
This commit is contained in:
parent
4b08d2ecf8
commit
9821c59e11
@ -16,58 +16,78 @@ The `TextField` accepts all props below as well as all [Box](/docs/ui-components
|
|||||||
|
|
||||||
<ArgsTable of={TextField} />
|
<ArgsTable of={TextField} />
|
||||||
|
|
||||||
### Show Clear
|
### Show Clear Button
|
||||||
|
|
||||||
Use the `showClear` prop to display a clear button when `TextField` has a value. Clicking the button will clear the value.
|
Use the `showClearButton` prop to display a clear button when `TextField` has a value. Use the `clearButtonOnClick` prop to pass an `onClick` event handler to clear the value of the input.
|
||||||
You can also attach an `onClear` handler to the `TextField` to perform additional actions when the clear button is clicked.
|
|
||||||
|
The clear button uses [ButtonIcon](/docs/ui-components-component-library-button-icon-button-icon-stories-js--default-story) and accepts all props from that component.
|
||||||
|
|
||||||
|
**NOTE: The `showClearButton` only works with a controlled input.**
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Story id="ui-components-component-library-text-field-text-field-stories-js--show-clear" />
|
<Story id="ui-components-component-library-text-field-text-field-stories-js--show-clear-button" />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
import { TextField } from '../../ui/component-library/text-field';
|
import { TextField } from '../../ui/component-library/text-field';
|
||||||
|
|
||||||
<TextField showClear />;
|
const [value, setValue] = useState('show clear');
|
||||||
|
|
||||||
|
const handleOnChange = (e) => {
|
||||||
|
setValue(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnClear = () => {
|
||||||
|
setValue('');
|
||||||
|
};
|
||||||
|
|
||||||
|
<TextField
|
||||||
|
placeholder="Enter text to show clear"
|
||||||
|
value={value}
|
||||||
|
onChange={handleOnChange}
|
||||||
|
showClearButton
|
||||||
|
clearButtonOnClick={handleOnClear}
|
||||||
|
/>;
|
||||||
```
|
```
|
||||||
|
|
||||||
### On Clear
|
### Clear Button Props
|
||||||
|
|
||||||
Use the `onClear` prop to perform additional actions when the clear button is clicked.
|
Use the `clearButtonProps` to access other props of the clear button.
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Story id="ui-components-component-library-text-field-text-field-stories-js--on-clear" />
|
<Story id="ui-components-component-library-text-field-text-field-stories-js--clear-button-props" />
|
||||||
</Canvas>
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
import { TextField } from '../../ui/component-library/text-field';
|
|
||||||
|
|
||||||
<TextField showClear onClear={() => console.log('cleared input')} />;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Clear Button Props and Clear Button Icon Props
|
|
||||||
|
|
||||||
Use the `clearButtonProps` and `clearButtonIconProps` props to pass props to the clear button and clear button icon respectively.
|
|
||||||
|
|
||||||
<Canvas>
|
|
||||||
<Story id="ui-components-component-library-text-field-text-field-stories-js--clear-button-props-clear-button-icon-props" />
|
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
import React, { useState } from 'react';
|
||||||
import {
|
import {
|
||||||
SIZES,
|
SIZES,
|
||||||
COLORS,
|
COLORS,
|
||||||
BORDER_RADIUS,
|
BORDER_RADIUS,
|
||||||
} from '../../../helpers/constants/design-system';
|
} from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
import { TextField } from '../../ui/component-library/text-field';
|
import { TextField } from '../../ui/component-library/text-field';
|
||||||
|
|
||||||
|
const [value, setValue] = useState('show clear');
|
||||||
|
|
||||||
|
const handleOnChange = (e) => {
|
||||||
|
setValue(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnClear = () => {
|
||||||
|
setValue('');
|
||||||
|
};
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
showClear
|
placeholder="Enter text to show clear"
|
||||||
|
value={value}
|
||||||
|
onChange={handleOnChange}
|
||||||
|
showClearButton
|
||||||
|
clearButtonOnClick={handleOnClear}
|
||||||
clearButtonProps={{
|
clearButtonProps={{
|
||||||
backgroundColor: COLORS.BACKGROUND_ALTERNATIVE,
|
backgroundColor: COLORS.BACKGROUND_ALTERNATIVE,
|
||||||
borderRadius: BORDER_RADIUS.XS,
|
borderRadius: BORDER_RADIUS.XS,
|
||||||
'data-testid': 'clear-button',
|
'data-testid': 'clear-button',
|
||||||
}}
|
}}
|
||||||
clearButtonIconProps={{ size: SIZES.MD }}
|
|
||||||
/>;
|
/>;
|
||||||
```
|
```
|
||||||
|
@ -1,86 +1,65 @@
|
|||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
import {
|
import { SIZES } from '../../../helpers/constants/design-system';
|
||||||
SIZES,
|
|
||||||
DISPLAY,
|
|
||||||
JUSTIFY_CONTENT,
|
|
||||||
ALIGN_ITEMS,
|
|
||||||
COLORS,
|
|
||||||
} from '../../../helpers/constants/design-system';
|
|
||||||
|
|
||||||
import Box from '../../ui/box';
|
import Box from '../../ui/box';
|
||||||
|
|
||||||
import { Icon, ICON_NAMES } from '../icon';
|
import { ICON_NAMES } from '../icon';
|
||||||
|
import { ButtonIcon } from '../button-icon';
|
||||||
|
|
||||||
import { TextFieldBase } from '../text-field-base';
|
import { TextFieldBase } from '../text-field-base';
|
||||||
|
|
||||||
export const TextField = ({
|
export const TextField = ({
|
||||||
className,
|
className,
|
||||||
showClear,
|
showClearButton, // only works with a controlled input
|
||||||
clearButtonIconProps,
|
clearButtonOnClick,
|
||||||
clearButtonProps,
|
clearButtonProps,
|
||||||
rightAccessory,
|
rightAccessory,
|
||||||
value: valueProp,
|
|
||||||
onChange,
|
|
||||||
onClear,
|
|
||||||
inputProps,
|
inputProps,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => (
|
||||||
const [value, setValue] = useState(valueProp || '');
|
<TextFieldBase
|
||||||
const handleOnChange = (e) => {
|
className={classnames('mm-text-field', className)}
|
||||||
setValue(e.target.value);
|
value={value}
|
||||||
onChange?.(e);
|
onChange={onChange}
|
||||||
};
|
rightAccessory={
|
||||||
const handleClear = (e) => {
|
value && showClearButton ? (
|
||||||
setValue('');
|
<>
|
||||||
clearButtonProps?.onClick?.(e);
|
<ButtonIcon
|
||||||
onClear?.(e);
|
className="mm-text-field__button-clear"
|
||||||
};
|
ariaLabel="Clear" // TODO: i18n
|
||||||
return (
|
icon={ICON_NAMES.CLOSE_OUTLINE}
|
||||||
<TextFieldBase
|
size={SIZES.SM}
|
||||||
className={classnames('mm-text-field', className)}
|
onClick={clearButtonOnClick}
|
||||||
value={value}
|
{...clearButtonProps}
|
||||||
onChange={handleOnChange}
|
/>
|
||||||
rightAccessory={
|
{rightAccessory}
|
||||||
value && showClear ? (
|
</>
|
||||||
<>
|
) : (
|
||||||
{/* replace with ButtonIcon */}
|
rightAccessory
|
||||||
<Box
|
)
|
||||||
className="mm-text-field__button-clear"
|
}
|
||||||
as="button"
|
inputProps={{
|
||||||
display={DISPLAY.FLEX}
|
marginRight: showClearButton ? 6 : 0,
|
||||||
alignItems={ALIGN_ITEMS.CENTER}
|
...inputProps,
|
||||||
justifyContent={JUSTIFY_CONTENT.CENTER}
|
}}
|
||||||
backgroundColor={COLORS.TRANSPARENT}
|
{...props}
|
||||||
padding={0}
|
/>
|
||||||
{...clearButtonProps} // don't override onClick
|
);
|
||||||
onClick={handleClear}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name={ICON_NAMES.CLOSE_OUTLINE}
|
|
||||||
size={SIZES.SM}
|
|
||||||
aria-label="Clear" // TODO: i18n
|
|
||||||
{...clearButtonIconProps}
|
|
||||||
/>
|
|
||||||
</Box>
|
|
||||||
{rightAccessory}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
rightAccessory
|
|
||||||
)
|
|
||||||
}
|
|
||||||
inputProps={{
|
|
||||||
marginRight: showClear ? 6 : 0,
|
|
||||||
...inputProps,
|
|
||||||
}}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
TextField.propTypes = {
|
TextField.propTypes = {
|
||||||
|
/**
|
||||||
|
* The value af the TextField
|
||||||
|
*/
|
||||||
|
value: TextFieldBase.propTypes.value.isRequired,
|
||||||
|
/**
|
||||||
|
* The onChange handler af the TextField
|
||||||
|
*/
|
||||||
|
onChange: TextFieldBase.propTypes.onChange.isRequired,
|
||||||
/**
|
/**
|
||||||
* An additional className to apply to the text-field
|
* An additional className to apply to the text-field
|
||||||
*/
|
*/
|
||||||
@ -88,19 +67,15 @@ TextField.propTypes = {
|
|||||||
/**
|
/**
|
||||||
* Show a clear button to clear the input
|
* Show a clear button to clear the input
|
||||||
*/
|
*/
|
||||||
showClear: PropTypes.bool,
|
showClearButton: PropTypes.bool,
|
||||||
/**
|
/**
|
||||||
* The event handler for when the clear button is clicked
|
* The onClick handler for the clear button
|
||||||
*/
|
*/
|
||||||
onClear: PropTypes.func,
|
clearButtonOnClick: PropTypes.func,
|
||||||
/**
|
/**
|
||||||
* The props to pass to the clear button
|
* The props to pass to the clear button
|
||||||
*/
|
*/
|
||||||
clearButtonProps: PropTypes.shape(Box.PropTypes),
|
clearButtonProps: PropTypes.shape(Box.PropTypes),
|
||||||
/**
|
|
||||||
* The props to pass to the icon inside of the close button
|
|
||||||
*/
|
|
||||||
clearButtonIconProps: PropTypes.shape(Icon.PropTypes),
|
|
||||||
/**
|
/**
|
||||||
* TextField accepts all the props from TextFieldBase and Box
|
* TextField accepts all the props from TextFieldBase and Box
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
|
import { useArgs } from '@storybook/client-api';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
SIZES,
|
SIZES,
|
||||||
@ -6,8 +7,6 @@ import {
|
|||||||
BORDER_RADIUS,
|
BORDER_RADIUS,
|
||||||
} from '../../../helpers/constants/design-system';
|
} from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
import { Text } from '../text';
|
|
||||||
|
|
||||||
import { TEXT_FIELD_SIZES, TEXT_FIELD_TYPES } from './text-field.constants';
|
import { TEXT_FIELD_SIZES, TEXT_FIELD_TYPES } from './text-field.constants';
|
||||||
import { TextField } from './text-field';
|
import { TextField } from './text-field';
|
||||||
|
|
||||||
@ -41,21 +40,17 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
argTypes: {
|
argTypes: {
|
||||||
showClear: {
|
|
||||||
control: 'boolean',
|
|
||||||
},
|
|
||||||
value: {
|
value: {
|
||||||
control: 'text',
|
control: 'text',
|
||||||
},
|
},
|
||||||
onChange: {
|
onChange: {
|
||||||
action: 'onChange',
|
action: 'onChange',
|
||||||
table: { category: 'text field base props' },
|
|
||||||
},
|
},
|
||||||
onClear: {
|
showClearButton: {
|
||||||
action: 'onClear',
|
control: 'boolean',
|
||||||
},
|
},
|
||||||
clearButtonIconProps: {
|
clearButtonOnClick: {
|
||||||
control: 'object',
|
action: 'clearButtonOnClick',
|
||||||
},
|
},
|
||||||
clearButtonProps: {
|
clearButtonProps: {
|
||||||
control: 'object',
|
control: 'object',
|
||||||
@ -172,7 +167,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
showClear: false,
|
showClearButton: false,
|
||||||
placeholder: 'Placeholder...',
|
placeholder: 'Placeholder...',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
@ -186,62 +181,48 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const Template = (args) => <TextField {...args} />;
|
const Template = (args) => {
|
||||||
|
const [{ value }, updateArgs] = useArgs();
|
||||||
export const DefaultStory = Template.bind({});
|
|
||||||
DefaultStory.storyName = 'Default';
|
|
||||||
|
|
||||||
export const ShowClear = (args) => {
|
|
||||||
const [value, setValue] = useState('show clear');
|
|
||||||
const handleOnChange = (e) => {
|
const handleOnChange = (e) => {
|
||||||
setValue(e.target.value);
|
updateArgs({ value: e.target.value });
|
||||||
|
};
|
||||||
|
const handleOnClear = () => {
|
||||||
|
updateArgs({ value: '' });
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
{...args}
|
{...args}
|
||||||
placeholder="Enter text to show clear"
|
|
||||||
value={value}
|
value={value}
|
||||||
onChange={handleOnChange}
|
onChange={handleOnChange}
|
||||||
showClear
|
clearButtonOnClick={handleOnClear}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const OnClear = (args) => {
|
export const DefaultStory = Template.bind({});
|
||||||
const [value, setValue] = useState('onClear example');
|
DefaultStory.storyName = 'Default';
|
||||||
const [showOnClearMessage, setShowOnClearMessage] = useState(false);
|
|
||||||
const handleOnChange = (e) => {
|
export const ShowClearButton = Template.bind({});
|
||||||
setValue(e.target.value);
|
|
||||||
showOnClearMessage && setShowOnClearMessage(false);
|
ShowClearButton.args = {
|
||||||
};
|
placeholder: 'Enter text to show clear',
|
||||||
const handleOnClear = () => {
|
showClearButton: true,
|
||||||
setShowOnClearMessage(true);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<TextField
|
|
||||||
{...args}
|
|
||||||
placeholder="Clear text to show onClear message"
|
|
||||||
value={value}
|
|
||||||
onChange={handleOnChange}
|
|
||||||
onClear={handleOnClear}
|
|
||||||
showClear
|
|
||||||
/>
|
|
||||||
{showOnClearMessage && <Text marginTop={4}>onClear called</Text>}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ClearButtonPropsClearButtonIconProps = Template.bind({});
|
export const ClearButtonOnClick = Template.bind({});
|
||||||
ClearButtonPropsClearButtonIconProps.args = {
|
|
||||||
|
ShowClearButton.args = {
|
||||||
|
placeholder: 'Enter text to show clear',
|
||||||
|
showClearButton: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ClearButtonProps = Template.bind({});
|
||||||
|
ClearButtonProps.args = {
|
||||||
value: 'clear button props',
|
value: 'clear button props',
|
||||||
size: SIZES.LG,
|
size: SIZES.LG,
|
||||||
showClear: true,
|
showClearButton: true,
|
||||||
clearButtonProps: {
|
clearButtonProps: {
|
||||||
backgroundColor: COLORS.BACKGROUND_ALTERNATIVE,
|
backgroundColor: COLORS.BACKGROUND_ALTERNATIVE,
|
||||||
borderRadius: BORDER_RADIUS.XS,
|
borderRadius: BORDER_RADIUS.XS,
|
||||||
},
|
},
|
||||||
clearButtonIconProps: {
|
|
||||||
size: SIZES.MD,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
@ -1,25 +1,45 @@
|
|||||||
/* eslint-disable jest/require-top-level-describe */
|
/* eslint-disable jest/require-top-level-describe */
|
||||||
import React from 'react';
|
import React, { useState } from 'react';
|
||||||
import { fireEvent, render } from '@testing-library/react';
|
import { fireEvent, render } from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
import { TextField } from './text-field';
|
import { TextField } from './text-field';
|
||||||
|
|
||||||
|
// userEvent setup function as per testing-library docs
|
||||||
|
// https://testing-library.com/docs/user-event/intr
|
||||||
|
function setup(jsx) {
|
||||||
|
return {
|
||||||
|
user: userEvent.setup(),
|
||||||
|
...render(jsx),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom userEvent setup function that renders the component in a controlled environment.
|
||||||
|
// This is used for the showClearButton and related props as the clearButton will only show in a controlled environment.
|
||||||
|
function setupControlled(FormComponent, props) {
|
||||||
|
const ControlledWrapper = () => {
|
||||||
|
const [value, setValue] = useState('');
|
||||||
|
return (
|
||||||
|
<FormComponent
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => setValue(e.target.value)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
return { user: userEvent.setup(), ...render(<ControlledWrapper />) };
|
||||||
|
}
|
||||||
|
|
||||||
describe('TextField', () => {
|
describe('TextField', () => {
|
||||||
it('should render correctly', () => {
|
it('should render correctly', () => {
|
||||||
const { getByRole } = render(<TextField />);
|
const { getByRole } = render(<TextField />);
|
||||||
expect(getByRole('textbox')).toBeDefined();
|
expect(getByRole('textbox')).toBeDefined();
|
||||||
});
|
});
|
||||||
it('should render and be able to input text', () => {
|
it('should render and be able to input text', async () => {
|
||||||
const { getByTestId } = render(
|
const { user, getByRole } = setup(<TextField />);
|
||||||
<TextField inputProps={{ 'data-testid': 'text-field' }} />,
|
const textField = getByRole('textbox');
|
||||||
);
|
await user.type(textField, 'text value');
|
||||||
const textField = getByTestId('text-field');
|
expect(textField).toHaveValue('text value');
|
||||||
|
|
||||||
expect(textField.value).toBe(''); // initial value is empty string
|
|
||||||
fireEvent.change(textField, { target: { value: 'text value' } });
|
|
||||||
expect(textField.value).toBe('text value');
|
|
||||||
fireEvent.change(textField, { target: { value: '' } }); // reset value
|
|
||||||
expect(textField.value).toBe(''); // value is empty string after reset
|
|
||||||
});
|
});
|
||||||
it('should render and fire onFocus and onBlur events', () => {
|
it('should render and fire onFocus and onBlur events', () => {
|
||||||
const onFocus = jest.fn();
|
const onFocus = jest.fn();
|
||||||
@ -38,46 +58,27 @@ describe('TextField', () => {
|
|||||||
fireEvent.blur(textField);
|
fireEvent.blur(textField);
|
||||||
expect(onBlur).toHaveBeenCalledTimes(1);
|
expect(onBlur).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
it('should render and fire onChange event', () => {
|
it('should render and fire onChange event', async () => {
|
||||||
const onChange = jest.fn();
|
const onChange = jest.fn();
|
||||||
const { getByTestId } = render(
|
const { user, getByRole } = setup(
|
||||||
<TextField
|
<TextField
|
||||||
inputProps={{ 'data-testid': 'text-field' }}
|
inputProps={{ 'data-testid': 'text-field' }}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
const textField = getByTestId('text-field');
|
|
||||||
|
|
||||||
fireEvent.change(textField, { target: { value: 'text value' } });
|
|
||||||
expect(onChange).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
it('should render and fire onClick event', () => {
|
|
||||||
const onClick = jest.fn();
|
|
||||||
const { getByTestId } = render(
|
|
||||||
<TextField
|
|
||||||
inputProps={{ 'data-testid': 'text-field' }}
|
|
||||||
onClick={onClick}
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
const textField = getByTestId('text-field');
|
|
||||||
|
|
||||||
fireEvent.click(textField);
|
|
||||||
expect(onClick).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
it('should render showClear button when showClear is true and value exists', () => {
|
|
||||||
const { getByRole, getByTestId } = render(
|
|
||||||
<TextField
|
|
||||||
clearButtonProps={{ 'data-testid': 'clear-button' }}
|
|
||||||
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }}
|
|
||||||
showClear
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
const textField = getByRole('textbox');
|
const textField = getByRole('textbox');
|
||||||
expect(textField.value).toBe(''); // initial value is empty string
|
|
||||||
fireEvent.change(textField, { target: { value: 'text value' } });
|
await user.type(textField, '123');
|
||||||
expect(textField.value).toBe('text value');
|
expect(textField).toHaveValue('123');
|
||||||
expect(getByTestId('clear-button')).toBeDefined();
|
expect(onChange).toHaveBeenCalledTimes(3);
|
||||||
expect(getByTestId('clear-button-icon')).toBeDefined();
|
});
|
||||||
|
it('should render and fire onClick event', async () => {
|
||||||
|
const onClick = jest.fn();
|
||||||
|
const { user, getByTestId } = setup(
|
||||||
|
<TextField data-testid="text-field" onClick={onClick} />,
|
||||||
|
);
|
||||||
|
await user.click(getByTestId('text-field'));
|
||||||
|
expect(onClick).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
it('should render with the rightAccessory', () => {
|
it('should render with the rightAccessory', () => {
|
||||||
const { getByText } = render(
|
const { getByText } = render(
|
||||||
@ -85,77 +86,52 @@ describe('TextField', () => {
|
|||||||
);
|
);
|
||||||
expect(getByText('right-accessory')).toBeDefined();
|
expect(getByText('right-accessory')).toBeDefined();
|
||||||
});
|
});
|
||||||
it('should still render with the rightAccessory when showClear is true', () => {
|
it('should render showClearButton button when showClearButton is true and value exists', async () => {
|
||||||
const { getByRole, getByTestId, getByText } = render(
|
// As showClearButton is intended to be used with a controlled input we need to use setupControlled
|
||||||
<TextField
|
const { user, getByRole } = setupControlled(TextField, {
|
||||||
clearButtonProps={{ 'data-testid': 'clear-button' }}
|
showClearButton: true,
|
||||||
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }}
|
});
|
||||||
rightAccessory={<div>right-accessory</div>}
|
await user.type(getByRole('textbox'), 'test value');
|
||||||
showClear
|
expect(getByRole('textbox')).toHaveValue('test value');
|
||||||
/>,
|
expect(getByRole('button', { name: /Clear/u })).toBeDefined();
|
||||||
);
|
});
|
||||||
const textField = getByRole('textbox');
|
it('should still render with the rightAccessory when showClearButton is true', async () => {
|
||||||
expect(textField.value).toBe(''); // initial value is empty string
|
// As showClearButton is intended to be used with a controlled input we need to use setupControlled
|
||||||
fireEvent.change(textField, { target: { value: 'text value' } });
|
const { user, getByRole, getByText } = setupControlled(TextField, {
|
||||||
expect(textField.value).toBe('text value');
|
showClearButton: true,
|
||||||
expect(getByTestId('clear-button')).toBeDefined();
|
rightAccessory: <div>right-accessory</div>,
|
||||||
expect(getByTestId('clear-button-icon')).toBeDefined();
|
});
|
||||||
|
await user.type(getByRole('textbox'), 'test value');
|
||||||
|
expect(getByRole('textbox')).toHaveValue('test value');
|
||||||
|
expect(getByRole('button', { name: /Clear/u })).toBeDefined();
|
||||||
expect(getByText('right-accessory')).toBeDefined();
|
expect(getByText('right-accessory')).toBeDefined();
|
||||||
});
|
});
|
||||||
it('should clear text when clear button is clicked', () => {
|
it('should fire onClick event when passed to clearButtonOnClick when clear button is clicked', async () => {
|
||||||
const { getByRole, getByTestId } = render(
|
// As showClearButton is intended to be used with a controlled input we need to use setupControlled
|
||||||
<TextField
|
const fn = jest.fn();
|
||||||
clearButtonProps={{ 'data-testid': 'clear-button' }}
|
const { user, getByRole } = setupControlled(TextField, {
|
||||||
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }}
|
showClearButton: true,
|
||||||
rightAccessory={<div>right-accessory</div>}
|
clearButtonOnClick: fn,
|
||||||
showClear
|
});
|
||||||
/>,
|
await user.type(getByRole('textbox'), 'test value');
|
||||||
);
|
await user.click(getByRole('button', { name: /Clear/u }));
|
||||||
const textField = getByRole('textbox');
|
expect(fn).toHaveBeenCalledTimes(1);
|
||||||
fireEvent.change(textField, { target: { value: 'text value' } });
|
|
||||||
expect(textField.value).toBe('text value');
|
|
||||||
fireEvent.click(getByTestId('clear-button'));
|
|
||||||
expect(textField.value).toBe('');
|
|
||||||
});
|
});
|
||||||
it('should fire onClear event when passed to onClear prop', () => {
|
it('should fire onClick event when passed to clearButtonProps.onClick prop', async () => {
|
||||||
const onClear = jest.fn();
|
// As showClearButton is intended to be used with a controlled input we need to use setupControlled
|
||||||
const { getByRole, getByTestId } = render(
|
const fn = jest.fn();
|
||||||
<TextField
|
const { user, getByRole } = setupControlled(TextField, {
|
||||||
onClear={onClear}
|
showClearButton: true,
|
||||||
clearButtonProps={{ 'data-testid': 'clear-button' }}
|
clearButtonProps: { onClick: fn },
|
||||||
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }}
|
});
|
||||||
showClear
|
await user.type(getByRole('textbox'), 'test value');
|
||||||
/>,
|
await user.click(getByRole('button', { name: /Clear/u }));
|
||||||
);
|
expect(fn).toHaveBeenCalledTimes(1);
|
||||||
const textField = getByRole('textbox');
|
|
||||||
fireEvent.change(textField, { target: { value: 'text value' } });
|
|
||||||
expect(textField.value).toBe('text value');
|
|
||||||
fireEvent.click(getByTestId('clear-button'));
|
|
||||||
expect(onClear).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
it('should fire clearButtonProps.onClick event when passed to clearButtonProps.onClick prop', () => {
|
|
||||||
const onClear = jest.fn();
|
|
||||||
const onClick = jest.fn();
|
|
||||||
const { getByRole, getByTestId } = render(
|
|
||||||
<TextField
|
|
||||||
onClear={onClear}
|
|
||||||
clearButtonProps={{ 'data-testid': 'clear-button', onClick }}
|
|
||||||
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }}
|
|
||||||
showClear
|
|
||||||
/>,
|
|
||||||
);
|
|
||||||
const textField = getByRole('textbox');
|
|
||||||
fireEvent.change(textField, { target: { value: 'text value' } });
|
|
||||||
expect(textField.value).toBe('text value');
|
|
||||||
fireEvent.click(getByTestId('clear-button'));
|
|
||||||
expect(onClear).toHaveBeenCalledTimes(1);
|
|
||||||
expect(onClick).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
});
|
||||||
it('should be able to accept inputProps', () => {
|
it('should be able to accept inputProps', () => {
|
||||||
const { getByRole } = render(
|
const { getByTestId } = render(
|
||||||
<TextField inputProps={{ 'data-testid': 'text-field' }} />,
|
<TextField inputProps={{ 'data-testid': 'text-field' }} />,
|
||||||
);
|
);
|
||||||
const textField = getByRole('textbox');
|
expect(getByTestId('text-field')).toBeDefined();
|
||||||
expect(textField).toBeDefined();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user