@axinom/mosaic-ui 0.55.0-rc.1 → 0.55.0-rc.11

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 (34) hide show
  1. package/dist/components/DynamicDataList/helpers/useColumnDefs.d.ts +1 -1
  2. package/dist/components/DynamicDataList/helpers/useColumnDefs.d.ts.map +1 -1
  3. package/dist/components/FormElements/Select/Select.d.ts +15 -11
  4. package/dist/components/FormElements/Select/Select.d.ts.map +1 -1
  5. package/dist/components/FormElements/Select/SelectField.d.ts.map +1 -1
  6. package/dist/components/FormElements/SingleLineText/SingleLineText.d.ts.map +1 -1
  7. package/dist/components/FormElements/Tags/Tags.d.ts +2 -2
  8. package/dist/components/FormElements/Tags/Tags.d.ts.map +1 -1
  9. package/dist/components/FormElements/Tags/TagsField.d.ts +1 -1
  10. package/dist/components/FormElements/Tags/TagsField.d.ts.map +1 -1
  11. package/dist/index.es.js +4 -4
  12. package/dist/index.es.js.map +1 -1
  13. package/dist/index.js +4 -4
  14. package/dist/index.js.map +1 -1
  15. package/package.json +4 -3
  16. package/src/components/DynamicDataList/DynamicDataList.spec.tsx +1 -5
  17. package/src/components/DynamicDataList/DynamicDataList.tsx +1 -1
  18. package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createSelectRenderer/createSelectRenderer.spec.tsx +9 -4
  19. package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createSelectRenderer/createSelectRenderer.tsx +2 -2
  20. package/src/components/DynamicDataList/helpers/useColumnDefs.ts +4 -2
  21. package/src/components/FormElements/FileUploadControl/FileUploadControl.scss +2 -3
  22. package/src/components/FormElements/FileUploadControl/FileUploadControl.stories.tsx +0 -1
  23. package/src/components/FormElements/FileUploadControl/FileUploadControl.tsx +2 -2
  24. package/src/components/FormElements/Select/Select.scss +108 -59
  25. package/src/components/FormElements/Select/Select.spec.tsx +52 -43
  26. package/src/components/FormElements/Select/Select.stories.tsx +8 -10
  27. package/src/components/FormElements/Select/Select.tsx +138 -52
  28. package/src/components/FormElements/Select/SelectField.tsx +1 -0
  29. package/src/components/FormElements/SingleLineText/SingleLineText.tsx +23 -7
  30. package/src/components/FormElements/Tags/Tags.scss +16 -76
  31. package/src/components/FormElements/Tags/Tags.spec.tsx +69 -80
  32. package/src/components/FormElements/Tags/Tags.tsx +54 -62
  33. package/src/components/FormElements/Tags/TagsField.tsx +3 -13
  34. package/src/styles/variables.scss +8 -0
@@ -1,73 +1,159 @@
1
+ import { Popper, useAutocomplete, UseAutocompleteProps } from '@mui/base';
1
2
  import clsx from 'clsx';
2
- import React from 'react';
3
- import { BaseFormControl, BaseSelectEvents } from '../Form.models';
3
+ import React, { ChangeEvent } from 'react';
4
+ import { Button, ButtonContext } from '../../Buttons';
5
+ import { IconName } from '../../Icons';
6
+ import { BaseFormControl, BaseInputEvents } from '../Form.models';
4
7
  import { FormElementContainer } from '../FormElementContainer';
5
8
  import classes from './Select.scss';
6
9
 
7
- export interface SelectProps extends BaseFormControl, BaseSelectEvents {
8
- /** Current value the form control has */
9
- value?: string | number | string[] | undefined;
10
- /** Array of options that can be selected from */
11
- options?: { value: string | number; label: string | number }[];
10
+ export interface SelectOption {
11
+ value: string | number | string[];
12
+ label: string | number;
13
+ }
14
+
15
+ type TrimmedUseAutocompleteProps = Omit<
16
+ UseAutocompleteProps<SelectOption, false, true, false>,
17
+ 'value' | 'onChange'
18
+ >;
19
+ export interface SelectProps
20
+ extends BaseFormControl,
21
+ BaseInputEvents,
22
+ TrimmedUseAutocompleteProps {
23
+ /** An array of options */
24
+ options: SelectOption[];
12
25
  /** Whether or not the control should start focused (default: false) */
13
26
  autoFocus?: boolean;
14
- /** Defines whether an empty option should be added as the first option (default: false) */
15
- addEmptyOption?: boolean;
27
+ /** Current value the form control has */
28
+ value?: string | string[] | number;
16
29
  /** Select placeholder */
17
30
  placeholder?: string;
31
+ /** Allows to clear the input field and leave empty */
32
+ addEmptyOption?: boolean;
18
33
  }
19
34
 
20
- export const Select: React.FC<SelectProps> = ({
21
- name,
22
- id,
23
- value = undefined,
24
- options = [],
25
- disabled = false,
26
- error,
27
- autoFocus = false,
28
- addEmptyOption = false,
29
- placeholder,
30
- onChange,
31
- onBlur,
32
- onFocus,
33
- className = '',
34
- ...rest
35
- }) => {
36
- const errorMsg: string | undefined = error;
35
+ export const Select: React.FC<SelectProps> = (props) => {
36
+ const {
37
+ name,
38
+ error,
39
+ disabled,
40
+ id,
41
+ label,
42
+ className,
43
+ tooltipContent,
44
+ inlineMode,
45
+ autoFocus,
46
+ value,
47
+ onBlur,
48
+ onFocus,
49
+ onChange,
50
+ placeholder,
51
+ addEmptyOption,
52
+ ...autoCompleteProps
53
+ } = props;
54
+ const {
55
+ getRootProps,
56
+ getInputProps,
57
+ getListboxProps,
58
+ getOptionProps,
59
+ getPopupIndicatorProps,
60
+ groupedOptions,
61
+ popupOpen,
62
+ setAnchorEl,
63
+ anchorEl,
64
+ } = useAutocomplete({
65
+ id,
66
+ disabled,
67
+ value:
68
+ autoCompleteProps.options.find((option) => option.value === value) ??
69
+ null,
70
+ onChange: ({ target: _, ...event }, value) => {
71
+ onChange?.({
72
+ ...event,
73
+ currentTarget: {
74
+ ...event.currentTarget,
75
+ id,
76
+ name,
77
+ value: value?.value ?? '',
78
+ },
79
+ } as ChangeEvent<HTMLInputElement>);
80
+ },
81
+ disableClearable: !addEmptyOption,
82
+ ...autoCompleteProps,
83
+ });
37
84
 
38
85
  return (
39
86
  <FormElementContainer
40
- {...rest}
87
+ id={id}
88
+ label={label}
89
+ tooltipContent={tooltipContent}
90
+ inlineMode={inlineMode}
41
91
  className={clsx(classes.container, 'select-container', className)}
42
- error={errorMsg}
92
+ error={error}
43
93
  dataTestFieldType="Select"
44
94
  >
45
- <select
46
- className={clsx({ [classes.hasError]: errorMsg !== undefined })}
47
- id={id}
48
- name={name}
49
- value={value}
50
- disabled={disabled}
51
- autoFocus={autoFocus}
52
- onChange={onChange}
53
- onBlur={onBlur}
54
- onFocus={onFocus}
95
+ <div
96
+ ref={setAnchorEl}
97
+ {...getRootProps()}
98
+ className={clsx(classes.inputWrapper)}
55
99
  >
56
- {addEmptyOption &&
57
- (placeholder === null || placeholder === undefined) && (
58
- <option value=""></option>
100
+ <input
101
+ {...getInputProps()}
102
+ name={name}
103
+ className={clsx({ [classes.hasError]: Boolean(error) })}
104
+ autoFocus={autoFocus}
105
+ onBlur={(event) => {
106
+ getInputProps().onBlur?.(event);
107
+ onBlur?.(event);
108
+ }}
109
+ onFocus={(event) => {
110
+ getInputProps().onFocus?.(event);
111
+ onFocus?.(event);
112
+ }}
113
+ placeholder={placeholder}
114
+ />
115
+ <Button
116
+ className={clsx(classes.button)}
117
+ buttonContext={ButtonContext.None}
118
+ icon={popupOpen ? IconName.ChevronUp : IconName.ChevronDown}
119
+ onButtonClicked={getPopupIndicatorProps().onClick}
120
+ onBlur={getPopupIndicatorProps().onBlur}
121
+ disabled={disabled}
122
+ />
123
+ </div>
124
+ <Popper
125
+ open={popupOpen}
126
+ anchorEl={anchorEl}
127
+ style={{
128
+ width: anchorEl ? anchorEl.clientWidth : undefined,
129
+ zIndex: 999,
130
+ }}
131
+ >
132
+ <PopperContent>
133
+ {groupedOptions.length > 0 && (
134
+ <ul {...getListboxProps()}>
135
+ {(groupedOptions as typeof autoCompleteProps.options).map(
136
+ (option, index) => (
137
+ <li
138
+ key={String(option.value)}
139
+ {...getOptionProps({ option, index })}
140
+ >
141
+ {option.label}
142
+ </li>
143
+ ),
144
+ )}
145
+ </ul>
59
146
  )}
60
- {placeholder && (
61
- <option value="" disabled>
62
- {disabled ? '' : placeholder}
63
- </option>
64
- )}
65
- {options.map((option) => (
66
- <option key={option.value} value={option.value}>
67
- {option.label}
68
- </option>
69
- ))}
70
- </select>
147
+ </PopperContent>
148
+ </Popper>
71
149
  </FormElementContainer>
72
150
  );
73
151
  };
152
+
153
+ const PopperContent: React.FC = ({ children }) => {
154
+ return (
155
+ <div className={clsx(classes.popperContent, 'select-popper-content')}>
156
+ {children}
157
+ </div>
158
+ );
159
+ };
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { useFormikError } from '../useFormikError';
3
3
  import { Select, SelectProps } from './Select';
4
+
4
5
  export const SelectField: React.FC<Omit<SelectProps, 'error'>> = (props) => {
5
6
  const error = useFormikError(props.name);
6
7
  return <Select {...props} error={error} />;
@@ -1,5 +1,10 @@
1
1
  import clsx from 'clsx';
2
- import React, { ChangeEvent, InputHTMLAttributes, useEffect } from 'react';
2
+ import React, {
3
+ ChangeEvent,
4
+ InputHTMLAttributes,
5
+ useEffect,
6
+ useRef,
7
+ } from 'react';
3
8
  import { executeIfRefAvailable } from '../../../helpers/utils';
4
9
  import { BaseFormControl, BaseInputEvents } from '../Form.models';
5
10
  import { FormElementContainer } from '../FormElementContainer';
@@ -50,7 +55,7 @@ export const SingleLineText: React.FC<SingleLineTextProps> = ({
50
55
  error,
51
56
  autoFocus = false,
52
57
  autoComplete,
53
- innerRef = React.createRef(),
58
+ innerRef: refFromParent,
54
59
  defaultValue,
55
60
  onChange,
56
61
  onBlur,
@@ -59,9 +64,13 @@ export const SingleLineText: React.FC<SingleLineTextProps> = ({
59
64
  inputProps,
60
65
  ...rest
61
66
  }) => {
67
+ // Create a local ref if no ref is passed from the parent
68
+ const localRef = useRef<HTMLInputElement>(null);
69
+ const innerRef = refFromParent || localRef;
70
+
62
71
  const errorMsg: string | undefined = error;
63
72
  const DUMMY_PWD = '0000000000';
64
- const isPasswordField = type === 'password' ? true : false;
73
+ const isPasswordField = type === 'password';
65
74
 
66
75
  useEffect(() => {
67
76
  if (innerRef.current) {
@@ -70,15 +79,22 @@ export const SingleLineText: React.FC<SingleLineTextProps> = ({
70
79
  }, [innerRef, value]);
71
80
 
72
81
  useEffect(() => {
73
- if (isPasswordField && isSet) {
82
+ // Only set the dummy password if the field is a password field and the value is not set
83
+ // and the field is not focused
84
+ if (
85
+ isPasswordField &&
86
+ isSet &&
87
+ !value &&
88
+ document.activeElement !== innerRef.current
89
+ ) {
74
90
  executeIfRefAvailable(innerRef, (input) => {
75
91
  input.value = DUMMY_PWD;
76
92
  });
77
93
  }
78
- }, [innerRef, isPasswordField, isSet]);
94
+ }, [innerRef, isPasswordField, isSet, value]);
79
95
 
80
96
  const onFocusWrapper = (e: ChangeEvent<HTMLInputElement>): void => {
81
- if (type === 'password' && isSet && !value) {
97
+ if (isPasswordField && isSet && !value) {
82
98
  executeIfRefAvailable(innerRef, (input) => {
83
99
  input.value = '';
84
100
  });
@@ -86,7 +102,7 @@ export const SingleLineText: React.FC<SingleLineTextProps> = ({
86
102
  onFocus?.(e);
87
103
  };
88
104
  const onBlurWrapper = (e: ChangeEvent<HTMLInputElement>): void => {
89
- if (type === 'password' && isSet && !value) {
105
+ if (isPasswordField && isSet && !value) {
90
106
  executeIfRefAvailable(innerRef, (input) => {
91
107
  input.value = DUMMY_PWD;
92
108
  });
@@ -10,6 +10,22 @@
10
10
  flex-flow: wrap;
11
11
  gap: 10px;
12
12
 
13
+ .hasError {
14
+ input {
15
+ border: 1px solid
16
+ var(--input-invalid-border-color, $input-invalid-border-color);
17
+
18
+ &:hover {
19
+ border-color: var(
20
+ --input-invalid-border-color,
21
+ $input-invalid-border-color
22
+ );
23
+ box-shadow: 0 0 0 2px
24
+ var(--input-invalid-hover-color, $input-invalid-hover-color);
25
+ }
26
+ }
27
+ }
28
+
13
29
  .selectedItem {
14
30
  width: max-content;
15
31
  display: grid;
@@ -38,82 +54,6 @@
38
54
  display: block;
39
55
  grid-template-columns: none;
40
56
  }
41
-
42
- select {
43
- -moz-appearance: none;
44
- -webkit-appearance: none;
45
- appearance: none;
46
-
47
- color: var(--input-color, $input-color);
48
- border: 1px solid var(--input-border-color, $input-border-color);
49
-
50
- font-size: var(--label-font-size, $label-font-size);
51
-
52
- height: 50px;
53
- max-width: $tags-max-width;
54
-
55
- padding: 0 40px 0 12px;
56
-
57
- // CSS variables will not work inside the background-image url - we still pass it in there for consistency reasons.
58
- background-image: svg-arrow-glyph(
59
- var(--select-arrow-color, encodecolor($select-arrow-color))
60
- );
61
- background-repeat: no-repeat;
62
- background-position-y: center;
63
- background-position-x: 100%;
64
-
65
- background-color: var(
66
- --select-background-color,
67
- $select-background-color
68
- );
69
-
70
- cursor: pointer;
71
- outline: none;
72
-
73
- transition: box-shadow 0.15s ease-in-out 0s;
74
-
75
- &.hasError {
76
- border: 1px solid
77
- var(--input-invalid-border-color, $input-invalid-border-color);
78
- }
79
-
80
- &:disabled {
81
- border-color: var(
82
- --input-disabled-border-color,
83
- $input-disabled-border-color
84
- );
85
-
86
- cursor: default;
87
-
88
- background-image: svg-arrow-glyph(
89
- var(--select-arrow-color, encodecolor($select-disabled-arrow-color))
90
- );
91
- background-color: var(
92
- --input-disabled-background-color,
93
- $input-disabled-background-color
94
- );
95
- }
96
- }
97
-
98
- select,
99
- option {
100
- width: 325px;
101
- overflow: hidden;
102
- white-space: nowrap;
103
- text-overflow: ellipsis;
104
- }
105
-
106
- select:hover:enabled {
107
- border: 1px solid var(--input-hover-color, $input-hover-color);
108
- box-shadow: 0 0 0 2px var(--input-hover-color, $input-hover-color);
109
-
110
- &.hasError {
111
- border: 1px solid
112
- var(--input-invalid-border-color, $input-invalid-border-color);
113
- box-shadow: 0 0 0 2px
114
- var(--input-invalid-hover-color, $input-invalid-hover-color);
115
- }
116
- }
117
57
  }
118
58
  }
119
59
 
@@ -1,9 +1,16 @@
1
- import { mount, shallow } from 'enzyme';
1
+ import { mount, ReactWrapper, shallow } from 'enzyme';
2
2
  import React from 'react';
3
- import { act } from 'react-dom/test-utils';
4
3
  import { Button } from '../../Buttons';
4
+ import { Select } from '../Select/Select';
5
5
  import { Tags } from './Tags';
6
6
 
7
+ function selectFirstOption(wrapper: ReactWrapper) {
8
+ const input = wrapper.find('[role="combobox"]');
9
+ input.simulate('mousedown');
10
+ const firstOption = document.querySelector('[role="option"]');
11
+ firstOption?.dispatchEvent(new Event('click', { bubbles: true }));
12
+ }
13
+
7
14
  describe('Tags', () => {
8
15
  it('renders the component without crashing', () => {
9
16
  const wrapper = shallow(<Tags name={'test-name'} />);
@@ -41,61 +48,54 @@ describe('Tags', () => {
41
48
  });
42
49
  });
43
50
 
44
- it('raises onChange when selecting a tag along with the new value', async () => {
45
- const spy = jest.fn();
51
+ it('raises onChange when selecting a tag along with the new value', () => {
52
+ const changeSpy = jest.fn();
46
53
  const mockValue: string[] = ['1'];
47
- const mockValueUpdated = '2';
48
54
  const wrapper = mount(
49
- <Tags name={'test-name'} onChange={spy} value={mockValue} />,
55
+ <Tags
56
+ name={'test-name'}
57
+ onChange={changeSpy}
58
+ value={mockValue}
59
+ tagsOptions={['1', '2']}
60
+ />,
50
61
  );
51
62
 
52
- const select = wrapper.find('select');
53
-
54
- await act(async () => {
55
- await select.simulate('change', {
56
- currentTarget: { value: mockValueUpdated },
57
- persist: jest.fn(),
58
- });
59
- wrapper.update();
60
- });
63
+ selectFirstOption(wrapper);
61
64
 
62
- expect(spy).toHaveBeenCalledTimes(1);
63
- // Test is only failing due to a bug with jasmine: https://github.com/jasmine/jasmine/issues/652
64
- // Objects do match, commenting it out for now.
65
- // expect(spy).toHaveBeenCalledWith({
66
- // currentTarget: { value: [...mockValue, mockValueUpdated] },
67
- // persist: jest.fn(),
68
- // });
65
+ expect(changeSpy).toHaveBeenCalledTimes(1);
66
+ expect(changeSpy).toHaveBeenCalledWith(
67
+ expect.objectContaining({
68
+ currentTarget: expect.objectContaining({ value: ['1', '2'] }),
69
+ }),
70
+ );
69
71
  });
70
72
 
71
- it('raises onChange when removing a tag along with the new value', async () => {
72
- const spy = jest.fn();
73
+ it('raises onChange when removing a tag along with the new value', () => {
74
+ const changeSpy = jest.fn();
73
75
  const mockValue: string[] = ['1'];
74
76
  const wrapper = mount(
75
77
  <Tags
76
78
  name={'test-name'}
77
- onChange={spy}
79
+ onChange={changeSpy}
78
80
  value={mockValue}
79
81
  tagsOptions={['1', '2']}
80
82
  />,
81
83
  );
82
84
 
83
- const x = wrapper.find('svg');
85
+ const x = wrapper.find('[data-test-id="tags-delete"]');
84
86
 
85
- await act(async () => {
86
- await x.simulate('click', {
87
- persist: jest.fn(),
88
- });
89
- wrapper.update();
87
+ x.simulate('click', {
88
+ persist: jest.fn(),
90
89
  });
91
90
 
92
- expect(spy).toHaveBeenCalledTimes(1);
93
- // Test is only failing due to a bug with jasmine: https://github.com/jasmine/jasmine/issues/652
94
- // Objects do match, commenting it out for now.
95
- // expect(spy).toHaveBeenCalledWith({
96
- // currentTarget: { value: mockValueUpdated },
97
- // persist: jest.fn(),
98
- // });
91
+ wrapper.update();
92
+
93
+ expect(changeSpy).toHaveBeenCalledTimes(1);
94
+ expect(changeSpy).toHaveBeenCalledWith(
95
+ expect.objectContaining({
96
+ currentTarget: expect.objectContaining({ value: [] }),
97
+ }),
98
+ );
99
99
  });
100
100
 
101
101
  it('shows select element when current selected tags and optional tags are the not same length', () => {
@@ -103,37 +103,38 @@ describe('Tags', () => {
103
103
  <Tags name={'test-name'} value={['1']} tagsOptions={['1', '2']} />,
104
104
  );
105
105
 
106
- const select = wrapper.find('select');
106
+ const select = wrapper.find(Select);
107
107
 
108
- expect(select.prop('hidden')).toBe(false);
108
+ expect(select).toHaveLength(1);
109
109
  });
110
110
 
111
111
  it('hides select element when current selected tags and optional tags are the same length', () => {
112
- const wrapper = shallow(
112
+ const wrapper = mount(
113
113
  <Tags name={'test-name'} value={['1']} tagsOptions={['1', '2']} />,
114
114
  );
115
115
 
116
- let select = wrapper.find('select');
116
+ selectFirstOption(wrapper);
117
117
 
118
- expect(select.prop('hidden')).toBe(false);
118
+ wrapper.update();
119
119
 
120
- select.simulate('change', {
121
- currentTarget: { value: '2' },
122
- persist: jest.fn(),
123
- });
124
- select = wrapper.find('select');
120
+ const select = wrapper.find(Select);
125
121
 
126
- expect(select.prop('hidden')).toBe(true);
122
+ expect(select).toHaveLength(0);
127
123
  });
128
124
 
129
125
  it('raises blur and focus events', () => {
130
126
  const blurSpy = jest.fn();
131
127
  const focusSpy = jest.fn();
132
128
  const wrapper = shallow(
133
- <Tags name={'test-name'} onBlur={blurSpy} onFocus={focusSpy} />,
129
+ <Tags
130
+ name={'test-name'}
131
+ onBlur={blurSpy}
132
+ onFocus={focusSpy}
133
+ tagsOptions={['1']}
134
+ />,
134
135
  );
135
136
 
136
- const select = wrapper.find('select');
137
+ const select = wrapper.find(Select);
137
138
 
138
139
  select.simulate('blur');
139
140
  expect(blurSpy).toHaveBeenCalledTimes(1);
@@ -166,7 +167,7 @@ describe('Tags', () => {
166
167
  });
167
168
 
168
169
  it('uses the displayValue for available tags when tagOptions are objects', () => {
169
- const wrapper = shallow(
170
+ const wrapper = mount(
170
171
  <Tags
171
172
  name={'test-name'}
172
173
  value={['1', '3']}
@@ -181,43 +182,31 @@ describe('Tags', () => {
181
182
  />,
182
183
  );
183
184
 
184
- const tags = wrapper.find('option').map((node) => node.text());
185
+ const input = wrapper.find('[role="combobox"]');
186
+ input.simulate('mousedown');
185
187
 
186
- expect(tags).toHaveLength(3);
188
+ const popper = document.querySelector('[role="tooltip"]');
189
+
190
+ const options = popper?.querySelectorAll('[role="option"]');
191
+
192
+ expect(options).toHaveLength(2);
187
193
 
188
- expect(tags).toEqual(['', 'Test2', 'Test4']);
194
+ expect([options?.[0].innerHTML, options?.[1].innerHTML]).toEqual([
195
+ 'Test2',
196
+ 'Test4',
197
+ ]);
189
198
  });
190
199
 
191
200
  it('applies error styling and renders error message when an error is passed', () => {
192
201
  const mockErrorMessage = 'test-error-message';
193
- const wrapper = shallow(
194
- <Tags name={'test-name'} error={mockErrorMessage} />,
202
+ const wrapper = mount(
203
+ <Tags name={'test-name'} error={mockErrorMessage} tagsOptions={['1']} />,
195
204
  );
196
205
 
197
- const errorMsg = wrapper.dive().find('small');
198
- const errorStyling = wrapper.find('select');
206
+ const errorMsg = wrapper.find('small');
207
+ const select = wrapper.find(Select);
199
208
 
200
209
  expect(errorMsg.text()).toBe(mockErrorMessage);
201
- expect(errorStyling.hasClass('hasError')).toBe(true);
202
- });
203
-
204
- it('defaults drop down label and value to empty strings', () => {
205
- const wrapper = shallow(<Tags name={'test-name'} />);
206
-
207
- const options = wrapper.find('option');
208
-
209
- expect(options.at(0).text()).toBe('');
210
- expect(options.at(0).prop('value')).toBe('');
211
- });
212
-
213
- it('displays a label for the drop down', () => {
214
- const mockDropDownLabel = 'mockLabel';
215
- const wrapper = shallow(
216
- <Tags name={'test-name'} dropDownLabel={mockDropDownLabel} />,
217
- );
218
-
219
- const options = wrapper.find('option');
220
-
221
- expect(options.at(0).text()).toBe(mockDropDownLabel);
210
+ expect(select.hasClass('hasError')).toBe(true);
222
211
  });
223
212
  });