@widergy/mobile-ui 1.47.0 → 1.48.0

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 (80) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/lib/components/CaptionLabel/README.md +30 -8
  3. package/lib/components/CaptionLabel/index.js +2 -1
  4. package/lib/components/CaptionLabel/propTypes.js +1 -0
  5. package/lib/components/Checkbox/README.md +93 -25
  6. package/lib/components/Checkbox/index.js +14 -1
  7. package/lib/components/Checkbox/propTypes.js +1 -0
  8. package/lib/components/Label/index.js +2 -1
  9. package/lib/components/Label/propTypes.js +1 -0
  10. package/lib/components/RadioGroup/components/RadioButton/index.js +29 -18
  11. package/lib/components/RadioGroup/index.js +19 -5
  12. package/lib/components/Touchable/index.js +3 -1
  13. package/lib/components/Touchable/propTypes.js +1 -0
  14. package/lib/components/UTBadge/index.js +3 -1
  15. package/lib/components/UTBaseInputField/README.md +41 -19
  16. package/lib/components/UTBaseInputField/components/ActionAdornment/index.js +10 -3
  17. package/lib/components/UTBaseInputField/components/BadgeAdornment/index.js +6 -1
  18. package/lib/components/UTBaseInputField/components/IconAdornment/index.js +8 -1
  19. package/lib/components/UTBaseInputField/components/PrefixAdornment/index.js +8 -2
  20. package/lib/components/UTBaseInputField/components/SuffixAdornment/index.js +6 -1
  21. package/lib/components/UTBaseInputField/components/TooltipAdornment/index.js +16 -3
  22. package/lib/components/UTBaseInputField/index.js +15 -4
  23. package/lib/components/UTBottomSheet/README.md +94 -23
  24. package/lib/components/UTBottomSheet/index.js +27 -4
  25. package/lib/components/UTButton/index.js +18 -4
  26. package/lib/components/UTButton/proptypes.js +1 -0
  27. package/lib/components/UTCheckBox/README.md +47 -0
  28. package/lib/components/UTCheckBox/index.js +24 -3
  29. package/lib/components/UTCheckBox/proptypes.js +1 -0
  30. package/lib/components/UTCheckList/README.MD +63 -0
  31. package/lib/components/UTCheckList/index.js +25 -2
  32. package/lib/components/UTCheckList/proptypes.js +1 -0
  33. package/lib/components/UTDetailDrawer/README.md +60 -10
  34. package/lib/components/UTDetailDrawer/index.js +11 -1
  35. package/lib/components/UTDetailDrawer/propTypes.js +1 -0
  36. package/lib/components/UTFieldLabel/README.md +99 -0
  37. package/lib/components/UTFieldLabel/index.js +19 -2
  38. package/lib/components/UTIcon/README.md +25 -2
  39. package/lib/components/UTIcon/index.js +3 -1
  40. package/lib/components/UTLabel/README.md +26 -0
  41. package/lib/components/UTLabel/index.js +2 -0
  42. package/lib/components/UTLabel/proptypes.js +1 -0
  43. package/lib/components/UTMenu/README.md +275 -0
  44. package/lib/components/UTMenu/components/ListView/index.js +5 -3
  45. package/lib/components/UTMenu/components/ListView/proptypes.js +2 -1
  46. package/lib/components/UTMenu/components/MenuOption/index.js +5 -3
  47. package/lib/components/UTMenu/index.js +18 -3
  48. package/lib/components/UTMenu/proptypes.js +2 -1
  49. package/lib/components/UTModal/README.md +193 -0
  50. package/lib/components/UTModal/index.js +22 -2
  51. package/lib/components/UTModal/proptypes.js +1 -0
  52. package/lib/components/UTPhoneInput/index.js +25 -2
  53. package/lib/components/UTRoundView/README.md +158 -0
  54. package/lib/components/UTRoundView/index.js +12 -1
  55. package/lib/components/UTRoundView/propTypes.js +4 -2
  56. package/lib/components/UTSearchField/README.md +64 -14
  57. package/lib/components/UTSearchField/index.js +3 -1
  58. package/lib/components/UTSearchField/proptypes.js +2 -1
  59. package/lib/components/UTSelect/versions/V0/README.md +216 -0
  60. package/lib/components/UTSelect/versions/V0/componentes/MultipleItem/index.js +4 -2
  61. package/lib/components/UTSelect/versions/V0/index.js +5 -2
  62. package/lib/components/UTSelect/versions/V0/proptypes.js +2 -1
  63. package/lib/components/UTSelect/versions/V1/README.md +94 -0
  64. package/lib/components/UTSelect/versions/V1/index.js +28 -6
  65. package/lib/components/UTSelect/versions/V1/proptypes.js +1 -0
  66. package/lib/components/UTSelectableCard/README.md +85 -0
  67. package/lib/components/UTSelectableCard/index.js +52 -4
  68. package/lib/components/UTTextInput/versions/V0/components/BaseInput/index.js +5 -1
  69. package/lib/components/UTTextInput/versions/V0/components/InputLabel/index.js +4 -1
  70. package/lib/components/UTTextInput/versions/V0/flavors/FilledInput/index.js +9 -1
  71. package/lib/components/UTTextInput/versions/V0/flavors/OutlinedInput/index.js +9 -1
  72. package/lib/components/UTTextInput/versions/V0/flavors/StandardInput/index.js +9 -1
  73. package/lib/components/UTTextInput/versions/V1/components/TextInputField/index.js +3 -0
  74. package/lib/components/UTTextInput/versions/V1/index.js +20 -3
  75. package/lib/components/UTTooltip/README.md +99 -0
  76. package/lib/components/UTTooltip/index.js +2 -0
  77. package/lib/components/UTTooltip/proptypes.js +2 -1
  78. package/lib/components/UTValidation/index.js +26 -4
  79. package/lib/constants/testIds.js +44 -0
  80. package/package.json +1 -1
@@ -0,0 +1,216 @@
1
+ # UTSelect V0
2
+
3
+ > **⚠️ AI-Generated Documentation Disclaimer**
4
+ > This documentation has been generated with AI assistance and has not been thoroughly reviewed by a developer. Please verify implementation details and usage examples before relying on them in production code.
5
+
6
+ A customizable select/dropdown component with support for single and multiple selection modes. Features autocomplete functionality, custom styling, and comprehensive test ID support.
7
+
8
+ ## Props
9
+
10
+ | NAME | TYPE | REQUIRED | DESCRIPTION |
11
+ | ---------------- | ------ | -------- | ----------------------------------------------------------------------------------------- |
12
+ | options | array | Yes | Array of option objects. Each option must have `id`, `label`, and `value` properties. |
13
+ | value | any | No | Selected value(s). For single select: option value. For multiple: array of values. |
14
+ | onChange | func | No | Callback function called when selection changes. Receives the selected value(s). |
15
+ | label | string | No | Label text for the input field. |
16
+ | error | string | No | Error message to display. |
17
+ | disabled | bool | No | Whether the select is disabled. |
18
+ | variant | string | No | Visual variant for the text input. |
19
+ | isMultiple | bool | No | Enables multiple selection mode with checkboxes. |
20
+ | title | string | No | Title text displayed above the select. |
21
+ | titleProps | object | No | Additional props to pass to the title Label component. |
22
+ | changeOnClose | bool | No | When true, onChange is only called when the menu closes, not on each selection. |
23
+ | verticalOffset | number | No | Vertical offset for the dropdown menu positioning. Default: 5. |
24
+ | UTMenuProps | object | No | Additional props to pass to the underlying UTMenu component. |
25
+ | UTTextInputProps | object | No | Additional props to pass to the underlying UTTextInput component. |
26
+ | styles | object | No | Custom styles for the container. |
27
+ | dataTestId | string | No | Unique identifier for testing purposes. Creates hierarchical test IDs for child elements. |
28
+
29
+ ## Option Object Structure
30
+
31
+ Each option in the `options` array should have the following structure:
32
+
33
+ ```js
34
+ {
35
+ id: string | number, // Unique identifier for the option
36
+ label: string, // Display text for the option
37
+ value: any, // Value to be passed to onChange when selected
38
+ action?: function // Optional custom action function
39
+ }
40
+ ```
41
+
42
+ ## Usage Examples
43
+
44
+ ### Basic Single Select
45
+
46
+ ```jsx
47
+ import React, { useState } from 'react';
48
+ import UTSelect from '@widergy/mobile-ui/lib/components/UTSelect/versions/V0';
49
+
50
+ const BasicExample = () => {
51
+ const [selectedValue, setSelectedValue] = useState(null);
52
+
53
+ const options = [
54
+ { id: '1', label: 'Option 1', value: 'value1' },
55
+ { id: '2', label: 'Option 2', value: 'value2' },
56
+ { id: '3', label: 'Option 3', value: 'value3' }
57
+ ];
58
+
59
+ return (
60
+ <UTSelect options={options} value={selectedValue} onChange={setSelectedValue} label="Choose an option" />
61
+ );
62
+ };
63
+ ```
64
+
65
+ ### Multiple Select with Title
66
+
67
+ ```jsx
68
+ const MultipleSelectExample = () => {
69
+ const [selectedValues, setSelectedValues] = useState([]);
70
+
71
+ const options = [
72
+ { id: 'red', label: 'Red', value: 'red' },
73
+ { id: 'green', label: 'Green', value: 'green' },
74
+ { id: 'blue', label: 'Blue', value: 'blue' }
75
+ ];
76
+
77
+ return (
78
+ <UTSelect
79
+ options={options}
80
+ value={selectedValues}
81
+ onChange={setSelectedValues}
82
+ label="Select colors"
83
+ title="Color Selection"
84
+ isMultiple
85
+ />
86
+ );
87
+ };
88
+ ```
89
+
90
+ ### With Error State
91
+
92
+ ```jsx
93
+ const ValidationExample = () => {
94
+ const [value, setValue] = useState(null);
95
+ const [error, setError] = useState('');
96
+
97
+ const handleChange = newValue => {
98
+ setValue(newValue);
99
+ if (newValue) {
100
+ setError('');
101
+ } else {
102
+ setError('Please select an option');
103
+ }
104
+ };
105
+
106
+ return (
107
+ <UTSelect options={options} value={value} onChange={handleChange} label="Required Field" error={error} />
108
+ );
109
+ };
110
+ ```
111
+
112
+ ## Testing
113
+
114
+ The `UTSelect` component supports comprehensive test ID assignment through the `dataTestId` prop. When provided, it creates a hierarchical structure of test IDs for all interactive and meaningful elements.
115
+
116
+ ### Test ID Structure
117
+
118
+ When you provide `dataTestId="provided.testId"`, the following test IDs are automatically generated:
119
+
120
+ | Element | Test ID | When Available |
121
+ | ----------------------- | ------------------------ | ------------------------------------------------------- |
122
+ | Text input field | `provided.testId` | Always (when dataTestId is provided) |
123
+ | Title text | `provided.testId.title` | When title prop is provided |
124
+ | Menu (all sub-elements) | `provided.testId.menu.*` | When menu is open - inherits UTMenu's test ID structure |
125
+
126
+ **Note:**
127
+
128
+ - The text input field test ID (`provided.testId`) creates additional hierarchical test IDs based on the UTTextInput component's own test ID structure.
129
+ - The menu test ID (`provided.testId.menu`) creates a hierarchical structure based on UTMenu's streamlined test ID implementation, including:
130
+ - `provided.testId.menu.anchor` (menu trigger)
131
+ - `provided.testId.menu.modal` (when open)
132
+ - `provided.testId.menu.searchInput` (when autocomplete is enabled)
133
+ - `provided.testId.menu.list` (options container)
134
+ - `provided.testId.menu.list.option.{index}` (each option by index)
135
+ - `provided.testId.menu.list.option.{index}.label` (each option label)
136
+ - For multiple selection: each checkbox inherits the option's test ID structure
137
+
138
+ ### Test ID Examples
139
+
140
+ ```jsx
141
+ // Basic single select with test IDs
142
+ <UTSelect
143
+ dataTestId="countrySelect"
144
+ options={countries}
145
+ value={selectedCountry}
146
+ onChange={setSelectedCountry}
147
+ label="Select Country"
148
+ />
149
+
150
+ // Creates test IDs:
151
+ // - countrySelect (text input field and its sub-elements)
152
+ // - countrySelect.menu.anchor (menu trigger - same as text input area)
153
+ // - countrySelect.menu.modal (when menu is open)
154
+ // - countrySelect.menu.list (options container when open)
155
+ // - countrySelect.menu.list.option.0 (first option when open)
156
+ // - countrySelect.menu.list.option.0.label (first option label when open)
157
+ // - countrySelect.menu.list.option.1 (second option when open)
158
+ // - countrySelect.menu.list.option.1.label (second option label when open)
159
+ // ... etc for each option
160
+
161
+ // Multiple select with title and test IDs
162
+ <UTSelect
163
+ dataTestId="skillsSelect"
164
+ options={skillOptions}
165
+ value={selectedSkills}
166
+ onChange={setSelectedSkills}
167
+ title="Technical Skills"
168
+ label="Choose your skills"
169
+ isMultiple
170
+ />
171
+
172
+ // Creates test IDs:
173
+ // - skillsSelect (text input field and its sub-elements)
174
+ // - skillsSelect.title (title label)
175
+ // - skillsSelect.menu.anchor (menu trigger)
176
+ // - skillsSelect.menu.modal (when menu is open)
177
+ // - skillsSelect.menu.list (options container when open)
178
+ // - skillsSelect.menu.list.option.0 (first checkbox option when open)
179
+ // - skillsSelect.menu.list.option.0.label (first option label when open)
180
+ // - skillsSelect.menu.list.option.1 (second checkbox option when open)
181
+ // - skillsSelect.menu.list.option.1.label (second option label when open)
182
+ // - skillsSelect.menu.list.option.2 (third checkbox option when open)
183
+ // - skillsSelect.menu.list.option.2.label (third option label when open)
184
+ // ... etc for each option
185
+
186
+ // Complex example with searchable menu
187
+ const options = [
188
+ { id: 'beginner', label: 'Beginner Level', value: 'beginner' },
189
+ { id: 'intermediate', label: 'Intermediate Level', value: 'intermediate' },
190
+ { id: 'advanced', label: 'Advanced Level', value: 'advanced' }
191
+ ];
192
+
193
+ <UTSelect
194
+ dataTestId="userLevel"
195
+ options={options}
196
+ value={userLevel}
197
+ onChange={setUserLevel}
198
+ title="Experience Level"
199
+ label="Select your level"
200
+ UTMenuProps={{ withAutocomplete: true, autoCompletePlaceholder: "Search levels..." }}
201
+ />
202
+
203
+ // Creates test IDs:
204
+ // - userLevel (text input field and its sub-elements)
205
+ // - userLevel.title (title label)
206
+ // - userLevel.menu.anchor (menu trigger)
207
+ // - userLevel.menu.modal (when menu is open)
208
+ // - userLevel.menu.searchInput (search input when menu is open)
209
+ // - userLevel.menu.list (options container when open)
210
+ // - userLevel.menu.list.option.0 (first option when open)
211
+ // - userLevel.menu.list.option.0.label (first option label when open)
212
+ // - userLevel.menu.list.option.1 (second option when open)
213
+ // - userLevel.menu.list.option.1.label (second option label when open)
214
+ // - userLevel.menu.list.option.2 (third option when open)
215
+ // - userLevel.menu.list.option.2.label (third option label when open)
216
+ ```
@@ -6,12 +6,13 @@ import Checkbox from '../../../../../Checkbox';
6
6
 
7
7
  import styles from './styles';
8
8
 
9
- const MultipleItem = ({ onPress, label, selected, checkboxProps, item }) => (
9
+ const MultipleItem = ({ onPress, label, selected, checkboxProps, item, dataTestId }) => (
10
10
  <Checkbox
11
11
  label={label}
12
12
  onPress={() => onPress(item)}
13
13
  checked={selected}
14
14
  style={styles.checkbox}
15
+ dataTestId={dataTestId}
15
16
  {...checkboxProps}
16
17
  />
17
18
  );
@@ -21,7 +22,8 @@ MultipleItem.propTypes = {
21
22
  label: string,
22
23
  selected: bool,
23
24
  checkboxProps: shape(any),
24
- item: shape(any)
25
+ item: shape(any),
26
+ dataTestId: string
25
27
  };
26
28
 
27
29
  export default memo(MultipleItem);
@@ -25,7 +25,8 @@ const UTSelect = ({
25
25
  verticalOffset = 5,
26
26
  title,
27
27
  titleProps,
28
- changeOnClose
28
+ changeOnClose,
29
+ dataTestId
29
30
  }) => {
30
31
  const [focused, setFocused] = useState(false);
31
32
 
@@ -63,7 +64,7 @@ const UTSelect = ({
63
64
  return (
64
65
  <View style={[styles.container, propStyles]}>
65
66
  {title && (
66
- <Label medium primary {...titleProps}>
67
+ <Label medium primary {...titleProps} dataTestId={dataTestId ? `${dataTestId}.title` : undefined}>
67
68
  {title}
68
69
  </Label>
69
70
  )}
@@ -79,6 +80,7 @@ const UTSelect = ({
79
80
  withoutOpacity
80
81
  MenuOptionComponent={isMultiple && MultipleItem}
81
82
  isMultiple={isMultiple}
83
+ dataTestId={dataTestId ? `${dataTestId}.menu` : undefined}
82
84
  {...UTMenuProps}
83
85
  >
84
86
  <UTTextInput
@@ -91,6 +93,7 @@ const UTSelect = ({
91
93
  disabled={disabled}
92
94
  version="V0"
93
95
  RightIcon={{ type: 'font-awesome', name: 'caret-down' }}
96
+ dataTestId={dataTestId}
94
97
  {...UTTextInputProps}
95
98
  />
96
99
  </UTMenu>
@@ -18,5 +18,6 @@ export default {
18
18
  variant: string,
19
19
  UTMenuProps: any,
20
20
  value: any,
21
- isMultiple: bool
21
+ isMultiple: bool,
22
+ dataTestId: string
22
23
  };
@@ -9,6 +9,7 @@
9
9
  | action | shape | | Action object containing `Icon`, `onPress`, and `size` for the action button. |
10
10
  | alwaysShowPlaceholder | bool | true | Determines if the placeholder should always be shown. |
11
11
  | clearable | bool | false | Determines whether a button to clear the current selection should be shown. |
12
+ | dataTestId | string | | Test ID for automated testing. Enables hierarchical test ID structure. |
12
13
  | helpText | string | | Help text displayed below the input field. |
13
14
  | title | string | | Title for the select field. |
14
15
  | multiple | bool | false | Allows multiple selection if true. |
@@ -27,6 +28,47 @@
27
28
  | value | oneOfType([string, array]) | null | The value of the input field. It can be a string for single selection or an array for multiple selection. |
28
29
  | withAutoReset | bool | true | Determines whether the select should automatically reset when the selected value is no longer available in the options. |
29
30
 
31
+ ## Test IDs
32
+
33
+ When `dataTestId` is provided, the component creates a hierarchical test ID structure:
34
+
35
+ | Element | Test ID | Condition |
36
+ | ------------------ | -------------------------------- | --------------------------------- |
37
+ | Select trigger | `${dataTestId}` | Always when `dataTestId` provided |
38
+ | Title | `${dataTestId}.title` | When `title` prop is provided |
39
+ | Input field | `${dataTestId}.input` | Always when `dataTestId` provided |
40
+ | Help text | `${dataTestId}.helpText` | When `helpText` prop is provided |
41
+ | Validation | `${dataTestId}.validation` | When `error` prop is provided |
42
+ | Bottom sheet | `${dataTestId}.bottomSheet` | When bottom sheet is open |
43
+ | Search field | `${dataTestId}.searchField` | When bottom sheet is open |
44
+ | No options message | `${dataTestId}.noOptionsMessage` | When no options to display |
45
+ | Options list | `${dataTestId}.optionsList` | When options are available |
46
+
47
+ ### Child Component Test IDs
48
+
49
+ UTSelect V1 uses several child components that have their own test ID hierarchies:
50
+
51
+ - **UTBaseInputField**: Creates test IDs for input field and adornments (badge, prefix, suffix, clear action, chevron icon)
52
+ - **UTBottomSheet**: Creates test IDs for modal, title, description, close button, and action buttons
53
+ - **UTSearchField**: Creates test IDs for search input, search icon, and clear button
54
+ - **UTCheckList**: Creates test IDs for checkboxes, labels, and select all functionality
55
+
56
+ ### Test ID Structure Details
57
+
58
+ ```
59
+ ${dataTestId} // Select trigger (Pressable)
60
+ ${dataTestId}.title // Title label
61
+ ${dataTestId}.input // Input field (+ UTBaseInputField hierarchy)
62
+ ${dataTestId}.input.left // Badge (when multiple selection has values)
63
+ ${dataTestId}.input.right // Clear action, chevron icon, custom action
64
+ ${dataTestId}.helpText // Help text
65
+ ${dataTestId}.validation // Validation message
66
+ ${dataTestId}.bottomSheet // Bottom sheet (+ UTBottomSheet hierarchy)
67
+ ${dataTestId}.searchField // Search field (+ UTSearchField hierarchy)
68
+ ${dataTestId}.noOptionsMessage // No options message
69
+ ${dataTestId}.optionsList // Options list (+ UTCheckList hierarchy)
70
+ ```
71
+
30
72
  ### Option Object
31
73
 
32
74
  The `options` prop is an array of objects, each representing an option:
@@ -42,6 +84,8 @@ The `options` prop is an array of objects, each representing an option:
42
84
 
43
85
  ## Usage
44
86
 
87
+ ### Basic Example
88
+
45
89
  ```jsx
46
90
  import React, { useState } from 'react';
47
91
  import { View, Text } from 'react-native';
@@ -75,3 +119,53 @@ const UTSelectExample = () => {
75
119
 
76
120
  export default UTSelectExample;
77
121
  ```
122
+
123
+ ### With Test IDs
124
+
125
+ ```jsx
126
+ import React, { useState } from 'react';
127
+ import { View, Text } from 'react-native';
128
+ import UTSelect from './UTSelect';
129
+
130
+ const options = [
131
+ { label: 'React', value: 'react' },
132
+ { label: 'JavaScript', value: 'javascript' },
133
+ { label: 'TypeScript', value: 'typescript' },
134
+ { label: 'Node.js', value: 'nodejs' }
135
+ ];
136
+
137
+ const TestableSelectExample = () => {
138
+ const [selectedSkills, setSelectedSkills] = useState([]);
139
+
140
+ return (
141
+ <View style={{ padding: 20 }}>
142
+ <UTSelect
143
+ dataTestId="skillsSelect"
144
+ title="Select Skills"
145
+ helpText="Choose your programming skills"
146
+ multiple={true}
147
+ clearable={true}
148
+ noMatchesText="No skills found"
149
+ noOptionsText="No skills available"
150
+ onChange={setSelectedSkills}
151
+ options={options}
152
+ placeholder="Choose skills..."
153
+ searchPlaceholder="Search skills..."
154
+ selectAllLabel="Select All Skills"
155
+ showSelectAll={true}
156
+ value={selectedSkills}
157
+ />
158
+ <Text>Selected Skills: {selectedSkills.join(', ')}</Text>
159
+ </View>
160
+ );
161
+ };
162
+
163
+ // Generated test IDs include:
164
+ // skillsSelect (select trigger)
165
+ // skillsSelect.title
166
+ // skillsSelect.input (+ UTBaseInputField hierarchy)
167
+ // skillsSelect.helpText
168
+ // skillsSelect.bottomSheet (when open + UTBottomSheet hierarchy)
169
+ // skillsSelect.searchField (when open + UTSearchField hierarchy)
170
+ // skillsSelect.optionsList (when open + UTCheckList hierarchy)
171
+ ```
@@ -41,7 +41,8 @@ const UTSelect = ({
41
41
  value,
42
42
  onChangeSearchTerm,
43
43
  disableFilterOptions,
44
- withAutoReset
44
+ withAutoReset,
45
+ dataTestId
45
46
  }) => {
46
47
  const [bottomSheetVisible, setBottomSheetVisible] = useState(false);
47
48
  const [searchTerm, setSearchTerm] = useState('');
@@ -146,11 +147,15 @@ const UTSelect = ({
146
147
  <Fragment>
147
148
  <View style={[styles.container, style]}>
148
149
  {title && (
149
- <UTFieldLabel required={required} variant="body">
150
+ <UTFieldLabel
151
+ required={required}
152
+ variant="body"
153
+ dataTestId={dataTestId ? `${dataTestId}.title` : undefined}
154
+ >
150
155
  {title}
151
156
  </UTFieldLabel>
152
157
  )}
153
- <Pressable disabled={disabled} onPress={handleOpenBottomSheet}>
158
+ <Pressable disabled={disabled} onPress={handleOpenBottomSheet} testID={dataTestId}>
154
159
  <UTBaseInputField
155
160
  alwaysShowPlaceholder={alwaysShowPlaceholder}
156
161
  disabled={disabled}
@@ -162,14 +167,24 @@ const UTSelect = ({
162
167
  rightAdornments={rightAdornments}
163
168
  value={displayValue}
164
169
  variant="button"
170
+ dataTestId={dataTestId ? `${dataTestId}.input` : undefined}
165
171
  />
166
172
  </Pressable>
167
173
  {helpText && (
168
- <UTLabel colorTheme="gray" variant="small">
174
+ <UTLabel
175
+ colorTheme="gray"
176
+ variant="small"
177
+ dataTestId={dataTestId ? `${dataTestId}.helpText` : undefined}
178
+ >
169
179
  {helpText}
170
180
  </UTLabel>
171
181
  )}
172
- {validationData && <UTValidation validationData={validationData} />}
182
+ {validationData && (
183
+ <UTValidation
184
+ validationData={validationData}
185
+ dataTestId={dataTestId ? `${dataTestId}.validation` : undefined}
186
+ />
187
+ )}
173
188
  </View>
174
189
  <UTBottomSheet
175
190
  title={title}
@@ -177,6 +192,7 @@ const UTSelect = ({
177
192
  visible={bottomSheetVisible}
178
193
  onClose={handleCloseBottomSheet}
179
194
  buttonText={closeButtonText}
195
+ dataTestId={dataTestId ? `${dataTestId}.bottomSheet` : undefined}
180
196
  >
181
197
  <View style={styles.bottomSheetBodyContainer}>
182
198
  <UTSearchField
@@ -184,9 +200,14 @@ const UTSelect = ({
184
200
  placeholder={searchPlaceholder}
185
201
  value={searchTerm}
186
202
  variant="gray"
203
+ dataTestId={dataTestId ? `${dataTestId}.searchField` : undefined}
187
204
  />
188
205
  {isEmpty(filteredOptions) ? (
189
- <UTLabel colorTheme="gray" style={styles.noMatchesText}>
206
+ <UTLabel
207
+ colorTheme="gray"
208
+ style={styles.noMatchesText}
209
+ dataTestId={dataTestId ? `${dataTestId}.noOptionsMessage` : undefined}
210
+ >
190
211
  {!searchTerm ? noOptionsText : noMatchesText}
191
212
  </UTLabel>
192
213
  ) : (
@@ -200,6 +221,7 @@ const UTSelect = ({
200
221
  value={value ? (multiple ? value : [value]) : []}
201
222
  variant="button"
202
223
  style={{ item: { title: styles.checklistTitles } }}
224
+ dataTestId={dataTestId ? `${dataTestId}.optionsList` : undefined}
203
225
  />
204
226
  </ScrollView>
205
227
  )}
@@ -20,6 +20,7 @@ export const propTypes = {
20
20
  alwaysShowPlaceholder: bool,
21
21
  clearable: bool,
22
22
  closeButtonText: string,
23
+ dataTestId: string,
23
24
  disabled: bool,
24
25
  error: string,
25
26
  helpText: string,
@@ -11,9 +11,11 @@
11
11
  | `additionalInfo` | `additionalInfoType` | `{}` | Contains `description` and `title` to display supplementary information in the card. |
12
12
  | `appearance` | `string` | `'white'` | Defines the card's appearance. Supported values: `white`, `gray`. |
13
13
  | `checkIcon` | `bool` | `true` | Whether to show a check icon when the card is selected. |
14
+ | `dataTestId` | `string` | | Unique identifier for testing purposes. Creates hierarchical test IDs for child elements. |
14
15
  | `description` | `string` | | Secondary text shown below the title. |
15
16
  | `disabled` | `bool` | `false` | Disables the card, preventing interactions and applying a disabled style. |
16
17
  | `Icon` | `iconType` | | Icon configuration. Supports `url`, `name`, `shade`, `size`, or a custom `Component`. |
18
+ | `iconDataTestId` | `string` | | Override test ID for Icon.Component. If not provided, uses `${dataTestId}.icon`. |
17
19
  | `numberOfLines` | `number` | | Determines the amount of lines the text can span. If the text overflows it will be ellipsized |
18
20
  | `onPress` | `func` | | Function triggered when the card is pressed. |
19
21
  | `selected` | `bool` | `false` | Indicates whether the card is selected. |
@@ -82,6 +84,89 @@ export default Example;
82
84
  />
83
85
  ```
84
86
 
87
+ ## Testing
88
+
89
+ The `UTSelectableCard` component supports comprehensive test ID assignment through the `dataTestId` prop. When provided, it creates a hierarchical structure of test IDs for all interactive and meaningful elements.
90
+
91
+ ### Test ID Structure
92
+
93
+ When you provide `dataTestId="provided.testId"`, the following test IDs are automatically generated:
94
+
95
+ | Element | Test ID | When Available |
96
+ | --------------------------- | -------------------------------------------- | ------------------------------------------- |
97
+ | Card container (touchable) | `provided.testId` | Always (when dataTestId is provided) |
98
+ | Icon | `provided.testId.icon` | When Icon prop is provided |
99
+ | Title text | `provided.testId.titleText` | When titleText prop is provided |
100
+ | Description text | `provided.testId.description` | When description prop is provided |
101
+ | Tooltip | `provided.testId.tooltip` | When tooltip prop is provided |
102
+ | Tooltip content | `provided.testId.tooltip.content` | When tooltip prop is provided |
103
+ | Additional info title | `provided.testId.additionalInfo.title` | When additionalInfo.title is provided |
104
+ | Additional info description | `provided.testId.additionalInfo.description` | When additionalInfo.description is provided |
105
+ | Check icon | `provided.testId.checkIcon` | When selected=true and checkIcon=true |
106
+
107
+ **Note:** If `Icon.Component` is used, the `iconDataTestId` prop can be used to override the default `${dataTestId}.icon` test ID. This prop only applies to custom icon components and has no effect when using `Icon.url` or `Icon.name`.
108
+
109
+ **Children Test IDs:** The `children` prop renders React components directly without wrapping them. If child components need test IDs, it's the responsibility of the developer creating those components to add appropriate `dataTestId` props.
110
+
111
+ ### Example Usage
112
+
113
+ ```jsx
114
+ // Basic test ID usage
115
+ <UTSelectableCard
116
+ dataTestId="addressCard.1"
117
+ titleText="Home Address"
118
+ description="123 Main Street"
119
+ selected={true}
120
+ onPress={() => selectAddress(1)}
121
+ />
122
+
123
+ // Creates the following test IDs:
124
+ // - addressCard.1 (main container)
125
+ // - addressCard.1.titleText (title text)
126
+ // - addressCard.1.description (description text)
127
+ // - addressCard.1.checkIcon (check icon when selected)
128
+
129
+ // With all features enabled
130
+ <UTSelectableCard
131
+ dataTestId="paymentCard.visa"
132
+ titleText="Visa ****1234"
133
+ description="Expires 12/25"
134
+ additionalInfo={{ title: "Primary", description: "Default card" }}
135
+ Icon={{ name: "IconCreditCard" }}
136
+ tooltip="Secure payment method"
137
+ selected={false}
138
+ onPress={() => selectCard('visa')}
139
+ />
140
+
141
+ // Creates test IDs:
142
+ // - paymentCard.visa
143
+ // - paymentCard.visa.icon
144
+ // - paymentCard.visa.titleText
145
+ // - paymentCard.visa.description
146
+ // - paymentCard.visa.tooltip
147
+ // - paymentCard.visa.tooltip.content
148
+ // - paymentCard.visa.additionalInfo.title
149
+ // - paymentCard.visa.additionalInfo.description
150
+
151
+ // Custom icon test ID override
152
+ <UTSelectableCard
153
+ dataTestId="productCard.featured"
154
+ iconDataTestId="customProductIcon.primary"
155
+ titleText="Premium Product"
156
+ description="High-quality item"
157
+ Icon={{ Component: CustomIconComponent }}
158
+ selected={true}
159
+ onPress={() => selectProduct('featured')}
160
+ />
161
+
162
+ // Creates test IDs:
163
+ // - productCard.featured (main container)
164
+ // - customProductIcon.primary (custom icon test ID)
165
+ // - productCard.featured.titleText
166
+ // - productCard.featured.description
167
+ // - productCard.featured.checkIcon
168
+ ```
169
+
85
170
  ## Notes
86
171
 
87
172
  - Ensure to define custom styles through the `style` prop or the project theme.