@eturnity/eturnity_reusable_components 9.25.17 → 9.28.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.
- package/package.json +1 -1
- package/src/components/collapsableInfoText/collapsableInfoText.spec.js +57 -0
- package/src/components/collapsableInfoText/collapsableInfoText.stories.js +8 -0
- package/src/components/filter/Filter.stories.js +177 -0
- package/src/components/filter/filter.spec.js +183 -0
- package/src/components/inputs/select/select.spec.js +154 -0
- package/src/components/inputs/select/select.stories.js +230 -56
- package/src/components/inputs/slider/slider.spec.js +59 -0
- package/src/components/inputs/slider/slider.stories.js +4 -2
- package/src/components/inputs/switchField/switchField.spec.js +88 -0
- package/src/components/inputs/textAreaInput/TextAreaInput.stories.js +78 -74
- package/src/components/inputs/textAreaInput/textAreaInput.spec.js +90 -0
|
@@ -2,53 +2,223 @@ import { computed, ref } from 'vue'
|
|
|
2
2
|
import Select from './index.vue'
|
|
3
3
|
import Option from './option/index.vue'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
// To use:
|
|
6
|
+
// import Select from '@eturnity/eturnity_reusable_components/src/components/inputs/select'
|
|
7
|
+
// import Option from '@eturnity/eturnity_reusable_components/src/components/inputs/select/option'
|
|
8
|
+
// <Select v-bind="props">
|
|
9
|
+
// <template #selector="{ selectedValue }">{{ selectedValue.label }}</template>
|
|
10
|
+
// <template #dropdown>
|
|
11
|
+
// <Option v-for="o in options" :key="o.key" :value="o">{{ o.label }}</Option>
|
|
12
|
+
// </template>
|
|
13
|
+
// </Select>
|
|
14
|
+
|
|
15
|
+
// The search field only appears once the dropdown holds at least
|
|
16
|
+
// `minOptionLength` (5 by default) options — see the WithSearchField story.
|
|
17
|
+
const FEW_OPTIONS = [
|
|
18
|
+
{ key: '1', label: 'Apple' },
|
|
19
|
+
{ key: '2', label: 'Banana' },
|
|
20
|
+
{ key: '3', label: 'Cherry' },
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
const MANY_OPTIONS = [
|
|
24
|
+
{ key: '1', label: 'Austria' },
|
|
25
|
+
{ key: '2', label: 'Belgium' },
|
|
26
|
+
{ key: '3', label: 'Denmark' },
|
|
27
|
+
{ key: '4', label: 'France' },
|
|
28
|
+
{ key: '5', label: 'Germany' },
|
|
29
|
+
{ key: '6', label: 'Italy' },
|
|
30
|
+
{ key: '7', label: 'Spain' },
|
|
31
|
+
{ key: '8', label: 'Switzerland' },
|
|
10
32
|
]
|
|
11
33
|
|
|
12
34
|
export default {
|
|
13
35
|
title: 'Components/Inputs/Select',
|
|
14
36
|
component: Select,
|
|
37
|
+
tags: ['autodocs'],
|
|
38
|
+
parameters: {
|
|
39
|
+
// The select relies on scoped slots (#selector="{ selectedValue }"), which
|
|
40
|
+
// Storybook's dynamic source generator cannot serialise (it throws
|
|
41
|
+
// "selectedValue is not defined"). Show the static story code instead.
|
|
42
|
+
docs: {
|
|
43
|
+
source: { type: 'code' },
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
argTypes: {
|
|
47
|
+
label: { description: 'Text shown above/beside the select' },
|
|
48
|
+
value: {
|
|
49
|
+
description: 'The currently selected value (any type, often an object)',
|
|
50
|
+
control: false,
|
|
51
|
+
},
|
|
52
|
+
options: {
|
|
53
|
+
description: 'Demo-only: the list of options rendered in the dropdown',
|
|
54
|
+
control: false,
|
|
55
|
+
},
|
|
56
|
+
alignItems: {
|
|
57
|
+
description: 'Label position relative to the select',
|
|
58
|
+
control: 'inline-radio',
|
|
59
|
+
options: ['horizontal', 'vertical'],
|
|
60
|
+
},
|
|
61
|
+
colorMode: {
|
|
62
|
+
description: 'Visual theme of the select',
|
|
63
|
+
control: 'inline-radio',
|
|
64
|
+
options: ['light', 'dark', 'transparent'],
|
|
65
|
+
},
|
|
66
|
+
isSearchable: {
|
|
67
|
+
description:
|
|
68
|
+
'Whether a search field is shown once the option count reaches minOptionLength',
|
|
69
|
+
control: 'boolean',
|
|
70
|
+
},
|
|
71
|
+
minOptionLength: {
|
|
72
|
+
description: 'Minimum number of options before the search field appears',
|
|
73
|
+
control: 'number',
|
|
74
|
+
},
|
|
75
|
+
searchPlacement: {
|
|
76
|
+
description: 'Where the search field renders',
|
|
77
|
+
control: 'inline-radio',
|
|
78
|
+
options: ['trigger', 'dropdown'],
|
|
79
|
+
},
|
|
80
|
+
disabled: { description: 'Disables the select', control: 'boolean' },
|
|
81
|
+
hasError: {
|
|
82
|
+
description: 'Shows the select in an error state',
|
|
83
|
+
control: 'boolean',
|
|
84
|
+
},
|
|
85
|
+
errorMessage: {
|
|
86
|
+
description: 'Message rendered below the select when hasError is true',
|
|
87
|
+
control: 'text',
|
|
88
|
+
},
|
|
89
|
+
selectWidth: { description: 'Width of the select trigger' },
|
|
90
|
+
optionWidth: { description: 'Width of the dropdown menu' },
|
|
91
|
+
|
|
92
|
+
// slots
|
|
93
|
+
selector: { description: 'Renders the selected value in the trigger' },
|
|
94
|
+
dropdown: { description: 'Holds the <Option> elements' },
|
|
95
|
+
},
|
|
15
96
|
}
|
|
16
97
|
|
|
17
98
|
const Template = (args) => ({
|
|
18
|
-
// Components used in your story `template` are defined in the `components` object
|
|
19
99
|
components: { Select, Option },
|
|
20
|
-
// The story's `args` need to be mapped into the template through the `setup()` method
|
|
21
100
|
setup() {
|
|
22
|
-
|
|
101
|
+
const options = args.options || FEW_OPTIONS
|
|
102
|
+
// Give dark / transparent modes a dark backdrop so the white text is legible.
|
|
103
|
+
const wrapperStyle = ['dark', 'transparent'].includes(args.colorMode)
|
|
104
|
+
? 'background: #2b2b2b; padding: 20px; border-radius: 4px;'
|
|
105
|
+
: 'padding: 20px;'
|
|
106
|
+
return { args, options, wrapperStyle }
|
|
23
107
|
},
|
|
24
|
-
template:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
108
|
+
template: `
|
|
109
|
+
<div :style="wrapperStyle">
|
|
110
|
+
<Select v-bind="args">
|
|
111
|
+
<template #selector="{ selectedValue }">
|
|
112
|
+
{{ selectedValue ? selectedValue.label : 'Select an option' }}
|
|
113
|
+
</template>
|
|
114
|
+
<template #dropdown>
|
|
115
|
+
<Option
|
|
116
|
+
v-for="item in options"
|
|
117
|
+
:key="item.key"
|
|
118
|
+
:value="item"
|
|
119
|
+
>
|
|
120
|
+
{{ item.label }}
|
|
121
|
+
</Option>
|
|
122
|
+
</template>
|
|
123
|
+
</Select>
|
|
124
|
+
</div>
|
|
125
|
+
`,
|
|
38
126
|
})
|
|
39
127
|
|
|
40
128
|
export const Default = Template.bind({})
|
|
41
129
|
Default.args = {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
130
|
+
label: 'Fruit',
|
|
131
|
+
alignItems: 'vertical',
|
|
132
|
+
options: FEW_OPTIONS,
|
|
133
|
+
value: FEW_OPTIONS[0],
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* With more than 5 options the search field is shown automatically so the user
|
|
138
|
+
* can filter the list. Open the dropdown to see the search input.
|
|
139
|
+
*/
|
|
140
|
+
export const WithSearchField = Template.bind({})
|
|
141
|
+
WithSearchField.args = {
|
|
142
|
+
label: 'Country',
|
|
143
|
+
alignItems: 'vertical',
|
|
144
|
+
options: MANY_OPTIONS,
|
|
145
|
+
value: MANY_OPTIONS[4],
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* The search field can also be rendered inside the dropdown itself instead of
|
|
150
|
+
* in the trigger, via `searchPlacement="dropdown"`.
|
|
151
|
+
*/
|
|
152
|
+
export const SearchInsideDropdown = Template.bind({})
|
|
153
|
+
SearchInsideDropdown.args = {
|
|
154
|
+
label: 'Country',
|
|
155
|
+
alignItems: 'vertical',
|
|
156
|
+
searchPlacement: 'dropdown',
|
|
157
|
+
options: MANY_OPTIONS,
|
|
158
|
+
value: MANY_OPTIONS[4],
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Set `minOptionLength` to change how many options trigger the search field.
|
|
163
|
+
* Here it appears with only 3 options.
|
|
164
|
+
*/
|
|
165
|
+
export const LowerSearchThreshold = Template.bind({})
|
|
166
|
+
LowerSearchThreshold.args = {
|
|
167
|
+
label: 'Fruit',
|
|
168
|
+
alignItems: 'vertical',
|
|
169
|
+
minOptionLength: 3,
|
|
170
|
+
options: FEW_OPTIONS,
|
|
171
|
+
value: FEW_OPTIONS[0],
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export const Disabled = Template.bind({})
|
|
175
|
+
Disabled.args = {
|
|
176
|
+
label: 'Fruit',
|
|
177
|
+
alignItems: 'vertical',
|
|
178
|
+
disabled: true,
|
|
179
|
+
options: FEW_OPTIONS,
|
|
180
|
+
value: FEW_OPTIONS[0],
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export const WithError = Template.bind({})
|
|
184
|
+
WithError.args = {
|
|
185
|
+
label: 'Fruit',
|
|
46
186
|
alignItems: 'vertical',
|
|
47
|
-
|
|
187
|
+
hasError: true,
|
|
188
|
+
errorMessage: 'This field is required',
|
|
189
|
+
options: FEW_OPTIONS,
|
|
190
|
+
value: null,
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export const HorizontalLabel = Template.bind({})
|
|
194
|
+
HorizontalLabel.args = {
|
|
195
|
+
label: 'Fruit',
|
|
196
|
+
alignItems: 'horizontal',
|
|
197
|
+
options: FEW_OPTIONS,
|
|
198
|
+
value: FEW_OPTIONS[0],
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export const ColorModeDark = Template.bind({})
|
|
202
|
+
ColorModeDark.args = {
|
|
203
|
+
label: 'Fruit',
|
|
204
|
+
alignItems: 'vertical',
|
|
205
|
+
colorMode: 'dark',
|
|
206
|
+
options: FEW_OPTIONS,
|
|
207
|
+
value: FEW_OPTIONS[0],
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export const ColorModeTransparent = Template.bind({})
|
|
211
|
+
ColorModeTransparent.args = {
|
|
212
|
+
label: 'Fruit',
|
|
213
|
+
alignItems: 'vertical',
|
|
214
|
+
colorMode: 'transparent',
|
|
215
|
+
options: FEW_OPTIONS,
|
|
216
|
+
value: FEW_OPTIONS[0],
|
|
48
217
|
}
|
|
49
218
|
|
|
50
219
|
/**
|
|
51
|
-
*
|
|
220
|
+
* A customizable select lets the user type a value that is not in the list and
|
|
221
|
+
* add it as a new option.
|
|
52
222
|
*/
|
|
53
223
|
const CustomizableTemplate = (args) => ({
|
|
54
224
|
components: { Select, Option },
|
|
@@ -60,7 +230,7 @@ const CustomizableTemplate = (args) => ({
|
|
|
60
230
|
label: customOptionValue,
|
|
61
231
|
})
|
|
62
232
|
const customizableOptions = computed(() => {
|
|
63
|
-
const options = [...
|
|
233
|
+
const options = [...FEW_OPTIONS]
|
|
64
234
|
if (customOption.value) {
|
|
65
235
|
options.push(customOption.value)
|
|
66
236
|
}
|
|
@@ -83,33 +253,37 @@ const CustomizableTemplate = (args) => ({
|
|
|
83
253
|
onInputChange,
|
|
84
254
|
}
|
|
85
255
|
},
|
|
86
|
-
template:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
value selected: {{ selectedValue.label }}
|
|
93
|
-
</template>
|
|
94
|
-
<template #dropdown>
|
|
95
|
-
<Option
|
|
96
|
-
v-for="(item) in customizableOptions"
|
|
97
|
-
:key="item.key"
|
|
98
|
-
:value="item"
|
|
99
|
-
>
|
|
100
|
-
{{ item.label }}
|
|
101
|
-
</Option>
|
|
102
|
-
</template>
|
|
103
|
-
<template #customOption="{ customOptionValue }">
|
|
104
|
-
<Option
|
|
105
|
-
data-custom-option
|
|
106
|
-
:value="createCustomOption(customOptionValue)"
|
|
256
|
+
template: `
|
|
257
|
+
<div style="padding: 20px;">
|
|
258
|
+
<Select
|
|
259
|
+
v-bind="args"
|
|
260
|
+
:custom-option-adapter="createCustomOption"
|
|
261
|
+
@input-change="onInputChange"
|
|
107
262
|
>
|
|
108
|
-
{
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
263
|
+
<template #selector="{ selectedValue }">
|
|
264
|
+
{{ selectedValue ? selectedValue.label : 'Select an option' }}
|
|
265
|
+
</template>
|
|
266
|
+
<template #dropdown>
|
|
267
|
+
<Option
|
|
268
|
+
v-for="item in customizableOptions"
|
|
269
|
+
:key="item.key"
|
|
270
|
+
:value="item"
|
|
271
|
+
>
|
|
272
|
+
{{ item.label }}
|
|
273
|
+
</Option>
|
|
274
|
+
</template>
|
|
275
|
+
<template #customOption="{ customOptionValue }">
|
|
276
|
+
<Option
|
|
277
|
+
data-custom-option
|
|
278
|
+
:value="createCustomOption(customOptionValue)"
|
|
279
|
+
>
|
|
280
|
+
{{ customOptionValue }}
|
|
281
|
+
<div>(custom)</div>
|
|
282
|
+
</Option>
|
|
283
|
+
</template>
|
|
284
|
+
</Select>
|
|
285
|
+
</div>
|
|
286
|
+
`,
|
|
113
287
|
})
|
|
114
288
|
|
|
115
289
|
export const Customizable = CustomizableTemplate.bind({})
|
|
@@ -117,5 +291,5 @@ Customizable.args = {
|
|
|
117
291
|
label: 'Customizable select',
|
|
118
292
|
alignItems: 'vertical',
|
|
119
293
|
isCustomizable: true,
|
|
120
|
-
value:
|
|
294
|
+
value: FEW_OPTIONS[1],
|
|
121
295
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import RcSlider from '@/components/inputs/slider'
|
|
4
|
+
|
|
5
|
+
// Isolate the wrapper from the third-party @vueform/slider, which does not
|
|
6
|
+
// render meaningfully under jsdom. The stub records the props it receives and
|
|
7
|
+
// lets us emit its `update` event.
|
|
8
|
+
jest.mock('@vueform/slider', () => ({
|
|
9
|
+
__esModule: true,
|
|
10
|
+
default: {
|
|
11
|
+
name: 'VueformSlider',
|
|
12
|
+
props: ['max', 'min', 'value', 'tooltips'],
|
|
13
|
+
emits: ['update'],
|
|
14
|
+
template: '<div data-test-id="vueform-slider"></div>',
|
|
15
|
+
},
|
|
16
|
+
}))
|
|
17
|
+
|
|
18
|
+
describe('RcSlider', () => {
|
|
19
|
+
const mountSlider = (props = {}) => mount(RcSlider, { props })
|
|
20
|
+
const innerSlider = (wrapper) =>
|
|
21
|
+
wrapper.findComponent({ name: 'VueformSlider' })
|
|
22
|
+
|
|
23
|
+
it('renders the current value with its unit', () => {
|
|
24
|
+
const wrapper = mountSlider({ value: 35, unit: '%' })
|
|
25
|
+
expect(wrapper.text()).toContain('35')
|
|
26
|
+
expect(wrapper.text()).toContain('%')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('forwards value, min and max to the underlying slider', () => {
|
|
30
|
+
const inner = innerSlider(
|
|
31
|
+
mountSlider({ value: 120, minValue: 10, maxValue: 500 })
|
|
32
|
+
)
|
|
33
|
+
expect(inner.props('value')).toBe(120)
|
|
34
|
+
expect(inner.props('min')).toBe(10)
|
|
35
|
+
expect(inner.props('max')).toBe(500)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('applies the documented defaults', () => {
|
|
39
|
+
const wrapper = mountSlider()
|
|
40
|
+
const inner = innerSlider(wrapper)
|
|
41
|
+
expect(inner.props('value')).toBe(0)
|
|
42
|
+
expect(inner.props('min')).toBe(0)
|
|
43
|
+
expect(inner.props('max')).toBe(100)
|
|
44
|
+
expect(wrapper.text()).toContain('0')
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('always disables the built-in tooltips', () => {
|
|
48
|
+
expect(innerSlider(mountSlider()).props('tooltips')).toBe(false)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('emits change with the new value when the slider updates', async () => {
|
|
52
|
+
const wrapper = mountSlider({ value: 10 })
|
|
53
|
+
|
|
54
|
+
await innerSlider(wrapper).vm.$emit('update', 42)
|
|
55
|
+
|
|
56
|
+
expect(wrapper.emitted('change')).toHaveLength(1)
|
|
57
|
+
expect(wrapper.emitted('change')[0]).toEqual([42])
|
|
58
|
+
})
|
|
59
|
+
})
|
|
@@ -11,7 +11,9 @@ export default {
|
|
|
11
11
|
docs: {
|
|
12
12
|
description: {
|
|
13
13
|
component:
|
|
14
|
-
'Wrapper around `@vueform/slider` with Eturnity styling. The inner
|
|
14
|
+
'Wrapper around `@vueform/slider` with Eturnity styling. The inner ' +
|
|
15
|
+
'control is registered as `VueformSlider` so it cannot recurse into ' +
|
|
16
|
+
'the host component.',
|
|
15
17
|
},
|
|
16
18
|
},
|
|
17
19
|
},
|
|
@@ -31,7 +33,7 @@ const Template = (args) => ({
|
|
|
31
33
|
() => args.value,
|
|
32
34
|
(v) => {
|
|
33
35
|
innerValue.value = v
|
|
34
|
-
}
|
|
36
|
+
}
|
|
35
37
|
)
|
|
36
38
|
const onSliderChange = (v) => {
|
|
37
39
|
innerValue.value = v
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import SwitchField from '@/components/inputs/switchField'
|
|
4
|
+
import RCIcon from '@/components/icon'
|
|
5
|
+
import InfoText from '@/components/infoText'
|
|
6
|
+
|
|
7
|
+
// import.meta in the real iconCache.mjs cannot be parsed by Jest.
|
|
8
|
+
jest.mock('@/components/icon/iconCache.mjs', () => ({
|
|
9
|
+
fetchIcon: jest.fn(() => Promise.resolve('mocked-icon-url.svg')),
|
|
10
|
+
}))
|
|
11
|
+
|
|
12
|
+
const OPTIONS = [
|
|
13
|
+
{ value: 0, content: 'Off', dataId: 'opt_off' },
|
|
14
|
+
{ value: 1, content: 'Auto', dataId: 'opt_auto' },
|
|
15
|
+
{ value: 2, content: 'On', dataId: 'opt_on' },
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
describe('SwitchField', () => {
|
|
19
|
+
const mountSwitch = (props = {}) =>
|
|
20
|
+
mount(SwitchField, { props: { options: OPTIONS, value: 1, ...props } })
|
|
21
|
+
|
|
22
|
+
it('renders one option per entry with its content', () => {
|
|
23
|
+
const wrapper = mountSwitch()
|
|
24
|
+
expect(wrapper.find('[data-id="opt_off"]').exists()).toBe(true)
|
|
25
|
+
expect(wrapper.find('[data-id="opt_auto"]').exists()).toBe(true)
|
|
26
|
+
expect(wrapper.find('[data-id="opt_on"]').exists()).toBe(true)
|
|
27
|
+
expect(wrapper.text()).toContain('Off')
|
|
28
|
+
expect(wrapper.text()).toContain('Auto')
|
|
29
|
+
expect(wrapper.text()).toContain('On')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('emits on-switch-change with the clicked value', async () => {
|
|
33
|
+
const wrapper = mountSwitch()
|
|
34
|
+
|
|
35
|
+
await wrapper.find('[data-id="opt_on"]').trigger('click')
|
|
36
|
+
|
|
37
|
+
expect(wrapper.emitted('on-switch-change')).toHaveLength(1)
|
|
38
|
+
expect(wrapper.emitted('on-switch-change')[0]).toEqual([2])
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('emits the matching value for each option clicked', async () => {
|
|
42
|
+
const wrapper = mountSwitch()
|
|
43
|
+
|
|
44
|
+
await wrapper.find('[data-id="opt_off"]').trigger('click')
|
|
45
|
+
await wrapper.find('[data-id="opt_auto"]').trigger('click')
|
|
46
|
+
|
|
47
|
+
const emitted = wrapper.emitted('on-switch-change')
|
|
48
|
+
expect(emitted).toHaveLength(2)
|
|
49
|
+
expect(emitted[0]).toEqual([0])
|
|
50
|
+
expect(emitted[1]).toEqual([1])
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('does not emit when disabled', async () => {
|
|
54
|
+
const wrapper = mountSwitch({ disabled: true })
|
|
55
|
+
|
|
56
|
+
await wrapper.find('[data-id="opt_on"]').trigger('click')
|
|
57
|
+
|
|
58
|
+
expect(wrapper.emitted('on-switch-change')).toBeUndefined()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('renders the label with the required star', () => {
|
|
62
|
+
const wrapper = mountSwitch({ label: 'Mode', isRequiredLabel: true })
|
|
63
|
+
expect(wrapper.text()).toContain('Mode')
|
|
64
|
+
expect(wrapper.text()).toContain('*')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('renders the info text only when a message is provided', () => {
|
|
68
|
+
expect(mountSwitch({ label: 'Mode' }).findComponent(InfoText).exists()).toBe(
|
|
69
|
+
false
|
|
70
|
+
)
|
|
71
|
+
expect(
|
|
72
|
+
mountSwitch({ label: 'Mode', infoTextMessage: 'Helpful hint' })
|
|
73
|
+
.findComponent(InfoText)
|
|
74
|
+
.exists()
|
|
75
|
+
).toBe(true)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('renders an icon only for options that define one', () => {
|
|
79
|
+
const wrapper = mountSwitch({
|
|
80
|
+
options: [
|
|
81
|
+
{ value: 0, content: 'A', icon: 'check', iconSize: '12px' },
|
|
82
|
+
{ value: 1, content: 'B' },
|
|
83
|
+
],
|
|
84
|
+
value: 0,
|
|
85
|
+
})
|
|
86
|
+
expect(wrapper.findAllComponents(RCIcon)).toHaveLength(1)
|
|
87
|
+
})
|
|
88
|
+
})
|