@widergy/mobile-ui 1.47.0 → 1.48.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -0
  3. package/lib/components/CaptionLabel/README.md +30 -8
  4. package/lib/components/CaptionLabel/index.js +2 -1
  5. package/lib/components/CaptionLabel/propTypes.js +1 -0
  6. package/lib/components/Checkbox/README.md +93 -25
  7. package/lib/components/Checkbox/index.js +14 -1
  8. package/lib/components/Checkbox/propTypes.js +1 -0
  9. package/lib/components/Label/index.js +2 -1
  10. package/lib/components/Label/propTypes.js +1 -0
  11. package/lib/components/RadioGroup/components/RadioButton/index.js +29 -18
  12. package/lib/components/RadioGroup/index.js +19 -5
  13. package/lib/components/Touchable/index.js +3 -1
  14. package/lib/components/Touchable/propTypes.js +1 -0
  15. package/lib/components/UTBadge/index.js +3 -1
  16. package/lib/components/UTBaseInputField/README.md +41 -19
  17. package/lib/components/UTBaseInputField/components/ActionAdornment/index.js +10 -3
  18. package/lib/components/UTBaseInputField/components/BadgeAdornment/index.js +6 -1
  19. package/lib/components/UTBaseInputField/components/IconAdornment/index.js +8 -1
  20. package/lib/components/UTBaseInputField/components/PrefixAdornment/index.js +8 -2
  21. package/lib/components/UTBaseInputField/components/SuffixAdornment/index.js +6 -1
  22. package/lib/components/UTBaseInputField/components/TooltipAdornment/index.js +16 -3
  23. package/lib/components/UTBaseInputField/index.js +15 -4
  24. package/lib/components/UTBottomSheet/README.md +94 -23
  25. package/lib/components/UTBottomSheet/index.js +27 -4
  26. package/lib/components/UTButton/index.js +18 -4
  27. package/lib/components/UTButton/proptypes.js +1 -0
  28. package/lib/components/UTCheckBox/README.md +47 -0
  29. package/lib/components/UTCheckBox/index.js +24 -3
  30. package/lib/components/UTCheckBox/proptypes.js +1 -0
  31. package/lib/components/UTCheckList/README.MD +63 -0
  32. package/lib/components/UTCheckList/index.js +25 -2
  33. package/lib/components/UTCheckList/proptypes.js +1 -0
  34. package/lib/components/UTDetailDrawer/README.md +60 -10
  35. package/lib/components/UTDetailDrawer/index.js +11 -1
  36. package/lib/components/UTDetailDrawer/propTypes.js +1 -0
  37. package/lib/components/UTFieldLabel/README.md +99 -0
  38. package/lib/components/UTFieldLabel/index.js +19 -2
  39. package/lib/components/UTIcon/README.md +25 -2
  40. package/lib/components/UTIcon/index.js +3 -1
  41. package/lib/components/UTLabel/README.md +26 -0
  42. package/lib/components/UTLabel/constants.js +0 -10
  43. package/lib/components/UTLabel/index.js +2 -0
  44. package/lib/components/UTLabel/proptypes.js +1 -0
  45. package/lib/components/UTLabel/utils.js +4 -22
  46. package/lib/components/UTMenu/README.md +275 -0
  47. package/lib/components/UTMenu/components/ListView/index.js +5 -3
  48. package/lib/components/UTMenu/components/ListView/proptypes.js +2 -1
  49. package/lib/components/UTMenu/components/MenuOption/index.js +5 -3
  50. package/lib/components/UTMenu/index.js +18 -3
  51. package/lib/components/UTMenu/proptypes.js +2 -1
  52. package/lib/components/UTModal/README.md +193 -0
  53. package/lib/components/UTModal/index.js +22 -2
  54. package/lib/components/UTModal/proptypes.js +1 -0
  55. package/lib/components/UTPhoneInput/index.js +25 -2
  56. package/lib/components/UTRoundView/README.md +158 -0
  57. package/lib/components/UTRoundView/index.js +12 -1
  58. package/lib/components/UTRoundView/propTypes.js +4 -2
  59. package/lib/components/UTSearchField/README.md +64 -14
  60. package/lib/components/UTSearchField/index.js +3 -1
  61. package/lib/components/UTSearchField/proptypes.js +2 -1
  62. package/lib/components/UTSelect/versions/V0/README.md +216 -0
  63. package/lib/components/UTSelect/versions/V0/componentes/MultipleItem/index.js +4 -2
  64. package/lib/components/UTSelect/versions/V0/index.js +5 -2
  65. package/lib/components/UTSelect/versions/V0/proptypes.js +2 -1
  66. package/lib/components/UTSelect/versions/V1/README.md +94 -0
  67. package/lib/components/UTSelect/versions/V1/index.js +28 -6
  68. package/lib/components/UTSelect/versions/V1/proptypes.js +1 -0
  69. package/lib/components/UTSelectableCard/README.md +85 -0
  70. package/lib/components/UTSelectableCard/index.js +52 -4
  71. package/lib/components/UTTextInput/versions/V0/components/BaseInput/index.js +5 -1
  72. package/lib/components/UTTextInput/versions/V0/components/InputLabel/index.js +4 -1
  73. package/lib/components/UTTextInput/versions/V0/flavors/FilledInput/index.js +9 -1
  74. package/lib/components/UTTextInput/versions/V0/flavors/OutlinedInput/index.js +9 -1
  75. package/lib/components/UTTextInput/versions/V0/flavors/StandardInput/index.js +9 -1
  76. package/lib/components/UTTextInput/versions/V1/components/TextInputField/index.js +3 -0
  77. package/lib/components/UTTextInput/versions/V1/index.js +20 -3
  78. package/lib/components/UTTooltip/README.md +99 -0
  79. package/lib/components/UTTooltip/index.js +2 -0
  80. package/lib/components/UTTooltip/proptypes.js +2 -1
  81. package/lib/components/UTValidation/index.js +26 -4
  82. package/lib/constants/testIds.js +44 -0
  83. package/package.json +1 -1
@@ -11,6 +11,7 @@
11
11
  | alwaysShowPlaceholder | bool | false | Whether to always show the placeholder text, even when the field is focused. |
12
12
  | autoCapitalize | oneOf('none','sentences','words','characters') | 'sentences' | Defines how to automatically capitalize certain characters. |
13
13
  | blurOnSubmit | bool | | If true, the input will be blurred when the user submits the text. |
14
+ | dataTestId | string | | Test ID for automated testing. Enables hierarchical test ID structure. |
14
15
  | disabled | bool | | Whether the input field is disabled. |
15
16
  | editable | bool | true | Whether the input field is editable. If false, it behaves like a disabled field. |
16
17
  | error | oneOfType([bool, string]) | | Error message to display, or `true` to indicate an error state without a message. |
@@ -33,6 +34,28 @@
33
34
  | type | string | | Type of the input field (e.g., text, email, numeric, password). |
34
35
  | variant | string | 'white' | Variant of the input field. One of: `white`, `gray`. |
35
36
 
37
+ ## Test IDs
38
+
39
+ When `dataTestId` is provided, the component creates a hierarchical test ID structure:
40
+
41
+ | Element | Test ID | Condition |
42
+ | ---------------- | ------------------------------ | --------------------------------- |
43
+ | Input field | `${dataTestId}` | Always when `dataTestId` provided |
44
+ | Left adornments | `${dataTestId}.left` | When left adornments are present |
45
+ | Right adornments | `${dataTestId}.right` | When right adornments are present |
46
+ | Character count | `${dataTestId}.characterCount` | When `showCharacterCount` is true |
47
+
48
+ ### Test ID Structure Details
49
+
50
+ - **Input field**: The main TextInput element gets the base `dataTestId`
51
+ - **Left adornments**: All left-side adornments share the `.left` test ID
52
+ - **Right adornments**: All right-side adornments share the `.right` test ID
53
+ - **Character count**: The character count display when enabled
54
+
55
+ ### Adornment Test IDs
56
+
57
+ Individual adornments within the left/right containers inherit the adornment test ID and may create their own hierarchical structure based on their component type (e.g., UTIcon, UTButton, etc.).
58
+
36
59
  ## Input Types
37
60
 
38
61
  The `type` prop can be one of these values:
@@ -176,31 +199,30 @@ Displays a tooltip with an icon.
176
199
  <UTBaseInputField rightAdornments={[{ name: 'Tooltip', props: { tooltip: 'Tooltip Text' } }]} />
177
200
  ```
178
201
 
179
- ### Example Usages:
202
+ ### Example with Test IDs
180
203
 
181
204
  ```javascript
182
- // Example of PrefixAdornment usage
183
- <UTBaseInputField
184
- leftAdornments={[{ name: 'Prefix', props: { text: 'Prefix Text' } }]}
185
- />
186
-
187
- // Example of SuffixAdornment usage
188
- <UTBaseInputField
189
- rightAdornments={[{ name: 'Suffix', props: { text: 'Suffix Text' } }]}
190
- />
191
-
192
- // Example of IconAdornment usage
205
+ // Basic input with test ID
193
206
  <UTBaseInputField
194
- rightAdornments={[{ name: 'Icon', props: { Icon: 'IconActivity', changeOnError: true } }]}
207
+ dataTestId="userEmail"
208
+ placeholder="Enter your email"
209
+ type="email"
195
210
  />
196
211
 
197
- // Example of ActionAdornment usage
212
+ // Input with adornments and test IDs
198
213
  <UTBaseInputField
199
- rightAdornments={[{ name: 'Action', props: { action: { text: 'Go', onPress: handlePress } } }]}
214
+ dataTestId="searchField"
215
+ placeholder="Search products..."
216
+ leftAdornments={[{ name: 'Icon', props: { Icon: 'IconSearch' } }]}
217
+ rightAdornments={[{ name: 'Action', props: { action: { text: 'Search', onPress: handleSearch } } }]}
218
+ showCharacterCount
219
+ maxLength={100}
200
220
  />
201
221
 
202
- // Example of TooltipAdornment usage
203
- <UTBaseInputField
204
- rightAdornments={[{ name: 'Tooltip', props: { tooltip: 'Tooltip Text' } }]}
205
- />
222
+ // Generated test IDs:
223
+ // userEmail (input field)
224
+ // searchField (input field)
225
+ // searchField.left (left adornments container)
226
+ // searchField.right (right adornments container)
227
+ // searchField.characterCount (character count display)
206
228
  ```
@@ -1,14 +1,20 @@
1
1
  import React from 'react';
2
- import { bool, object, shape } from 'prop-types';
2
+ import { bool, object, shape, string } from 'prop-types';
3
3
 
4
4
  import UTButton from '../../../UTButton';
5
5
  import { propTypes as utbuttonProptypes } from '../../../UTButton/proptypes';
6
6
 
7
- const ActionAdornment = ({ action, disabled, actionStyle }) => {
7
+ const ActionAdornment = ({ action, dataTestId, disabled, actionStyle }) => {
8
8
  if (!action) return null;
9
9
 
10
10
  return (
11
- <UTButton disabled={disabled} style={actionStyle} variant="text" {...action}>
11
+ <UTButton
12
+ dataTestId={dataTestId ? `${dataTestId}.actionAdornment` : undefined}
13
+ disabled={disabled}
14
+ style={actionStyle}
15
+ variant="text"
16
+ {...action}
17
+ >
12
18
  {action.text}
13
19
  </UTButton>
14
20
  );
@@ -21,6 +27,7 @@ ActionAdornment.propTypes = {
21
27
  icon: object,
22
28
  root: object
23
29
  }),
30
+ dataTestId: string,
24
31
  disabled: bool
25
32
  };
26
33
 
@@ -3,10 +3,15 @@ import { number, oneOfType, string } from 'prop-types';
3
3
 
4
4
  import UTBadge from '../../../UTBadge';
5
5
 
6
- const BadgeAdornment = ({ text, colorTheme }) => <UTBadge colorTheme={colorTheme}>{text}</UTBadge>;
6
+ const BadgeAdornment = ({ dataTestId, text, colorTheme }) => (
7
+ <UTBadge dataTestId={dataTestId ? `${dataTestId}.badgeAdornment` : undefined} colorTheme={colorTheme}>
8
+ {text}
9
+ </UTBadge>
10
+ );
7
11
 
8
12
  BadgeAdornment.propTypes = {
9
13
  colorTheme: string,
14
+ dataTestId: string,
10
15
  text: oneOfType([string, number])
11
16
  };
12
17
 
@@ -12,6 +12,7 @@ const IconAdornment = ({
12
12
  changeOnError,
13
13
  changeOnFocus,
14
14
  colorTheme,
15
+ dataTestId,
15
16
  error,
16
17
  focused,
17
18
  Icon,
@@ -23,12 +24,17 @@ const IconAdornment = ({
23
24
 
24
25
  return isUTIcon(IconToRender) ? (
25
26
  <UTIcon
27
+ dataTestId={dataTestId ? `${dataTestId}.iconAdornment` : undefined}
26
28
  name={IconToRender}
27
29
  size={ICON_SIZE}
28
30
  {...getIconColorProps(changeOnError, changeOnFocus, colorTheme, error, focused, shade)}
29
31
  />
30
32
  ) : (
31
- <Icon size={ICON_SIZE} fill={inputStyle.root.color} />
33
+ <Icon
34
+ testID={dataTestId ? `${dataTestId}.iconAdornment` : undefined}
35
+ size={ICON_SIZE}
36
+ fill={inputStyle.root.color}
37
+ />
32
38
  );
33
39
  };
34
40
 
@@ -36,6 +42,7 @@ IconAdornment.propTypes = {
36
42
  changeOnError: bool,
37
43
  changeOnFocus: bool,
38
44
  colorTheme: string,
45
+ dataTestId: string,
39
46
  error: oneOfType([bool, string]),
40
47
  focused: bool,
41
48
  Icon: elementType,
@@ -3,13 +3,19 @@ import { string } from 'prop-types';
3
3
 
4
4
  import UTLabel from '../../../UTLabel';
5
5
 
6
- const PrefixAdornment = ({ text }) => (
7
- <UTLabel colorTheme="gray" variant="small" weight="medium">
6
+ const PrefixAdornment = ({ dataTestId, text }) => (
7
+ <UTLabel
8
+ dataTestId={dataTestId ? `${dataTestId}.prefixAdornment` : undefined}
9
+ colorTheme="gray"
10
+ variant="small"
11
+ weight="medium"
12
+ >
8
13
  {text}
9
14
  </UTLabel>
10
15
  );
11
16
 
12
17
  PrefixAdornment.propTypes = {
18
+ dataTestId: string,
13
19
  text: string
14
20
  };
15
21
 
@@ -3,9 +3,14 @@ import { string } from 'prop-types';
3
3
 
4
4
  import UTLabel from '../../../UTLabel';
5
5
 
6
- const SuffixAdornment = ({ text }) => <UTLabel colorTheme="gray">{text}</UTLabel>;
6
+ const SuffixAdornment = ({ dataTestId, text }) => (
7
+ <UTLabel dataTestId={dataTestId ? `${dataTestId}.suffixAdornment` : undefined} colorTheme="gray">
8
+ {text}
9
+ </UTLabel>
10
+ );
7
11
 
8
12
  SuffixAdornment.propTypes = {
13
+ dataTestId: string,
9
14
  text: string
10
15
  };
11
16
 
@@ -5,19 +5,32 @@ import UTTooltip from '../../../UTTooltip';
5
5
  import UTIcon from '../../../UTIcon';
6
6
  import UTLabel from '../../../UTLabel';
7
7
 
8
- const TooltipAdornment = ({ tooltip, tooltipProps }) => {
8
+ const TooltipAdornment = ({ dataTestId, tooltip, tooltipProps }) => {
9
9
  const { tooltip: tooltipStyles, arrowTouchable, labelProps } = tooltipProps || {};
10
10
  return tooltip ? (
11
11
  <UTTooltip
12
+ dataTestId={dataTestId ? `${dataTestId}.tooltipAdornment` : undefined}
12
13
  styles={{ tooltip: tooltipStyles, arrow: arrowTouchable }}
13
- content={<UTLabel {...labelProps}>{tooltip}</UTLabel>}
14
+ content={
15
+ <UTLabel
16
+ dataTestId={dataTestId ? `${dataTestId}.tooltipAdornment.content` : undefined}
17
+ {...labelProps}
18
+ >
19
+ {tooltip}
20
+ </UTLabel>
21
+ }
14
22
  >
15
- <UTIcon name="IconInfoCircle" colorTheme="gray" />
23
+ <UTIcon
24
+ dataTestId={dataTestId ? `${dataTestId}.tooltipAdornment.icon` : undefined}
25
+ name="IconInfoCircle"
26
+ colorTheme="gray"
27
+ />
16
28
  </UTTooltip>
17
29
  ) : undefined;
18
30
  };
19
31
 
20
32
  TooltipAdornment.propTypes = {
33
+ dataTestId: string,
21
34
  tooltip: string,
22
35
  tooltipProps: shape({
23
36
  tooltip: object,
@@ -14,11 +14,14 @@ import { arrayOf, bool, func, number, object, oneOfType, shape, string } from 'p
14
14
 
15
15
  import { useTheme } from '../../theming';
16
16
  import UTLabel from '../UTLabel';
17
+ import { TEST_ID_CONSTANTS } from '../../constants/testIds';
17
18
 
18
19
  import { COMPONENTS_MAPPER, DEBOUNCE_CONFIG, DEBOUNCE_DELAY } from './constants';
19
20
  import { getPropsByType } from './utils';
20
21
  import { CONTAINER, LINE_HEIGHT, retrieveStyle } from './theme';
21
22
 
23
+ const { characterCount } = TEST_ID_CONSTANTS;
24
+
22
25
  const UTBaseInputField = forwardRef(
23
26
  (
24
27
  {
@@ -26,6 +29,7 @@ const UTBaseInputField = forwardRef(
26
29
  autoCapitalize: autoCapitalize_,
27
30
  blurOnSubmit,
28
31
  disabled,
32
+ dataTestId,
29
33
  editable = true,
30
34
  error,
31
35
  id,
@@ -153,10 +157,11 @@ const UTBaseInputField = forwardRef(
153
157
  }));
154
158
 
155
159
  const renderElement = useCallback(
156
- element => {
160
+ (element, adornmentSide) => {
157
161
  const Component = COMPONENTS_MAPPER[element.name];
158
162
  return Component ? (
159
163
  <Component
164
+ dataTestId={dataTestId ? `${dataTestId}.${adornmentSide}` : undefined}
160
165
  actionStyle={actionStyle}
161
166
  disabled={disabled}
162
167
  error={error}
@@ -179,11 +184,12 @@ const UTBaseInputField = forwardRef(
179
184
  return (
180
185
  <View style={[containerStyle, { minHeight }]}>
181
186
  <View style={inputRowStyle}>
182
- {leftAdornments.map(renderElement)}
187
+ {leftAdornments.map(element => renderElement(element, 'left'))}
183
188
  <TextInput
184
189
  autoCapitalize={autoCapitalize}
185
190
  autoCorrect={false}
186
191
  cursorColor={inputStyle.cursorColor}
192
+ testID={dataTestId}
187
193
  defaultValue={value}
188
194
  editable={!disabled && !readOnly && editable}
189
195
  id={id ? `${id}` : undefined}
@@ -206,11 +212,15 @@ const UTBaseInputField = forwardRef(
206
212
  style={inputStyle.root}
207
213
  type={type}
208
214
  />
209
- {rightAdornments.map(renderElement)}
215
+ {rightAdornments.map(element => renderElement(element, 'right'))}
210
216
  </View>
211
217
  {hasCharactersCount && (
212
218
  <View style={textLengthRowStyle}>
213
- <UTLabel colorTheme="gray" variant="small">
219
+ <UTLabel
220
+ dataTestId={dataTestId ? `${dataTestId}.${characterCount}` : undefined}
221
+ colorTheme="gray"
222
+ variant="small"
223
+ >
214
224
  {value?.length || 0}/{maxLength}
215
225
  </UTLabel>
216
226
  </View>
@@ -226,6 +236,7 @@ UTBaseInputField.propTypes = {
226
236
  alwaysShowPlaceholder: bool,
227
237
  autoCapitalize: string,
228
238
  blurOnSubmit: bool,
239
+ dataTestId: string,
229
240
  disabled: bool,
230
241
  editable: bool,
231
242
  error: oneOfType([bool, string]),
@@ -6,29 +6,30 @@
6
6
 
7
7
  ## Props
8
8
 
9
- | Name | Type | Default | Description |
10
- | ------------------------- | -------- | ----------- | --------------------------------------------------------------------------- |
11
- | `actionAlignment` | `string` | | Aligns the actions. |
12
- | `adjustableHeight` | `bool` | `false` | If true the height of the component adjusts to the content. |
13
- | `buttonText` | `string` | | Text for the button that appears in the top right corner of the header. |
14
- | `description` | `string` | | Description that appears below the title in the header. |
15
- | `onClose` | `func` | | Function called when the bottom sheet is closed. |
16
- | `onCloseProps` | `object` | | Additional props passed to the `onClose` function (optional). |
17
- | `primaryAction` | `func` | | Callback for the primary action button. |
18
- | `primaryActionProps` | `object` | | Props for the primary action button. |
19
- | `primaryActionText` | `string` | | Text for the primary action button. |
20
- | `required` | `bool` | | Indicates if the field is required, showing an asterisk in the title. |
21
- | `scrolleable` | `bool` | `false` | Determines if the content inside the bottom sheet should be scrollable. |
22
- | `secondaryAction` | `func` | | Callback for the secondary action button. |
23
- | `secondaryActionProps` | `object` | | Props for the secondary action button. |
24
- | `secondaryActionText` | `string` | | Text for the secondary action button. |
25
- | `tertiaryAction` | `func` | | Callback for the tertiary action button. |
26
- | `tertiaryActionProps` | `object` | | Props for the tertiary action button . |
27
- | `tertiaryActionText` | `string` | | Text for the tertiary action button. |
28
- | `title` | `string` | | Title that appears in the bottom sheet header. |
29
- | `titleProps` | `object` | | Props for the title label |
30
- | `visible` | `bool` | | Controls the visibility of the bottom sheet. |
31
- | `withBodyPadding` | `bool` | `true` | Controls the visibility of the bottom sheet. |
9
+ | Name | Type | Default | Description |
10
+ | ---------------------- | -------- | ------- | ----------------------------------------------------------------------- |
11
+ | `actionAlignment` | `string` | | Aligns the actions. |
12
+ | `adjustableHeight` | `bool` | `false` | If true the height of the component adjusts to the content. |
13
+ | `buttonText` | `string` | | Text for the button that appears in the top right corner of the header. |
14
+ | `dataTestId` | `string` | | Test ID for automated testing. Enables hierarchical test ID structure. |
15
+ | `description` | `string` | | Description that appears below the title in the header. |
16
+ | `onClose` | `func` | | Function called when the bottom sheet is closed. |
17
+ | `onCloseProps` | `object` | | Additional props passed to the `onClose` function (optional). |
18
+ | `primaryAction` | `func` | | Callback for the primary action button. |
19
+ | `primaryActionProps` | `object` | | Props for the primary action button. |
20
+ | `primaryActionText` | `string` | | Text for the primary action button. |
21
+ | `required` | `bool` | | Indicates if the field is required, showing an asterisk in the title. |
22
+ | `scrolleable` | `bool` | `false` | Determines if the content inside the bottom sheet should be scrollable. |
23
+ | `secondaryAction` | `func` | | Callback for the secondary action button. |
24
+ | `secondaryActionProps` | `object` | | Props for the secondary action button. |
25
+ | `secondaryActionText` | `string` | | Text for the secondary action button. |
26
+ | `tertiaryAction` | `func` | | Callback for the tertiary action button. |
27
+ | `tertiaryActionProps` | `object` | | Props for the tertiary action button . |
28
+ | `tertiaryActionText` | `string` | | Text for the tertiary action button. |
29
+ | `title` | `string` | | Title that appears in the bottom sheet header. |
30
+ | `titleProps` | `object` | | Props for the title label |
31
+ | `visible` | `bool` | | Controls the visibility of the bottom sheet. |
32
+ | `withBodyPadding` | `bool` | `true` | Controls the visibility of the bottom sheet. |
32
33
 
33
34
  ### actionAlignment
34
35
 
@@ -39,8 +40,35 @@ The value of `actionAlignment` must be one of the following:
39
40
 
40
41
  By default, actions are aligned horizontally if there are two, and vertically otherwise.
41
42
 
43
+ ## Test IDs
44
+
45
+ When `dataTestId` is provided, the component creates a hierarchical test ID structure:
46
+
47
+ | Element | Test ID | Condition |
48
+ | ---------------- | ------------------------------- | --------------------------------------- |
49
+ | Modal container | `${dataTestId}` | Always when `dataTestId` provided |
50
+ | Title | `${dataTestId}.title` | When `title` prop is provided |
51
+ | Description | `${dataTestId}.description` | When `description` prop is provided |
52
+ | Close button | `${dataTestId}.closeButton` | When `buttonText` prop is provided |
53
+ | Primary action | `${dataTestId}.primaryAction` | When `primaryAction` prop is provided |
54
+ | Secondary action | `${dataTestId}.secondaryAction` | When `secondaryAction` prop is provided |
55
+ | Tertiary action | `${dataTestId}.tertiaryAction` | When `tertiaryAction` prop is provided |
56
+
57
+ ### Action Button Test IDs
58
+
59
+ Action buttons inherit test IDs from `UTButton` component:
60
+
61
+ - Each action gets its specific test ID (e.g., `${dataTestId}.primaryAction`)
62
+ - UTButton creates its own hierarchy for internal elements
63
+
64
+ ### Children Test IDs
65
+
66
+ The content area (children) does not receive a test ID automatically. Developers should add test IDs directly to their children components as needed.
67
+
42
68
  ## Example
43
69
 
70
+ ### Basic Usage
71
+
44
72
  ```jsx
45
73
  import React, { useState } from 'react';
46
74
  import { View, Button, Text } from 'react-native';
@@ -74,3 +102,46 @@ const Example = () => {
74
102
 
75
103
  export default Example;
76
104
  ```
105
+
106
+ ### With Test IDs
107
+
108
+ ```jsx
109
+ import React, { useState } from 'react';
110
+ import { View, Button, Text } from 'react-native';
111
+ import UTBottomSheet from './UTBottomSheet';
112
+
113
+ const TestableExample = () => {
114
+ const [visible, setVisible] = useState(false);
115
+
116
+ return (
117
+ <View style={{ flex: 1 }}>
118
+ <Button title="Show Bottom Sheet" onPress={() => setVisible(true)} />
119
+ <UTBottomSheet
120
+ dataTestId="settingsSheet"
121
+ title="Settings"
122
+ description="Configure your preferences"
123
+ buttonText="Done"
124
+ visible={visible}
125
+ onClose={() => setVisible(false)}
126
+ primaryAction={() => console.log('Save')}
127
+ primaryActionText="Save Changes"
128
+ secondaryAction={() => console.log('Cancel')}
129
+ secondaryActionText="Cancel"
130
+ tertiaryAction={() => console.log('Reset')}
131
+ tertiaryActionText="Reset to Default"
132
+ >
133
+ <Text>Settings content goes here</Text>
134
+ </UTBottomSheet>
135
+ </View>
136
+ );
137
+ };
138
+
139
+ // Generated test IDs:
140
+ // settingsSheet
141
+ // settingsSheet.title
142
+ // settingsSheet.description
143
+ // settingsSheet.closeButton
144
+ // settingsSheet.primaryAction
145
+ // settingsSheet.secondaryAction
146
+ // settingsSheet.tertiaryAction
147
+ ```
@@ -8,10 +8,20 @@ import UTButton from '../UTButton';
8
8
  import UTFieldLabel from '../UTFieldLabel';
9
9
  import UTLabel from '../UTLabel';
10
10
  import { IS_IOS } from '../../utils/platformUtils/constants';
11
+ import { TEST_ID_CONSTANTS } from '../../constants/testIds';
11
12
 
12
13
  import styles from './styles';
13
14
  import { ACTION_ALIGNMENTS } from './constants';
14
15
 
16
+ const {
17
+ title: titleTestId,
18
+ closeButton,
19
+ description: descriptionTestId,
20
+ primaryAction: primaryActionTestId,
21
+ secondaryAction: secondaryActionTestId,
22
+ tertiaryAction: tertiaryActionTestId
23
+ } = TEST_ID_CONSTANTS;
24
+
15
25
  const screenHeight = Dimensions.get('window').height;
16
26
 
17
27
  const UTBottomSheet = ({
@@ -36,7 +46,8 @@ const UTBottomSheet = ({
36
46
  title,
37
47
  titleProps = {},
38
48
  visible,
39
- withBodyPadding = true
49
+ withBodyPadding = true,
50
+ dataTestId
40
51
  }) => {
41
52
  const [height, setHeight] = useState('70%');
42
53
  const [modalHeight, setModalHeight] = useState(height);
@@ -94,6 +105,7 @@ const UTBottomSheet = ({
94
105
  propagateSwipe
95
106
  style={styles.modal}
96
107
  swipeDirection="down"
108
+ testID={dataTestId}
97
109
  >
98
110
  <Animated.View style={[styles.animatedContainer(theme), { height: modalHeight }, pan.getLayout()]}>
99
111
  <SafeAreaView onLayout={onLayout} style={styles.content(adjustableHeight)}>
@@ -108,6 +120,7 @@ const UTBottomSheet = ({
108
120
  style={styles.title}
109
121
  variant="subtitle1"
110
122
  weight="medium"
123
+ dataTestId={dataTestId ? `${dataTestId}.${titleTestId}` : undefined}
111
124
  {...titleProps}
112
125
  >
113
126
  {title}
@@ -117,6 +130,7 @@ const UTBottomSheet = ({
117
130
  colorTheme="primary"
118
131
  onPress={onClose}
119
132
  variant="semitransparent"
133
+ dataTestId={dataTestId ? `${dataTestId}.${closeButton}` : undefined}
120
134
  {...onCloseProps}
121
135
  >
122
136
  {buttonText}
@@ -124,7 +138,11 @@ const UTBottomSheet = ({
124
138
  )}
125
139
  </View>
126
140
  {description && (
127
- <UTLabel colorTheme="gray" variant="small">
141
+ <UTLabel
142
+ colorTheme="gray"
143
+ variant="small"
144
+ dataTestId={dataTestId ? `${dataTestId}.${descriptionTestId}` : undefined}
145
+ >
128
146
  {description}
129
147
  </UTLabel>
130
148
  )}
@@ -142,12 +160,14 @@ const UTBottomSheet = ({
142
160
  variant: 'semitransparent',
143
161
  onPress: primaryAction,
144
162
  text: primaryActionText,
163
+ dataTestId: dataTestId ? `${dataTestId}.${primaryActionTestId}` : undefined,
145
164
  ...primaryActionProps
146
165
  },
147
166
  {
148
167
  key: 'secondaryAction',
149
168
  onPress: secondaryAction,
150
169
  text: secondaryActionText,
170
+ dataTestId: dataTestId ? `${dataTestId}.${secondaryActionTestId}` : undefined,
151
171
  ...secondaryActionProps
152
172
  },
153
173
  {
@@ -155,16 +175,18 @@ const UTBottomSheet = ({
155
175
  onPress: tertiaryAction,
156
176
  text: tertiaryActionText,
157
177
  variant: 'text',
178
+ dataTestId: dataTestId ? `${dataTestId}.${tertiaryActionTestId}` : undefined,
158
179
  ...tertiaryActionProps
159
180
  }
160
181
  ].map(
161
- ({ text, key, onPress, ...actionProps }) =>
182
+ ({ text, key, onPress, dataTestId: actionDataTestId, ...actionProps }) =>
162
183
  onPress && (
163
184
  <UTButton
164
185
  key={key}
165
186
  onPress={onPress}
166
187
  size="large"
167
188
  style={styles.action(actionAlignment)}
189
+ dataTestId={actionDataTestId}
168
190
  {...actionProps}
169
191
  >
170
192
  {text}
@@ -204,7 +226,8 @@ UTBottomSheet.propTypes = {
204
226
  title: string,
205
227
  titleProps: object,
206
228
  visible: bool,
207
- withBodyPadding: bool
229
+ withBodyPadding: bool,
230
+ dataTestId: string
208
231
  };
209
232
 
210
233
  export default UTBottomSheet;
@@ -8,15 +8,19 @@ import UTBadge from '../UTBadge';
8
8
  import UTIcon from '../UTIcon';
9
9
  import UTLabel from '../UTLabel';
10
10
  import UTLoading from '../UTLoading';
11
+ import { TEST_ID_CONSTANTS } from '../../constants/testIds';
11
12
 
12
13
  import { COLORS_MAPPER, ICON_PLACEMENTS, VARIANTS_NAMES } from './constants';
13
14
  import { defaultProps, propTypes } from './proptypes';
14
15
  import { retrieveStyle } from './theme';
15
16
 
17
+ const { icon, badge, label: labelTestId } = TEST_ID_CONSTANTS;
18
+
16
19
  const UTButton = ({
17
20
  children,
18
21
  colorTheme,
19
22
  count,
23
+ dataTestId,
20
24
  disabled,
21
25
  Icon,
22
26
  iconPlacement,
@@ -67,6 +71,7 @@ const UTButton = ({
67
71
  return (
68
72
  <UTIcon
69
73
  colorTheme={textStyles.colorTheme}
74
+ dataTestId={`${dataTestId}.${icon}`}
70
75
  name={Icon}
71
76
  size={iconSize}
72
77
  style={remainingIconStyles}
@@ -74,15 +79,24 @@ const UTButton = ({
74
79
  );
75
80
  })()
76
81
  ) : (
77
- <Icon style={iconStyles} fill={iconStyles.color} />
82
+ <Icon testID={`${dataTestId}.${icon}`} style={iconStyles} fill={iconStyles.color} />
78
83
  ));
79
84
 
80
85
  const RenderedChildren = (
81
86
  <View style={themeChildrenContainerStyles}>
82
- {count && <UTBadge colorTheme={counterColorTheme}>{count}</UTBadge>}
87
+ {count && (
88
+ <UTBadge colorTheme={counterColorTheme} dataTestId={`${dataTestId}.${badge}`}>
89
+ {count}
90
+ </UTBadge>
91
+ )}
83
92
  {iconPlacement === ICON_PLACEMENTS.LEFT && IconToShow}
84
93
  {children && (
85
- <UTLabel colorTheme={textStyles.colorTheme} variant={textStyles.variant} weight={textStyles.weight}>
94
+ <UTLabel
95
+ colorTheme={textStyles.colorTheme}
96
+ dataTestId={`${dataTestId}.${labelTestId}`}
97
+ variant={textStyles.variant}
98
+ weight={textStyles.weight}
99
+ >
86
100
  {children}
87
101
  </UTLabel>
88
102
  )}
@@ -91,7 +105,7 @@ const UTButton = ({
91
105
  );
92
106
 
93
107
  return (
94
- <Pressable disabled={disabled || loading} onPress={onPress} style={buttonStyles}>
108
+ <Pressable testID={dataTestId} disabled={disabled || loading} onPress={onPress} style={buttonStyles}>
95
109
  <UTLoading color={iconStyles.color} loading={loading} size={24} thickness={2}>
96
110
  {RenderedChildren}
97
111
  </UTLoading>
@@ -15,6 +15,7 @@ export const propTypes = {
15
15
  colorTheme: string,
16
16
  count: number,
17
17
  disabled: bool,
18
+ dataTestId: string,
18
19
  Icon: elementType,
19
20
  iconPlacement: string,
20
21
  loading: bool,