mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 01:47:00 +01:00
Adding TextField
component (#16105)
* Adding TextField component * Fixing lint issues * More linting fixes * Adding more tests * Adding reference to TextFieldBase props * Adding reminder todo comment to styles * Using short hand syntax for conditionally firing event props and removing some css and unused classsNames in favor of box props * Fixing up my sloppy code * Removing text base docs update * More clean up * Adding more stories and docs * Adding new stories to mdx docs
This commit is contained in:
parent
c88efadf1e
commit
da4e6d3e37
@ -1,9 +1,10 @@
|
||||
process.env.METAMASK_ENV = 'test';
|
||||
|
||||
/**
|
||||
* Used for testing components that use the Icon component
|
||||
* Used for testing components that use the Icon component
|
||||
* 'ui/components/component-library/icon/icon.js'
|
||||
*/
|
||||
process.env.ICON_NAMES = {
|
||||
LOADING_FILLED: 'loading-filled',
|
||||
CLOSE_OUTLINE: 'close-outline',
|
||||
};
|
||||
|
@ -12,4 +12,5 @@
|
||||
@import 'icon/icon';
|
||||
@import 'tag/tag';
|
||||
@import 'text/text';
|
||||
@import 'text-field/text-field';
|
||||
@import 'text-field-base/text-field-base';
|
||||
|
73
ui/components/component-library/text-field/README.mdx
Normal file
73
ui/components/component-library/text-field/README.mdx
Normal file
@ -0,0 +1,73 @@
|
||||
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
|
||||
|
||||
import { TextField } from './text-field';
|
||||
|
||||
# TextField
|
||||
|
||||
The `TextField` component lets users enter and edit text as well as adding a show clear button option. It wraps `TextFieldBase` and functions only as a controlled input.
|
||||
|
||||
<Canvas>
|
||||
<Story id="ui-components-component-library-text-field-text-field-stories-js--default-story" />
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
The `TextField` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) and [TextFieldBase](/docs/ui-components-component-library-text-field-base-text-field-base-stories-js--default-story#props) component props
|
||||
|
||||
<ArgsTable of={TextField} />
|
||||
|
||||
### Show Clear
|
||||
|
||||
Use the `showClear` prop to display a clear button when `TextField` has a value. Clicking the button will clear the value.
|
||||
You can also attach an `onClear` handler to the `TextField` to perform additional actions when the clear button is clicked.
|
||||
|
||||
<Canvas>
|
||||
<Story id="ui-components-component-library-text-field-text-field-stories-js--show-clear" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { TextField } from '../../ui/component-library/text-field';
|
||||
|
||||
<TextField showClear />;
|
||||
```
|
||||
|
||||
### On Clear
|
||||
|
||||
Use the `onClear` prop to perform additional actions when the clear button is clicked.
|
||||
|
||||
<Canvas>
|
||||
<Story id="ui-components-component-library-text-field-text-field-stories-js--on-clear" />
|
||||
</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>
|
||||
|
||||
```jsx
|
||||
import {
|
||||
SIZES,
|
||||
COLORS,
|
||||
BORDER_RADIUS,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import { TextField } from '../../ui/component-library/text-field';
|
||||
|
||||
<TextField
|
||||
showClear
|
||||
clearButtonProps={{
|
||||
backgroundColor: COLORS.BACKGROUND_ALTERNATIVE,
|
||||
borderRadius: BORDER_RADIUS.XS,
|
||||
'data-testid': 'clear-button',
|
||||
}}
|
||||
clearButtonIconProps={{ size: SIZES.MD }}
|
||||
/>;
|
||||
```
|
2
ui/components/component-library/text-field/index.js
Normal file
2
ui/components/component-library/text-field/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
export { TextField } from './text-field';
|
||||
export { TEXT_FIELD_SIZES, TEXT_FIELD_TYPES } from './text-field.constants';
|
@ -0,0 +1,7 @@
|
||||
import {
|
||||
TEXT_FIELD_BASE_SIZES,
|
||||
TEXT_FIELD_BASE_TYPES,
|
||||
} from '../text-field-base/text-field-base.constants';
|
||||
|
||||
export const TEXT_FIELD_SIZES = TEXT_FIELD_BASE_SIZES;
|
||||
export const TEXT_FIELD_TYPES = TEXT_FIELD_BASE_TYPES;
|
108
ui/components/component-library/text-field/text-field.js
Normal file
108
ui/components/component-library/text-field/text-field.js
Normal file
@ -0,0 +1,108 @@
|
||||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import {
|
||||
SIZES,
|
||||
DISPLAY,
|
||||
JUSTIFY_CONTENT,
|
||||
ALIGN_ITEMS,
|
||||
COLORS,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
|
||||
import Box from '../../ui/box';
|
||||
|
||||
import { Icon, ICON_NAMES } from '../icon';
|
||||
|
||||
import { TextFieldBase } from '../text-field-base';
|
||||
|
||||
export const TextField = ({
|
||||
className,
|
||||
showClear,
|
||||
clearButtonIconProps,
|
||||
clearButtonProps,
|
||||
rightAccessory,
|
||||
value: valueProp,
|
||||
onChange,
|
||||
onClear,
|
||||
inputProps,
|
||||
...props
|
||||
}) => {
|
||||
const [value, setValue] = useState(valueProp || '');
|
||||
const handleOnChange = (e) => {
|
||||
setValue(e.target.value);
|
||||
onChange?.(e);
|
||||
};
|
||||
const handleClear = (e) => {
|
||||
setValue('');
|
||||
clearButtonProps?.onClick?.(e);
|
||||
onClear?.(e);
|
||||
};
|
||||
return (
|
||||
<TextFieldBase
|
||||
className={classnames('mm-text-field', className)}
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
rightAccessory={
|
||||
value && showClear ? (
|
||||
<>
|
||||
{/* replace with ButtonIcon */}
|
||||
<Box
|
||||
className="mm-text-field__button-clear"
|
||||
as="button"
|
||||
display={DISPLAY.FLEX}
|
||||
alignItems={ALIGN_ITEMS.CENTER}
|
||||
justifyContent={JUSTIFY_CONTENT.CENTER}
|
||||
backgroundColor={COLORS.TRANSPARENT}
|
||||
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 = {
|
||||
/**
|
||||
* An additional className to apply to the text-field
|
||||
*/
|
||||
className: PropTypes.string,
|
||||
/**
|
||||
* Show a clear button to clear the input
|
||||
*/
|
||||
showClear: PropTypes.bool,
|
||||
/**
|
||||
* The event handler for when the clear button is clicked
|
||||
*/
|
||||
onClear: PropTypes.func,
|
||||
/**
|
||||
* The props to pass to the clear button
|
||||
*/
|
||||
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
|
||||
*/
|
||||
...TextFieldBase.propTypes,
|
||||
};
|
10
ui/components/component-library/text-field/text-field.scss
Normal file
10
ui/components/component-library/text-field/text-field.scss
Normal file
@ -0,0 +1,10 @@
|
||||
.mm-text-field {
|
||||
// TOD: remove most of these styles when replaced by ButtonIcon
|
||||
&__button-clear {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
max-width: 24px;
|
||||
flex: 0 0 24px;
|
||||
margin-left: -24px;
|
||||
}
|
||||
}
|
247
ui/components/component-library/text-field/text-field.stories.js
Normal file
247
ui/components/component-library/text-field/text-field.stories.js
Normal file
@ -0,0 +1,247 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import {
|
||||
SIZES,
|
||||
COLORS,
|
||||
BORDER_RADIUS,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
|
||||
import { Text } from '../text';
|
||||
|
||||
import { TEXT_FIELD_SIZES, TEXT_FIELD_TYPES } from './text-field.constants';
|
||||
import { TextField } from './text-field';
|
||||
|
||||
import README from './README.mdx';
|
||||
|
||||
const marginSizeControlOptions = [
|
||||
undefined,
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
10,
|
||||
11,
|
||||
12,
|
||||
'auto',
|
||||
];
|
||||
|
||||
export default {
|
||||
title: 'Components/ComponentLibrary/TextField',
|
||||
id: __filename,
|
||||
component: TextField,
|
||||
parameters: {
|
||||
docs: {
|
||||
page: README,
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
showClear: {
|
||||
control: 'boolean',
|
||||
},
|
||||
value: {
|
||||
control: 'text',
|
||||
},
|
||||
onChange: {
|
||||
action: 'onChange',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
onClear: {
|
||||
action: 'onClear',
|
||||
},
|
||||
clearButtonIconProps: {
|
||||
control: 'object',
|
||||
},
|
||||
clearButtonProps: {
|
||||
control: 'object',
|
||||
},
|
||||
autoComplete: {
|
||||
control: 'boolean',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
autoFocus: {
|
||||
control: 'boolean',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
className: {
|
||||
control: 'text',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
error: {
|
||||
control: 'boolean',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
id: {
|
||||
control: 'text',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
inputProps: {
|
||||
control: 'object',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
leftAccessory: {
|
||||
control: 'text',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
maxLength: {
|
||||
control: 'number',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
name: {
|
||||
control: 'text',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
onBlur: {
|
||||
action: 'onBlur',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
onClick: {
|
||||
action: 'onClick',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
onFocus: {
|
||||
action: 'onFocus',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
onKeyDown: {
|
||||
action: 'onKeyDown',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
onKeyUp: {
|
||||
action: 'onKeyUp',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
placeholder: {
|
||||
control: 'text',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
readOnly: {
|
||||
control: 'boolean',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
required: {
|
||||
control: 'boolean',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
rightAccessory: {
|
||||
control: 'text',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
size: {
|
||||
control: 'select',
|
||||
options: Object.values(TEXT_FIELD_SIZES),
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
type: {
|
||||
control: 'select',
|
||||
options: Object.values(TEXT_FIELD_TYPES),
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
truncate: {
|
||||
control: 'boolean',
|
||||
table: { category: 'text field base props' },
|
||||
},
|
||||
marginTop: {
|
||||
options: marginSizeControlOptions,
|
||||
control: 'select',
|
||||
table: { category: 'box props' },
|
||||
},
|
||||
marginRight: {
|
||||
options: marginSizeControlOptions,
|
||||
control: 'select',
|
||||
table: { category: 'box props' },
|
||||
},
|
||||
marginBottom: {
|
||||
options: marginSizeControlOptions,
|
||||
control: 'select',
|
||||
table: { category: 'box props' },
|
||||
},
|
||||
marginLeft: {
|
||||
options: marginSizeControlOptions,
|
||||
control: 'select',
|
||||
table: { category: 'box props' },
|
||||
},
|
||||
},
|
||||
args: {
|
||||
showClear: false,
|
||||
placeholder: 'Placeholder...',
|
||||
autoFocus: false,
|
||||
disabled: false,
|
||||
error: false,
|
||||
id: '',
|
||||
readOnly: false,
|
||||
required: false,
|
||||
size: SIZES.MD,
|
||||
type: 'text',
|
||||
truncate: false,
|
||||
},
|
||||
};
|
||||
|
||||
const Template = (args) => <TextField {...args} />;
|
||||
|
||||
export const DefaultStory = Template.bind({});
|
||||
DefaultStory.storyName = 'Default';
|
||||
|
||||
export const ShowClear = (args) => {
|
||||
const [value, setValue] = useState('show clear');
|
||||
const handleOnChange = (e) => {
|
||||
setValue(e.target.value);
|
||||
};
|
||||
return (
|
||||
<TextField
|
||||
{...args}
|
||||
placeholder="Enter text to show clear"
|
||||
value={value}
|
||||
onChange={handleOnChange}
|
||||
showClear
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const OnClear = (args) => {
|
||||
const [value, setValue] = useState('onClear example');
|
||||
const [showOnClearMessage, setShowOnClearMessage] = useState(false);
|
||||
const handleOnChange = (e) => {
|
||||
setValue(e.target.value);
|
||||
showOnClearMessage && setShowOnClearMessage(false);
|
||||
};
|
||||
const handleOnClear = () => {
|
||||
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({});
|
||||
ClearButtonPropsClearButtonIconProps.args = {
|
||||
value: 'clear button props',
|
||||
size: SIZES.LG,
|
||||
showClear: true,
|
||||
clearButtonProps: {
|
||||
backgroundColor: COLORS.BACKGROUND_ALTERNATIVE,
|
||||
borderRadius: BORDER_RADIUS.XS,
|
||||
},
|
||||
clearButtonIconProps: {
|
||||
size: SIZES.MD,
|
||||
},
|
||||
};
|
161
ui/components/component-library/text-field/text-field.test.js
Normal file
161
ui/components/component-library/text-field/text-field.test.js
Normal file
@ -0,0 +1,161 @@
|
||||
/* eslint-disable jest/require-top-level-describe */
|
||||
import React from 'react';
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import { TextField } from './text-field';
|
||||
|
||||
describe('TextField', () => {
|
||||
it('should render correctly', () => {
|
||||
const { getByRole } = render(<TextField />);
|
||||
expect(getByRole('textbox')).toBeDefined();
|
||||
});
|
||||
it('should render and be able to input text', () => {
|
||||
const { getByTestId } = render(
|
||||
<TextField inputProps={{ 'data-testid': 'text-field' }} />,
|
||||
);
|
||||
const textField = getByTestId('text-field');
|
||||
|
||||
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', () => {
|
||||
const onFocus = jest.fn();
|
||||
const onBlur = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
<TextField
|
||||
inputProps={{ 'data-testid': 'text-field' }}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
/>,
|
||||
);
|
||||
const textField = getByTestId('text-field');
|
||||
|
||||
fireEvent.focus(textField);
|
||||
expect(onFocus).toHaveBeenCalledTimes(1);
|
||||
fireEvent.blur(textField);
|
||||
expect(onBlur).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
it('should render and fire onChange event', () => {
|
||||
const onChange = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
<TextField
|
||||
inputProps={{ 'data-testid': 'text-field' }}
|
||||
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');
|
||||
expect(textField.value).toBe(''); // initial value is empty string
|
||||
fireEvent.change(textField, { target: { value: 'text value' } });
|
||||
expect(textField.value).toBe('text value');
|
||||
expect(getByTestId('clear-button')).toBeDefined();
|
||||
expect(getByTestId('clear-button-icon')).toBeDefined();
|
||||
});
|
||||
it('should render with the rightAccessory', () => {
|
||||
const { getByText } = render(
|
||||
<TextField rightAccessory={<div>right-accessory</div>} />,
|
||||
);
|
||||
expect(getByText('right-accessory')).toBeDefined();
|
||||
});
|
||||
it('should still render with the rightAccessory when showClear is true', () => {
|
||||
const { getByRole, getByTestId, getByText } = render(
|
||||
<TextField
|
||||
clearButtonProps={{ 'data-testid': 'clear-button' }}
|
||||
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }}
|
||||
rightAccessory={<div>right-accessory</div>}
|
||||
showClear
|
||||
/>,
|
||||
);
|
||||
const textField = getByRole('textbox');
|
||||
expect(textField.value).toBe(''); // initial value is empty string
|
||||
fireEvent.change(textField, { target: { value: 'text value' } });
|
||||
expect(textField.value).toBe('text value');
|
||||
expect(getByTestId('clear-button')).toBeDefined();
|
||||
expect(getByTestId('clear-button-icon')).toBeDefined();
|
||||
expect(getByText('right-accessory')).toBeDefined();
|
||||
});
|
||||
it('should clear text when clear button is clicked', () => {
|
||||
const { getByRole, getByTestId } = render(
|
||||
<TextField
|
||||
clearButtonProps={{ 'data-testid': 'clear-button' }}
|
||||
clearButtonIconProps={{ 'data-testid': 'clear-button-icon' }}
|
||||
rightAccessory={<div>right-accessory</div>}
|
||||
showClear
|
||||
/>,
|
||||
);
|
||||
const textField = getByRole('textbox');
|
||||
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', () => {
|
||||
const onClear = jest.fn();
|
||||
const { getByRole, getByTestId } = render(
|
||||
<TextField
|
||||
onClear={onClear}
|
||||
clearButtonProps={{ 'data-testid': 'clear-button' }}
|
||||
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);
|
||||
});
|
||||
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', () => {
|
||||
const { getByRole } = render(
|
||||
<TextField inputProps={{ 'data-testid': 'text-field' }} />,
|
||||
);
|
||||
const textField = getByRole('textbox');
|
||||
expect(textField).toBeDefined();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user