@hero-design/rn-work-uikit 1.1.0-alpha.0 → 1.2.0-alpha.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 (56) hide show
  1. package/.cursorrules +57 -0
  2. package/CHANGELOG.md +8 -3
  3. package/DEVELOPMENT.md +118 -0
  4. package/THEME_OVERRIDE.md +52 -0
  5. package/eslint.config.js +20 -0
  6. package/lib/index.js +1000 -4
  7. package/locales/en_AU.js +10 -0
  8. package/locales/en_AU.mjs +8 -0
  9. package/locales/en_CA.js +10 -0
  10. package/locales/en_CA.mjs +8 -0
  11. package/locales/index.js +11 -0
  12. package/locales/index.mjs +9 -0
  13. package/locales/types.js +2 -0
  14. package/locales/types.mjs +1 -0
  15. package/package.json +8 -4
  16. package/rollup.config.mjs +18 -2
  17. package/src/__tests__/__snapshots__/index.spec.tsx.snap +91 -116
  18. package/src/__tests__/index.spec.tsx +15 -0
  19. package/src/__tests__/theme-export-override.spec.ts +96 -0
  20. package/src/components/TextInput/ErrorOrHelpText.tsx +58 -0
  21. package/src/components/TextInput/FloatingLabel.tsx +120 -0
  22. package/src/components/TextInput/InputComponent.tsx +61 -0
  23. package/src/components/TextInput/InputRow.tsx +103 -0
  24. package/src/components/TextInput/MaxLengthMessage.tsx +66 -0
  25. package/src/components/TextInput/PrefixComponent.tsx +77 -0
  26. package/src/components/TextInput/StyledTextInput.tsx +134 -0
  27. package/src/components/TextInput/SuffixComponent.tsx +73 -0
  28. package/src/components/TextInput/__tests__/ErrorOrHelpText.spec.tsx +20 -0
  29. package/src/components/TextInput/__tests__/FloatingLabel.spec.tsx +203 -0
  30. package/src/components/TextInput/__tests__/InputComponent.spec.tsx +39 -0
  31. package/src/components/TextInput/__tests__/InputRow.spec.tsx +275 -0
  32. package/src/components/TextInput/__tests__/MaxLengthMessage.spec.tsx +17 -0
  33. package/src/components/TextInput/__tests__/PrefixComponent.spec.tsx +14 -0
  34. package/src/components/TextInput/__tests__/StyledTextInput.spec.tsx +114 -0
  35. package/src/components/TextInput/__tests__/SuffixComponent.spec.tsx +20 -0
  36. package/src/components/TextInput/__tests__/__snapshots__/StyledTextInput.spec.tsx.snap +571 -0
  37. package/src/components/TextInput/__tests__/__snapshots__/index.spec.tsx.snap +5671 -0
  38. package/src/components/TextInput/__tests__/getState.spec.tsx +89 -0
  39. package/src/components/TextInput/__tests__/index.spec.tsx +699 -0
  40. package/src/components/TextInput/constants.ts +1 -0
  41. package/src/components/TextInput/index.tsx +327 -0
  42. package/src/components/TextInput/types.ts +95 -0
  43. package/src/emotion.d.ts +15 -0
  44. package/src/index.ts +16 -1
  45. package/src/jest.d.ts +24 -0
  46. package/src/theme/ThemeProvider.ts +20 -0
  47. package/src/theme/ThemeSwitcher.tsx +76 -0
  48. package/src/theme/__tests__/ThemeProvider.spec.tsx +32 -0
  49. package/src/theme/__tests__/__snapshots__/index.spec.ts.snap +1851 -0
  50. package/src/theme/__tests__/index.spec.ts +7 -0
  51. package/src/theme/components/textInput.ts +92 -0
  52. package/src/theme/getTheme.ts +32 -0
  53. package/src/theme/index.ts +17 -0
  54. package/src/utils/__tests__/helpers.spec.ts +92 -0
  55. package/src/utils/helpers.ts +113 -0
  56. package/testUtils/renderWithTheme.tsx +6 -3
@@ -0,0 +1,203 @@
1
+ import React from 'react';
2
+ import renderWithTheme from '../../../../testUtils/renderWithTheme';
3
+ import FloatingLabel from '../FloatingLabel';
4
+
5
+ describe('FloatingLabel', () => {
6
+ describe('label text display based on required prop', () => {
7
+ it.each`
8
+ required | expectedText | shouldShowOptional | description
9
+ ${true} | ${'Email'} | ${false} | ${'required field without optional indicator'}
10
+ ${false} | ${'Phone (Optional)'} | ${true} | ${'optional field with optional indicator'}
11
+ `(
12
+ 'should display $expectedText for $description',
13
+ ({ required, expectedText, shouldShowOptional }) => {
14
+ const label = required ? 'Email' : 'Phone';
15
+ const { getByText, queryByText } = renderWithTheme(
16
+ <FloatingLabel
17
+ label={label}
18
+ variant="text"
19
+ state="default"
20
+ isFocused={false}
21
+ required={required}
22
+ isEmptyValue
23
+ />
24
+ );
25
+
26
+ // User should see the appropriate label text
27
+ expect(getByText(expectedText)).toBeTruthy();
28
+
29
+ if (!shouldShowOptional) {
30
+ expect(queryByText(`${label} (Optional)`)).toBeFalsy();
31
+ expect(queryByText('(Optional)')).toBeFalsy();
32
+ }
33
+ }
34
+ );
35
+ });
36
+
37
+ describe('label behavior based on focus and content state', () => {
38
+ it.each`
39
+ state | isEmptyValue | expectedBehavior | description
40
+ ${'focused'} | ${true} | ${'label in focused state'} | ${'user focuses empty input'}
41
+ ${'filled'} | ${false} | ${'label remains in floating position'} | ${'user enters text in input'}
42
+ `(
43
+ 'should show $expectedBehavior when $description',
44
+ ({ state, isEmptyValue }) => {
45
+ const { getByTestId } = renderWithTheme(
46
+ <FloatingLabel
47
+ label={state === 'focused' ? 'Password' : 'Message'}
48
+ variant="text"
49
+ state={state}
50
+ isFocused={state === 'focused'}
51
+ required
52
+ isEmptyValue={isEmptyValue}
53
+ />
54
+ );
55
+
56
+ // User should see the label behaving appropriately
57
+ const label = getByTestId('input-label');
58
+ expect(label).toBeTruthy();
59
+ const { children } = label.props;
60
+ const expectedText = state === 'focused' ? 'Password' : 'Message';
61
+ expect(
62
+ Array.isArray(children) ? children.filter(Boolean).join('') : children
63
+ ).toBe(expectedText);
64
+ }
65
+ );
66
+ });
67
+
68
+ describe('variant-specific positioning', () => {
69
+ it.each`
70
+ variant | required | expectedText | description
71
+ ${'textarea'} | ${false} | ${'Description (Optional)'} | ${'multiline input with optional label'}
72
+ `(
73
+ 'should position label appropriately for $variant ($description)',
74
+ ({ variant, required, expectedText }) => {
75
+ const { getByTestId } = renderWithTheme(
76
+ <FloatingLabel
77
+ label="Description"
78
+ variant={variant}
79
+ state="default"
80
+ isFocused={false}
81
+ required={required}
82
+ isEmptyValue
83
+ />
84
+ );
85
+
86
+ // User should see the label with proper variant positioning
87
+ const label = getByTestId('input-label');
88
+ expect(label).toBeTruthy();
89
+ const { children } = label.props;
90
+ expect(Array.isArray(children) ? children.join('') : children).toBe(
91
+ expectedText
92
+ );
93
+ }
94
+ );
95
+ });
96
+
97
+ describe('when user encounters different input states', () => {
98
+ it.each`
99
+ state | required | expectedText | description
100
+ ${'error'} | ${true} | ${'Email'} | ${'validation error with required field'}
101
+ ${'disabled'} | ${false} | ${'Disabled Field (Optional)'} | ${'non-interactive optional field'}
102
+ `(
103
+ 'should display appropriate styling for $state state ($description)',
104
+ ({ state, required, expectedText }) => {
105
+ const { getByTestId } = renderWithTheme(
106
+ <FloatingLabel
107
+ label={state === 'error' ? 'Email' : 'Disabled Field'}
108
+ variant="text"
109
+ state={state}
110
+ isFocused={false}
111
+ required={required}
112
+ isEmptyValue
113
+ />
114
+ );
115
+
116
+ // User should see the label with appropriate state styling
117
+ const label = getByTestId('input-label');
118
+ expect(label).toBeTruthy();
119
+ const { children } = label.props;
120
+ expect(
121
+ Array.isArray(children) ? children.filter(Boolean).join('') : children
122
+ ).toBe(expectedText);
123
+ }
124
+ );
125
+ });
126
+
127
+ describe('when used with accessibility features', () => {
128
+ it('should provide proper accessibility labeling', () => {
129
+ const accessibilityId = 'email-input-label';
130
+ const { getByTestId } = renderWithTheme(
131
+ <FloatingLabel
132
+ label="Email Address"
133
+ variant="text"
134
+ state="default"
135
+ isFocused={false}
136
+ required
137
+ accessibilityLabelledBy={accessibilityId}
138
+ isEmptyValue
139
+ />
140
+ );
141
+
142
+ // User should have proper accessibility support
143
+ const label = getByTestId('input-label');
144
+ expect(label).toHaveProp('nativeID', accessibilityId);
145
+ });
146
+ });
147
+
148
+ describe('label color styling based on state', () => {
149
+ it.each`
150
+ state | isFocused | expectedColor | description
151
+ ${'default'} | ${false} | ${'#808f91'} | ${'inactive/empty field'}
152
+ ${'default'} | ${true} | ${'#001f23'} | ${'user is typing'}
153
+ ${'filled'} | ${false} | ${'#001f23'} | ${'field has content'}
154
+ ${'filled'} | ${true} | ${'#001f23'} | ${'field has content and focused'}
155
+ ${'error'} | ${false} | ${'#cb300a'} | ${'validation error'}
156
+ ${'error'} | ${true} | ${'#001f23'} | ${'validation error but focused'}
157
+ ${'disabled'} | ${false} | ${'#bfc1c5'} | ${'non-interactive field'}
158
+ ${'readonly'} | ${false} | ${'#808f91'} | ${'read-only field'}
159
+ `(
160
+ 'should apply $expectedColor color for $state state when focused=$isFocused ($description)',
161
+ ({ state, isFocused, expectedColor: _expectedColor }) => {
162
+ const { getByTestId } = renderWithTheme(
163
+ <FloatingLabel
164
+ label={`${state} Label`}
165
+ variant="text"
166
+ state={state}
167
+ isFocused={isFocused}
168
+ required
169
+ isEmptyValue={state !== 'filled'}
170
+ />
171
+ );
172
+
173
+ const label = getByTestId('input-label');
174
+ expect(label).toHaveProp('themeState', state);
175
+ }
176
+ );
177
+
178
+ describe('component behavior', () => {
179
+ it('should render correctly with all props', () => {
180
+ const { getByTestId } = renderWithTheme(
181
+ <FloatingLabel
182
+ label="Full Name"
183
+ variant="text"
184
+ state="filled"
185
+ isFocused
186
+ required={false}
187
+ accessibilityLabelledBy="fullname-label"
188
+ isEmptyValue={false}
189
+ />
190
+ );
191
+
192
+ // User should see a fully rendered floating label
193
+ const label = getByTestId('input-label');
194
+ expect(label).toBeTruthy();
195
+ expect(label).toHaveProp('nativeID', 'fullname-label');
196
+ const { children } = label.props;
197
+ expect(Array.isArray(children) ? children.join('') : children).toBe(
198
+ 'Full Name (Optional)'
199
+ );
200
+ });
201
+ });
202
+ });
203
+ });
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import { TextInput as RNTextInput } from 'react-native';
3
+ import renderWithTheme from '../../../../testUtils/renderWithTheme';
4
+ import InputComponent from '../InputComponent';
5
+
6
+ describe('InputComponent', () => {
7
+ it('renders correctly with renderInputValue', () => {
8
+ const ref = React.createRef<RNTextInput>();
9
+ const wrapper = renderWithTheme(
10
+ <InputComponent
11
+ variant="textarea"
12
+ nativeInputProps={{}}
13
+ renderInputValue={(props) => (
14
+ <RNTextInput
15
+ {...props}
16
+ value="customised text"
17
+ testID="custom-text-input"
18
+ />
19
+ )}
20
+ ref={ref}
21
+ />
22
+ );
23
+ expect(wrapper.queryAllByTestId('custom-text-input')).toHaveLength(1);
24
+ expect(wrapper.queryAllByDisplayValue('customised text')).toHaveLength(1);
25
+ });
26
+
27
+ it('renders correctly without renderInputValue', () => {
28
+ const ref = React.createRef<RNTextInput>();
29
+ const wrapper = renderWithTheme(
30
+ <InputComponent
31
+ variant="textarea"
32
+ nativeInputProps={{ testID: 'text-input', value: 'text input value' }}
33
+ ref={ref}
34
+ />
35
+ );
36
+ expect(wrapper.queryAllByTestId('text-input')).toHaveLength(1);
37
+ expect(wrapper.queryAllByDisplayValue('text input value')).toHaveLength(1);
38
+ });
39
+ });
@@ -0,0 +1,275 @@
1
+ import React from 'react';
2
+ import { Text, TextInput as RNTextInput } from 'react-native';
3
+ import type { TextInputProps as NativeTextInputProps } from 'react-native';
4
+ // import { TextInput as RNTextInput } from 'react-native';
5
+ import renderWithTheme from '../../../../testUtils/renderWithTheme';
6
+ import InputRow from '../InputRow';
7
+
8
+ // Mock the LABEL_ANIMATION_DURATION constant
9
+ jest.mock('../constants', () => ({
10
+ LABEL_ANIMATION_DURATION: 0, // Instant animation for testing
11
+ }));
12
+
13
+ describe('InputRow', () => {
14
+ const defaultProps = {
15
+ state: 'default' as const,
16
+ isFocused: false,
17
+ variant: 'text' as const,
18
+ nativeInputProps: {
19
+ value: '',
20
+ placeholder: 'Enter text',
21
+ },
22
+ isEmptyValue: true,
23
+ };
24
+
25
+ beforeEach(() => {
26
+ jest.clearAllMocks();
27
+ });
28
+
29
+ describe('when user sees an empty input field', () => {
30
+ it('should hide both prefix and input components with opacity', () => {
31
+ const ref = React.createRef<RNTextInput>();
32
+ const { getByTestId } = renderWithTheme(
33
+ <InputRow {...defaultProps} prefix="search" ref={ref} />
34
+ );
35
+
36
+ // Components should be present but hidden
37
+ const inputWrapper = getByTestId('input-row-input-wrapper');
38
+ expect(inputWrapper).toBeTruthy();
39
+ expect(inputWrapper).toHaveProp('accessibilityElementsHidden', true);
40
+ });
41
+ });
42
+
43
+ describe('when user focuses the input', () => {
44
+ it('should show both prefix and input components with animation', () => {
45
+ const ref = React.createRef<RNTextInput>();
46
+ const { getByTestId } = renderWithTheme(
47
+ <InputRow {...defaultProps} isFocused isEmptyValue ref={ref} />
48
+ );
49
+
50
+ // Should be visible when focused
51
+ const inputWrapper = getByTestId('input-row-input-wrapper');
52
+ expect(inputWrapper).toHaveProp('accessibilityElementsHidden', false);
53
+ });
54
+ });
55
+
56
+ describe('when user enters text in the input', () => {
57
+ it('should keep components visible even when not focused', () => {
58
+ const ref = React.createRef<RNTextInput>();
59
+ const { getByTestId } = renderWithTheme(
60
+ <InputRow
61
+ {...defaultProps}
62
+ prefix="search"
63
+ state="filled"
64
+ isEmptyValue={false}
65
+ nativeInputProps={{
66
+ ...defaultProps.nativeInputProps,
67
+ value: 'user@example.com',
68
+ }}
69
+ ref={ref}
70
+ />
71
+ );
72
+
73
+ // User has entered text - components should be visible
74
+ const inputWrapper = getByTestId('input-row-input-wrapper');
75
+ expect(inputWrapper).toHaveProp('accessibilityElementsHidden', false);
76
+ });
77
+ });
78
+
79
+ describe('when user uses input with prefix icon', () => {
80
+ it('should render input wrapper when prefix is provided', () => {
81
+ const ref = React.createRef<RNTextInput>();
82
+ const { getByTestId } = renderWithTheme(
83
+ <InputRow
84
+ {...defaultProps}
85
+ prefix="search"
86
+ isFocused
87
+ isEmptyValue={false}
88
+ ref={ref}
89
+ />
90
+ );
91
+
92
+ // User should see the input wrapper with prefix
93
+ const inputWrapper = getByTestId('input-row-input-wrapper');
94
+ expect(inputWrapper).toBeTruthy();
95
+ expect(inputWrapper).toHaveProp('accessibilityElementsHidden', false);
96
+ });
97
+ });
98
+
99
+ describe('when user uses input with custom prefix', () => {
100
+ it('should render custom prefix element', () => {
101
+ const CustomPrefix = () => <Text testID="custom-prefix">Custom</Text>;
102
+ const ref = React.createRef<RNTextInput>();
103
+
104
+ const { getByTestId } = renderWithTheme(
105
+ <InputRow
106
+ {...defaultProps}
107
+ prefix={<CustomPrefix />}
108
+ isFocused
109
+ isEmptyValue={false}
110
+ ref={ref}
111
+ />
112
+ );
113
+
114
+ // User should see the custom prefix
115
+ expect(getByTestId('custom-prefix')).toBeTruthy();
116
+ });
117
+ });
118
+
119
+ describe('when user uses textarea variant', () => {
120
+ it('should render input component with textarea variant', () => {
121
+ const ref = React.createRef<RNTextInput>();
122
+ const { getByTestId } = renderWithTheme(
123
+ <InputRow
124
+ {...defaultProps}
125
+ variant="textarea"
126
+ isFocused
127
+ isEmptyValue={false}
128
+ nativeInputProps={{
129
+ ...defaultProps.nativeInputProps,
130
+ multiline: true,
131
+ numberOfLines: 4,
132
+ }}
133
+ ref={ref}
134
+ />
135
+ );
136
+
137
+ // User should see the textarea input
138
+ const inputWrapper = getByTestId('input-row-input-wrapper');
139
+ expect(inputWrapper).toBeTruthy();
140
+ expect(inputWrapper).toHaveProp('accessibilityLabel', 'Text input field');
141
+ });
142
+ });
143
+
144
+ describe('when user encounters different input states', () => {
145
+ it('should render input wrapper in error state', () => {
146
+ const ref = React.createRef<RNTextInput>();
147
+ const { getByTestId } = renderWithTheme(
148
+ <InputRow
149
+ {...defaultProps}
150
+ state="error"
151
+ isEmptyValue={false}
152
+ ref={ref}
153
+ />
154
+ );
155
+
156
+ // Components should render with error state
157
+ const inputWrapper = getByTestId('input-row-input-wrapper');
158
+ expect(inputWrapper).toBeTruthy();
159
+ });
160
+
161
+ it('should handle disabled state appropriately', () => {
162
+ const ref = React.createRef<RNTextInput>();
163
+ const { getByTestId } = renderWithTheme(
164
+ <InputRow {...defaultProps} state="disabled" isEmptyValue ref={ref} />
165
+ );
166
+
167
+ // Even disabled inputs should render components
168
+ const inputWrapper = getByTestId('input-row-input-wrapper');
169
+ expect(inputWrapper).toBeTruthy();
170
+ });
171
+ });
172
+
173
+ describe('when user uses custom input renderer', () => {
174
+ it('should use custom render function for input value', () => {
175
+ const customRenderer = (inputProps: NativeTextInputProps) => (
176
+ <Text testID="custom-input-renderer">Custom: {inputProps.value}</Text>
177
+ );
178
+ const ref = React.createRef<RNTextInput>();
179
+
180
+ const { getByTestId } = renderWithTheme(
181
+ <InputRow
182
+ {...defaultProps}
183
+ renderInputValue={customRenderer}
184
+ isFocused
185
+ isEmptyValue={false}
186
+ nativeInputProps={{
187
+ ...defaultProps.nativeInputProps,
188
+ value: 'test value',
189
+ }}
190
+ ref={ref}
191
+ />
192
+ );
193
+
194
+ // User should see the custom rendered input
195
+ expect(getByTestId('custom-input-renderer')).toBeTruthy();
196
+ });
197
+ });
198
+
199
+ describe('input reference handling', () => {
200
+ it('should properly handle input ref', () => {
201
+ const ref = React.createRef<RNTextInput>();
202
+ renderWithTheme(
203
+ <InputRow {...defaultProps} isFocused isEmptyValue={false} ref={ref} />
204
+ );
205
+ expect(ref.current).toBeDefined();
206
+ });
207
+ });
208
+
209
+ describe('accessibility features', () => {
210
+ it('should provide proper accessibility labels for input wrapper', () => {
211
+ const ref = React.createRef<RNTextInput>();
212
+ const { getByTestId } = renderWithTheme(
213
+ <InputRow {...defaultProps} isFocused isEmptyValue={false} ref={ref} />
214
+ );
215
+
216
+ // User should have proper accessibility support
217
+ const inputWrapper = getByTestId('input-row-input-wrapper');
218
+ expect(inputWrapper).toHaveProp('accessibilityLabel', 'Text input field');
219
+ });
220
+
221
+ it('should hide components from screen readers when not visible', () => {
222
+ const ref = React.createRef<RNTextInput>();
223
+ const { getByTestId } = renderWithTheme(
224
+ <InputRow
225
+ {...defaultProps}
226
+ prefix="search"
227
+ state="default"
228
+ isEmptyValue
229
+ ref={ref}
230
+ />
231
+ );
232
+
233
+ // Components should be hidden from screen readers when not visible
234
+ const inputWrapper = getByTestId('input-row-input-wrapper');
235
+ expect(inputWrapper).toHaveProp('accessibilityElementsHidden', true);
236
+ });
237
+ });
238
+
239
+ describe('component behavior', () => {
240
+ it('should render correctly with all props', () => {
241
+ const ref = React.createRef<RNTextInput>();
242
+ const { getByTestId } = renderWithTheme(
243
+ <InputRow
244
+ {...defaultProps}
245
+ prefix="search"
246
+ isFocused
247
+ isEmptyValue={false}
248
+ nativeInputProps={{
249
+ ...defaultProps.nativeInputProps,
250
+ value: 'test@example.com',
251
+ placeholder: 'Enter email',
252
+ }}
253
+ ref={ref}
254
+ />
255
+ );
256
+
257
+ // User should see a fully rendered input row
258
+ const inputWrapper = getByTestId('input-row-input-wrapper');
259
+ expect(inputWrapper).toBeTruthy();
260
+ expect(inputWrapper).toHaveProp('accessibilityElementsHidden', false);
261
+ });
262
+
263
+ it('should render without prefix', () => {
264
+ const ref = React.createRef<RNTextInput>();
265
+ const { getByTestId, queryByText } = renderWithTheme(
266
+ <InputRow {...defaultProps} ref={ref} />
267
+ );
268
+
269
+ // User should see input without prefix
270
+ const inputWrapper = getByTestId('input-row-input-wrapper');
271
+ expect(inputWrapper).toBeTruthy();
272
+ expect(queryByText('search')).toBeNull();
273
+ });
274
+ });
275
+ });
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import renderWithTheme from '../../../../testUtils/renderWithTheme';
3
+ import MaxLengthMessage from '../MaxLengthMessage';
4
+
5
+ describe('MaxLengthMessage', () => {
6
+ it('renders correctly with maxLength', () => {
7
+ const { queryAllByText } = renderWithTheme(
8
+ <MaxLengthMessage
9
+ maxLength={10}
10
+ state="default"
11
+ currentLength={5}
12
+ hideCharacterCount={false}
13
+ />
14
+ );
15
+ expect(queryAllByText('5/10')).toHaveLength(1);
16
+ });
17
+ });
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import renderWithTheme from '../../../../testUtils/renderWithTheme';
3
+ import PrefixComponent from '../PrefixComponent';
4
+
5
+ describe('PrefixComponent', () => {
6
+ it('renders prefix icon', () => {
7
+ const wrapper = renderWithTheme(
8
+ <PrefixComponent prefix="dollar-sign" state="default" />
9
+ );
10
+ expect(wrapper.getByA11yLabel('Prefix icon: dollar-sign')).toBeDefined();
11
+ // Optionally, keep testID fallback
12
+ expect(wrapper.getByTestId('input-prefix')).toBeDefined();
13
+ });
14
+ });
@@ -0,0 +1,114 @@
1
+ import React from 'react';
2
+ import renderWithTheme from '../../../../testUtils/renderWithTheme';
3
+ import {
4
+ StyledHelperText,
5
+ StyledTextInput,
6
+ StyledCharacterCount,
7
+ StyledError,
8
+ StyledErrorRow,
9
+ StyledLabel,
10
+ StyledBorder,
11
+ } from '../StyledTextInput';
12
+
13
+ describe('StyledLabel', () => {
14
+ it.each`
15
+ themeState
16
+ ${'default'}
17
+ ${'filled'}
18
+ ${'error'}
19
+ ${'disabled'}
20
+ ${'readonly'}
21
+ `('renders correctly with themeState $themeState', ({ themeState }): void => {
22
+ const { toJSON } = renderWithTheme(
23
+ <StyledLabel themeState={themeState}>Label</StyledLabel>
24
+ );
25
+
26
+ expect(toJSON()).toMatchSnapshot();
27
+ });
28
+ });
29
+
30
+ describe('StyledErrorRow', () => {
31
+ it('renders correctly', (): void => {
32
+ const { toJSON } = renderWithTheme(<StyledErrorRow />);
33
+
34
+ expect(toJSON()).toMatchSnapshot();
35
+ });
36
+ });
37
+
38
+ describe('StyledError', () => {
39
+ it('renders correctly', (): void => {
40
+ const { toJSON } = renderWithTheme(
41
+ <StyledError>must not exceed character limit</StyledError>
42
+ );
43
+
44
+ expect(toJSON()).toMatchSnapshot();
45
+ });
46
+ });
47
+
48
+ describe('StyledCharacterCount', () => {
49
+ it.each`
50
+ themeState
51
+ ${'default'}
52
+ ${'filled'}
53
+ ${'error'}
54
+ ${'disabled'}
55
+ ${'readonly'}
56
+ `('renders correctly with themeState $themeState', ({ themeState }): void => {
57
+ const { toJSON } = renderWithTheme(
58
+ <StyledCharacterCount themeState={themeState}>
59
+ 100/255
60
+ </StyledCharacterCount>
61
+ );
62
+
63
+ expect(toJSON()).toMatchSnapshot();
64
+ });
65
+ });
66
+
67
+ describe('StyledHelperText', () => {
68
+ it('renders correctly', (): void => {
69
+ const { toJSON } = renderWithTheme(
70
+ <StyledHelperText>helper text</StyledHelperText>
71
+ );
72
+
73
+ expect(toJSON()).toMatchSnapshot();
74
+ });
75
+ });
76
+
77
+ describe('StyledBorder', () => {
78
+ it.each`
79
+ themeState
80
+ ${'default'}
81
+ ${'filled'}
82
+ ${'error'}
83
+ ${'disabled'}
84
+ ${'readonly'}
85
+ `('renders correctly with themeState $themeState', ({ themeState }): void => {
86
+ const { toJSON } = renderWithTheme(
87
+ <StyledBorder themeState={themeState} themeFocused={false} />
88
+ );
89
+
90
+ expect(toJSON()).toMatchSnapshot();
91
+ });
92
+
93
+ it('renders correctly when focused', (): void => {
94
+ const { toJSON } = renderWithTheme(
95
+ <StyledBorder themeState="error" themeFocused />
96
+ );
97
+
98
+ expect(toJSON()).toMatchSnapshot();
99
+ });
100
+ });
101
+
102
+ describe('StyledTextInput', () => {
103
+ it.each`
104
+ themeVariant
105
+ ${'text'}
106
+ ${'textarea'}
107
+ `('renders correctly with $themeState state', ({ themeVariant }) => {
108
+ const { toJSON } = renderWithTheme(
109
+ <StyledTextInput themeVariant={themeVariant} />
110
+ );
111
+
112
+ expect(toJSON()).toMatchSnapshot();
113
+ });
114
+ });
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import renderWithTheme from '../../../../testUtils/renderWithTheme';
3
+ import SuffixComponent from '../SuffixComponent';
4
+
5
+ describe('SuffixComponent', () => {
6
+ it('renders loading icon with loading', () => {
7
+ const wrapper = renderWithTheme(
8
+ <SuffixComponent loading suffix="dollar-sign" state="default" />
9
+ );
10
+
11
+ expect(wrapper.getByA11yLabel('Suffix icon: loading')).toBeDefined();
12
+ });
13
+
14
+ it('renders suffix icon', () => {
15
+ const wrapper = renderWithTheme(
16
+ <SuffixComponent loading={false} suffix="dollar-sign" state="default" />
17
+ );
18
+ expect(wrapper.getByA11yLabel('Suffix icon: dollar-sign')).toBeDefined();
19
+ });
20
+ });