@nexxtmove/ui 2.6.0 → 2.7.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/dist/index.js +49 -126
- package/dist/nuxt.js +0 -1
- package/package.json +38 -36
- package/src/attribute-contract.test.ts +151 -0
- package/src/components/atoms/AnimatedNumber/AnimatedNumber.stories.ts +36 -0
- package/src/components/atoms/AnimatedNumber/AnimatedNumber.test.ts +21 -0
- package/src/components/atoms/Avatar/Avatar.stories.ts +122 -0
- package/src/components/atoms/Avatar/Avatar.test.ts +134 -0
- package/src/components/atoms/Button/Button.stories.ts +290 -0
- package/src/components/atoms/Button/Button.test.ts +406 -0
- package/src/components/atoms/Card/Card.stories.ts +45 -0
- package/src/components/atoms/Card/Card.test.ts +46 -0
- package/src/components/atoms/Checkbox/Checkbox.stories.ts +35 -0
- package/src/components/atoms/Checkbox/Checkbox.test.ts +55 -0
- package/src/components/atoms/Chip/Chip.stories.ts +274 -0
- package/src/components/atoms/Chip/Chip.test.ts +230 -0
- package/src/components/atoms/EnergyLabel/EnergyLabel.stories.ts +189 -0
- package/src/components/atoms/EnergyLabel/EnergyLabel.test.ts +100 -0
- package/src/components/atoms/FloatingPanel/FloatingPanel.stories.ts +677 -0
- package/src/components/atoms/FloatingPanel/FloatingPanel.test.ts +864 -0
- package/src/components/atoms/Icon/Icon.stories.ts +63 -0
- package/src/components/atoms/Icon/Icon.test.ts +89 -0
- package/src/components/atoms/Loader/Loader.stories.ts +36 -0
- package/src/components/atoms/Loader/Loader.test.ts +40 -0
- package/src/components/atoms/PickerItem/PickerItem.stories.ts +172 -0
- package/src/components/atoms/PickerItem/PickerItem.test.ts +142 -0
- package/src/components/atoms/PickerPreview/PickerPreview.stories.ts +183 -0
- package/src/components/atoms/PickerPreview/PickerPreview.test.ts +137 -0
- package/src/components/atoms/PresenceIndicator/PresenceIndicator.stories.ts +21 -0
- package/src/components/atoms/PropertyListing/PropertyListing.stories.ts +38 -0
- package/src/components/atoms/PropertyListing/PropertyListing.test.ts +46 -0
- package/src/components/atoms/SelectableOption/SelectableOption.stories.ts +131 -0
- package/src/components/atoms/SelectableOption/SelectableOption.test.ts +96 -0
- package/src/components/atoms/Skeleton/Skeleton.stories.ts +27 -0
- package/src/components/atoms/Skeleton/Skeleton.test.ts +28 -0
- package/src/components/atoms/Slider/Slider.stories.ts +151 -0
- package/src/components/atoms/Slider/Slider.test.ts +191 -0
- package/src/components/atoms/Squircle/Squircle.stories.ts +114 -0
- package/src/components/atoms/Squircle/Squircle.test.ts +70 -0
- package/src/components/atoms/Switch/Switch.stories.ts +91 -0
- package/src/components/atoms/Switch/Switch.test.ts +183 -0
- package/src/components/atoms/Tooltip/Tooltip.stories.ts +158 -0
- package/src/components/atoms/Tooltip/Tooltip.test.ts +134 -0
- package/src/components/editor/atoms/EditorDimensionField/EditorDimensionField.stories.ts +124 -0
- package/src/components/editor/atoms/EditorDimensionField/EditorDimensionField.test.ts +464 -0
- package/src/components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.stories.ts +266 -0
- package/src/components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.test.ts +421 -0
- package/src/components/editor/atoms/EditorSettingsGroup/EditorSettingsGroup.stories.ts +365 -0
- package/src/components/editor/atoms/EditorSettingsGroup/EditorSettingsGroup.test.ts +484 -0
- package/src/components/editor/composables/useRadioGrid.test.ts +261 -0
- package/src/components/editor/molecules/EditorAlignItems/EditorAlignItems.stories.ts +73 -0
- package/src/components/editor/molecules/EditorAlignItems/EditorAlignItems.test.ts +189 -0
- package/src/components/editor/molecules/EditorAlignmentGrid/EditorAlignmentGrid.stories.ts +309 -0
- package/src/components/editor/molecules/EditorAlignmentGrid/EditorAlignmentGrid.test.ts +359 -0
- package/src/components/editor/molecules/EditorAnchor/EditorAnchor.stories.ts +138 -0
- package/src/components/editor/molecules/EditorAnchor/EditorAnchor.test.ts +344 -0
- package/src/components/editor/molecules/EditorBackgroundSize/EditorBackgroundSize.stories.ts +87 -0
- package/src/components/editor/molecules/EditorBackgroundSize/EditorBackgroundSize.test.ts +262 -0
- package/src/components/editor/molecules/EditorBlur/EditorBlur.stories.ts +115 -0
- package/src/components/editor/molecules/EditorBlur/EditorBlur.test.ts +243 -0
- package/src/components/editor/molecules/EditorBorder/EditorBorder.stories.ts +187 -0
- package/src/components/editor/molecules/EditorBorder/EditorBorder.test.ts +456 -0
- package/src/components/editor/molecules/EditorColor/EditorColor.stories.ts +563 -0
- package/src/components/editor/molecules/EditorColor/EditorColor.test.ts +689 -0
- package/src/components/editor/molecules/EditorColor/EditorColorGradient.test.ts +793 -0
- package/src/components/editor/molecules/EditorColor/gradientClass.test.ts +303 -0
- package/src/components/editor/molecules/EditorDashPattern/EditorDashPattern.stories.ts +72 -0
- package/src/components/editor/molecules/EditorDashPattern/EditorDashPattern.test.ts +124 -0
- package/src/components/editor/molecules/EditorFlexDirection/EditorFlexDirection.stories.ts +46 -0
- package/src/components/editor/molecules/EditorFlexDirection/EditorFlexDirection.test.ts +97 -0
- package/src/components/editor/molecules/EditorFontSize/EditorFontSize.stories.ts +248 -0
- package/src/components/editor/molecules/EditorFontSize/EditorFontSize.test.ts +288 -0
- package/src/components/editor/molecules/EditorGap/EditorGap.stories.ts +129 -0
- package/src/components/editor/molecules/EditorGap/EditorGap.test.ts +253 -0
- package/src/components/editor/molecules/EditorHeadingType/EditorHeadingType.stories.ts +68 -0
- package/src/components/editor/molecules/EditorHeadingType/EditorHeadingType.test.ts +150 -0
- package/src/components/editor/molecules/EditorJustifyContent/EditorJustifyContent.stories.ts +71 -0
- package/src/components/editor/molecules/EditorJustifyContent/EditorJustifyContent.test.ts +161 -0
- package/src/components/editor/molecules/EditorLetterSpacing/EditorLetterSpacing.stories.ts +204 -0
- package/src/components/editor/molecules/EditorLetterSpacing/EditorLetterSpacing.test.ts +238 -0
- package/src/components/editor/molecules/EditorLineHeight/EditorLineHeight.stories.ts +257 -0
- package/src/components/editor/molecules/EditorLineHeight/EditorLineHeight.test.ts +286 -0
- package/src/components/editor/molecules/EditorLineStyle/EditorLineStyle.stories.ts +135 -0
- package/src/components/editor/molecules/EditorLineStyle/EditorLineStyle.test.ts +230 -0
- package/src/components/editor/molecules/EditorMaxWidth/EditorMaxWidth.stories.ts +154 -0
- package/src/components/editor/molecules/EditorMaxWidth/EditorMaxWidth.test.ts +112 -0
- package/src/components/editor/molecules/EditorOverrideStatus/EditorOverrideStatus.stories.ts +206 -0
- package/src/components/editor/molecules/EditorOverrideStatus/EditorOverrideStatus.test.ts +332 -0
- package/src/components/editor/molecules/EditorPadding/EditorPadding.stories.ts +374 -0
- package/src/components/editor/molecules/EditorPadding/EditorPadding.test.ts +712 -0
- package/src/components/editor/molecules/EditorRadius/EditorRadius.stories.ts +64 -0
- package/src/components/editor/molecules/EditorRadius/EditorRadius.test.ts +137 -0
- package/src/components/editor/molecules/EditorShadow/EditorShadow.stories.ts +103 -0
- package/src/components/editor/molecules/EditorShadow/EditorShadow.test.ts +168 -0
- package/src/components/editor/molecules/EditorSize/EditorSize.stories.ts +84 -0
- package/src/components/editor/molecules/EditorSize/EditorSize.test.ts +253 -0
- package/src/components/editor/molecules/EditorSizeLimit/EditorSizeLimit.stories.ts +49 -0
- package/src/components/editor/molecules/EditorSizeLimit/EditorSizeLimit.test.ts +43 -0
- package/src/components/editor/molecules/EditorTextAlign/EditorTextAlign.stories.ts +69 -0
- package/src/components/editor/molecules/EditorTextAlign/EditorTextAlign.test.ts +155 -0
- package/src/components/molecules/Announcement/Announcement.stories.ts +224 -0
- package/src/components/molecules/Announcement/Announcement.test.ts +161 -0
- package/src/components/molecules/ContactInfoCard/ContactInfoCard.stories.ts +99 -0
- package/src/components/molecules/ContactInfoCard/ContactInfoCard.test.ts +70 -0
- package/src/components/molecules/CustomerJourneyTile/CustomerJourneyTile.stories.ts +148 -0
- package/src/components/molecules/CustomerJourneyTile/CustomerJourneyTile.test.ts +271 -0
- package/src/components/molecules/DoughnutChart/DoughnutChart.stories.ts +45 -0
- package/src/components/molecules/DoughnutChart/DoughnutChart.test.ts +205 -0
- package/src/components/molecules/InfoBlock/InfoBlock.stories.ts +84 -0
- package/src/components/molecules/InfoBlock/InfoBlock.test.ts +101 -0
- package/src/components/molecules/InputField/InputField.stories.ts +117 -0
- package/src/components/molecules/InputField/InputField.test.ts +138 -0
- package/src/components/molecules/InputSelect/InputSelect.stories.ts +116 -0
- package/src/components/molecules/InputSelect/InputSelect.test.ts +127 -0
- package/src/components/molecules/ModalFooter/ModalFooter.stories.ts +204 -0
- package/src/components/molecules/ModalFooter/ModalFooter.test.ts +276 -0
- package/src/components/molecules/PageCard/PageCard.stories.ts +100 -0
- package/src/components/molecules/PageCard/PageCard.test.ts +91 -0
- package/src/components/molecules/PageContainer/PageContainer.stories.ts +90 -0
- package/src/components/molecules/PageContainer/PageContainer.test.ts +50 -0
- package/src/components/molecules/PageMockup/PageMockup.stories.ts +38 -0
- package/src/components/molecules/PageMockup/PageMockup.test.ts +20 -0
- package/src/components/molecules/PageTypeTile/PageTypeTile.stories.ts +63 -0
- package/src/components/molecules/PageTypeTile/PageTypeTile.test.ts +41 -0
- package/src/components/molecules/Pagination/Pagination.stories.ts +72 -0
- package/src/components/molecules/Pagination/Pagination.test.ts +130 -0
- package/src/components/molecules/PickerGroup/PickerGroup.stories.ts +90 -0
- package/src/components/molecules/PickerGroup/PickerGroup.test.ts +145 -0
- package/src/components/molecules/PickerList/PickerList.stories.ts +436 -0
- package/src/components/molecules/PickerList/PickerList.test.ts +870 -0
- package/src/components/molecules/PlaceholderInput/PlaceholderInput.stories.ts +48 -0
- package/src/components/molecules/PlaceholderInput/PlaceholderInput.test.ts +107 -0
- package/src/components/molecules/PropertyCard/PropertyCard.stories.ts +46 -0
- package/src/components/molecules/PropertyCard/PropertyCard.test.ts +59 -0
- package/src/components/molecules/Select/Select.stories.ts +264 -0
- package/src/components/molecules/Select/Select.test.ts +315 -0
- package/src/components/molecules/SidebarMenuItem/SidebarMenuItem.stories.ts +84 -0
- package/src/components/molecules/SidebarMenuItem/SidebarMenuItem.test.ts +103 -0
- package/src/components/molecules/SkeletonPropertyCard/SkeletonPropertyCard.stories.ts +11 -0
- package/src/components/molecules/SkeletonPropertyCard/SkeletonPropertyCard.test.ts +38 -0
- package/src/components/molecules/SocialIcons/SocialIcons.stories.ts +28 -0
- package/src/components/molecules/SocialIcons/SocialIcons.test.ts +58 -0
- package/src/components/molecules/SocialMediaCustomTemplate/SocialMediaCustomTemplate.stories.ts +11 -0
- package/src/components/molecules/SocialMediaCustomTemplate/SocialMediaCustomTemplate.test.ts +116 -0
- package/src/components/molecules/SocialMediaType/SocialMediaType.stories.ts +37 -0
- package/src/components/molecules/SocialMediaType/SocialMediaType.test.ts +126 -0
- package/src/components/molecules/Source/Source.stories.ts +35 -0
- package/src/components/molecules/Source/Source.test.ts +45 -0
- package/src/components/molecules/TabbedContent/TabbedContent.stories.ts +96 -0
- package/src/components/molecules/TabbedContent/TabbedContent.test.ts +109 -0
- package/src/components/molecules/Tabs/Tabs.stories.ts +230 -0
- package/src/components/molecules/Tabs/Tabs.test.ts +280 -0
- package/src/components/molecules/TemplateCard/TemplateCard.stories.ts +327 -0
- package/src/components/molecules/TemplateCard/TemplateCard.test.ts +339 -0
- package/src/components/molecules/Textarea/Textarea.stories.ts +216 -0
- package/src/components/molecules/Textarea/Textarea.test.ts +191 -0
- package/src/components/molecules/TimelineEvent/TimelineEvent.stories.ts +319 -0
- package/src/components/molecules/TimelineEvent/TimelineEvent.test.ts +224 -0
- package/src/components/molecules/TimelineLanes/TimelineLanes.stories.ts +29 -0
- package/src/components/molecules/TimelineLanes/TimelineLanes.test.ts +30 -0
- package/src/components/molecules/Toast/Toast.stories.ts +110 -0
- package/src/components/molecules/Toast/Toast.test.ts +103 -0
- package/src/components/molecules/ToggleGroup/ToggleGroup.stories.ts +297 -0
- package/src/components/molecules/ToggleGroup/ToggleGroup.test.ts +578 -0
- package/src/components/molecules/Tree/Tree.stories.ts +884 -0
- package/src/components/molecules/Tree/Tree.test.ts +1247 -0
- package/src/components/molecules/Tree/tree-drop.test.ts +223 -0
- package/src/components/organisms/Calendar/Calendar.stories.ts +108 -0
- package/src/components/organisms/Calendar/Calendar.test.ts +279 -0
- package/src/components/organisms/Calendar/_CalendarDayView.test.ts +104 -0
- package/src/components/organisms/Calendar/_CalendarHeader.test.ts +86 -0
- package/src/components/organisms/Calendar/_CalendarMonthView.test.ts +52 -0
- package/src/components/organisms/Calendar/_CalendarTimePicker.test.ts +89 -0
- package/src/components/organisms/Calendar/_CalendarYearView.test.ts +56 -0
- package/src/components/organisms/ColorPicker/ColorPicker.stories.ts +229 -0
- package/src/components/organisms/ColorPicker/ColorPicker.test.ts +638 -0
- package/src/components/organisms/ColorPicker/gradient.test.ts +67 -0
- package/src/components/organisms/ColorPicker/gradientGeometry.test.ts +206 -0
- package/src/components/organisms/Combobox/Combobox.stories.ts +234 -0
- package/src/components/organisms/Combobox/Combobox.test.ts +512 -0
- package/src/components/organisms/Combobox/Combobox.vue +1 -1
- package/src/components/organisms/ComboboxPanel/ComboboxPanel.stories.ts +158 -0
- package/src/components/organisms/ComboboxPanel/ComboboxPanel.test.ts +524 -0
- package/src/components/organisms/ComboboxPanel/ComboboxPanel.vue +1 -1
- package/src/components/organisms/CountrySelect/CountrySelect.stories.ts +139 -0
- package/src/components/organisms/CountrySelect/CountrySelect.test.ts +149 -0
- package/src/components/organisms/DatePicker/DatePicker.stories.ts +163 -0
- package/src/components/organisms/DatePicker/DatePicker.test.ts +214 -0
- package/src/components/organisms/DropdownButton/DropdownButton.stories.ts +123 -0
- package/src/components/organisms/DropdownButton/DropdownButton.test.ts +379 -0
- package/src/components/organisms/FontPicker/FontPicker.stories.ts +476 -0
- package/src/components/organisms/FontPicker/FontPicker.test.ts +873 -0
- package/src/components/organisms/Header/Header.stories.ts +75 -0
- package/src/components/organisms/Header/Header.test.ts +233 -0
- package/src/components/organisms/IconPicker/IconPicker.stories.ts +734 -0
- package/src/components/organisms/IconPicker/IconPicker.test.ts +669 -0
- package/src/components/organisms/IconPicker/_IconPickerGrid.test.ts +184 -0
- package/src/components/organisms/IconPicker/_IconPickerRail.test.ts +102 -0
- package/src/components/organisms/IconPicker/useIconPickerNavigation.test.ts +215 -0
- package/src/components/organisms/Modal/Modal.stories.ts +350 -0
- package/src/components/organisms/Modal/Modal.test.ts +275 -0
- package/src/components/organisms/PickerPanel/PickerPanel.stories.ts +452 -0
- package/src/components/organisms/PickerPanel/PickerPanel.test.ts +358 -0
- package/src/components/organisms/ProgressBar/ProgressBar.stories.ts +100 -0
- package/src/components/organisms/ProgressBar/ProgressBar.test.ts +417 -0
- package/src/components/organisms/ReferenceCard/ReferenceCard.stories.ts +191 -0
- package/src/components/organisms/ReferenceCard/ReferenceCard.test.ts +165 -0
- package/src/components/organisms/SocialMediaTemplate/SocialMediaTemplate.stories.ts +65 -0
- package/src/components/organisms/SocialMediaTemplate/SocialMediaTemplate.test.ts +466 -0
- package/src/components/organisms/StepperHeader/StepperHeader.stories.ts +91 -0
- package/src/components/organisms/StepperHeader/StepperHeader.test.ts +279 -0
- package/src/components/organisms/Table/Table.stories.ts +332 -0
- package/src/components/organisms/Table/Table.test.ts +320 -0
- package/src/components/organisms/TimelinePhaseblock/TimelinePhaseblock.stories.ts +198 -0
- package/src/components/organisms/TimelinePhaseblock/TimelinePhaseblock.test.ts +283 -0
- package/src/components/organisms/TimelineTrack/TimelineTrack.stories.ts +120 -0
- package/src/components/organisms/TimelineTrack/TimelineTrack.test.ts +91 -0
- package/src/components/organisms/Toaster/Toaster.stories.ts +51 -0
- package/src/components/organisms/Toaster/Toaster.test.ts +75 -0
- package/src/components/organisms/VideoControls/VideoControls.stories.ts +792 -0
- package/src/components/organisms/VideoControls/VideoControls.test.ts +1056 -0
- package/src/components/organisms/VideoPlayer/VideoPlayer.stories.ts +327 -0
- package/src/components/organisms/VideoPlayer/VideoPlayer.test.ts +439 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import TimelineEvent from './TimelineEvent.vue'
|
|
4
|
+
|
|
5
|
+
const baseEvent = {
|
|
6
|
+
id: 1,
|
|
7
|
+
happened_at: '2024-06-15T10:30:00.000Z',
|
|
8
|
+
medium_type: null,
|
|
9
|
+
url: null,
|
|
10
|
+
page_title: null,
|
|
11
|
+
request_reason: null,
|
|
12
|
+
agenda_item_type: null,
|
|
13
|
+
source: 'system',
|
|
14
|
+
direction: 'outbound',
|
|
15
|
+
description: null,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const mountEvent = (eventOverrides = {}, props = {}) =>
|
|
19
|
+
mount(TimelineEvent, {
|
|
20
|
+
props: {
|
|
21
|
+
event: { ...baseEvent, type: 'contact_created', ...eventOverrides },
|
|
22
|
+
...props,
|
|
23
|
+
},
|
|
24
|
+
global: {
|
|
25
|
+
stubs: {
|
|
26
|
+
NexxtIcon: true,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
describe('TimelineEvent', () => {
|
|
32
|
+
it('renders the formatted date', () => {
|
|
33
|
+
const wrapper = mountEvent()
|
|
34
|
+
const dateText = wrapper.find('.extra-small-normal').text()
|
|
35
|
+
expect(dateText).toContain('om')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('sets data-event-source attribute from direction', () => {
|
|
39
|
+
const wrapper = mountEvent({ direction: 'inbound' })
|
|
40
|
+
expect(wrapper.attributes('data-event-source')).toBe('inbound')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('sets data-event-date attribute from happened_at', () => {
|
|
44
|
+
const wrapper = mountEvent({ happened_at: '2024-06-15T10:30:00.000Z' })
|
|
45
|
+
expect(wrapper.attributes('data-event-date')).toBe('2024-06-15T10:30:00.000Z')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('sets date-event-type attribute from type', () => {
|
|
49
|
+
const wrapper = mountEvent({ type: 'page_viewed' })
|
|
50
|
+
expect(wrapper.attributes('date-event-type')).toBe('page_viewed')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('renders the event label for a known event type', () => {
|
|
54
|
+
const wrapper = mountEvent({ type: 'contact_created' })
|
|
55
|
+
expect(wrapper.text()).toContain('Contact aangemaakt')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('renders the event type as label for an unknown event type', () => {
|
|
59
|
+
const wrapper = mountEvent({ type: 'custom_unknown_type' })
|
|
60
|
+
expect(wrapper.text()).toContain('custom_unknown_type')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('does not render a link when event.url is null', () => {
|
|
64
|
+
const wrapper = mountEvent({ url: null })
|
|
65
|
+
expect(wrapper.find('a').exists()).toBe(false)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('renders a link when event.url is set', () => {
|
|
69
|
+
const wrapper = mountEvent({ url: 'https://example.com' })
|
|
70
|
+
const link = wrapper.find('a')
|
|
71
|
+
expect(link.exists()).toBe(true)
|
|
72
|
+
expect(link.attributes('href')).toBe('https://example.com')
|
|
73
|
+
expect(link.attributes('target')).toBe('_blank')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('renders event.description as link text when set', () => {
|
|
77
|
+
const wrapper = mountEvent({ url: 'https://example.com', description: 'Mijn voorstel' })
|
|
78
|
+
expect(wrapper.find('a').text()).toContain('Mijn voorstel')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
it('renders event.url as link text when description is null', () => {
|
|
82
|
+
const wrapper = mountEvent({ url: 'https://example.com', description: null })
|
|
83
|
+
expect(wrapper.find('a').text()).toContain('https://example.com')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('renders event.description as plain text when there is no url', () => {
|
|
87
|
+
const wrapper = mountEvent({ url: null, description: 'Naar Jan de Vries' })
|
|
88
|
+
expect(wrapper.find('a').exists()).toBe(false)
|
|
89
|
+
expect(wrapper.text()).toContain('Naar Jan de Vries')
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('does not render the url as text when there is no url', () => {
|
|
93
|
+
const wrapper = mountEvent({ url: null, description: null })
|
|
94
|
+
expect(wrapper.find('.rounded-xl').text()).toBe('Contact aangemaakt')
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('prefers event.label over the label from the config map', () => {
|
|
98
|
+
const wrapper = mountEvent({
|
|
99
|
+
type: 'proposal_status_changed',
|
|
100
|
+
label: 'Status gewijzigd van Gepland naar Verzonden',
|
|
101
|
+
})
|
|
102
|
+
expect(wrapper.text()).toContain('Status gewijzigd van Gepland naar Verzonden')
|
|
103
|
+
expect(wrapper.text()).not.toContain('Status gewijzigd van X')
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('still takes icon and color from the config map when only label is overridden', () => {
|
|
107
|
+
const wrapper = mountEvent({ type: 'proposal_status_changed', label: 'Eigen label' })
|
|
108
|
+
expect(wrapper.find('.rounded-full').classes()).toContain('bg-purple-500')
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('prefers event.color over the color from the config map', () => {
|
|
112
|
+
const wrapper = mountEvent({ type: 'contact_created', color: 'bg-emerald-500' })
|
|
113
|
+
const iconWrapper = wrapper.find('.rounded-full')
|
|
114
|
+
expect(iconWrapper.classes()).toContain('bg-emerald-500')
|
|
115
|
+
expect(iconWrapper.classes()).not.toContain('bg-pink-500')
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('prefers event.icon over the icon from the config map', () => {
|
|
119
|
+
const wrapper = mount(TimelineEvent, {
|
|
120
|
+
props: {
|
|
121
|
+
event: { ...baseEvent, type: 'contact_created', icon: 'star' },
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
expect(wrapper.find('i').classes()).toContain('fa-star')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('falls back to the default icon and color for an unknown type without overrides', () => {
|
|
128
|
+
const wrapper = mount(TimelineEvent, {
|
|
129
|
+
props: { event: { ...baseEvent, type: 'unknown_type' } },
|
|
130
|
+
})
|
|
131
|
+
expect(wrapper.find('.rounded-full').classes()).toContain('bg-gray-500')
|
|
132
|
+
expect(wrapper.find('i').classes()).toContain('fa-info')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('renders an event that only has type and happened_at', () => {
|
|
136
|
+
const wrapper = mount(TimelineEvent, {
|
|
137
|
+
props: {
|
|
138
|
+
event: { id: 'sent-12', type: 'proposal_sent', happened_at: '2024-06-15T10:30:00.000Z' },
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
expect(wrapper.text()).toContain('Voorstel verzonden')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('does not render request_reason when not set', () => {
|
|
145
|
+
const wrapper = mountEvent({ request_reason: null })
|
|
146
|
+
expect(wrapper.text()).not.toContain('Reden:')
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('renders request_reason when set', () => {
|
|
150
|
+
const wrapper = mountEvent({ request_reason: 'Interesse in de woning' })
|
|
151
|
+
expect(wrapper.text()).toContain('Reden: Interesse in de woning')
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('aligns outbound events to the left by default (no justify-end)', () => {
|
|
155
|
+
const wrapper = mountEvent({ direction: 'outbound' }, { splitView: true })
|
|
156
|
+
expect(wrapper.classes()).not.toContain('justify-end')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('aligns inbound events to the right when splitView is true', () => {
|
|
160
|
+
const wrapper = mountEvent({ direction: 'inbound' }, { splitView: true })
|
|
161
|
+
expect(wrapper.classes()).toContain('justify-end')
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('does not align inbound events to the right when splitView is false', () => {
|
|
165
|
+
const wrapper = mountEvent({ direction: 'inbound' }, { splitView: false })
|
|
166
|
+
expect(wrapper.classes()).not.toContain('justify-end')
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('reverses icon and content order for inbound events in splitView', () => {
|
|
170
|
+
const wrapper = mountEvent({ direction: 'inbound' }, { splitView: true })
|
|
171
|
+
const innerRow = wrapper.find('.flex.w-full.shrink-0')
|
|
172
|
+
expect(innerRow.classes()).toContain('flex-row-reverse')
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('does not reverse order for outbound events', () => {
|
|
176
|
+
const wrapper = mountEvent({ direction: 'outbound' }, { splitView: true })
|
|
177
|
+
const innerRow = wrapper.find('.flex.w-full.shrink-0')
|
|
178
|
+
expect(innerRow.classes()).not.toContain('flex-row-reverse')
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it('applies max-w-lg to content when splitView is true', () => {
|
|
182
|
+
const wrapper = mountEvent({}, { splitView: true })
|
|
183
|
+
const content = wrapper.find('.rounded-xl')
|
|
184
|
+
expect(content.classes()).toContain('max-w-lg')
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('does not apply max-w-lg to content when splitView is false', () => {
|
|
188
|
+
const wrapper = mountEvent({}, { splitView: false })
|
|
189
|
+
const content = wrapper.find('.rounded-xl')
|
|
190
|
+
expect(content.classes()).not.toContain('max-w-lg')
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('defaults splitView to true', () => {
|
|
194
|
+
const wrapper = mount(TimelineEvent, {
|
|
195
|
+
props: {
|
|
196
|
+
event: { ...baseEvent, type: 'contact_created', direction: 'inbound' },
|
|
197
|
+
},
|
|
198
|
+
global: { stubs: { NexxtIcon: true } },
|
|
199
|
+
})
|
|
200
|
+
expect(wrapper.classes()).toContain('justify-end')
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
it('applies correct background color class for known event type', () => {
|
|
204
|
+
const wrapper = mountEvent({ type: 'contact_created' })
|
|
205
|
+
const iconWrapper = wrapper.find('.rounded-full')
|
|
206
|
+
expect(iconWrapper.classes()).toContain('bg-pink-500')
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('applies default background color for unknown event type', () => {
|
|
210
|
+
const wrapper = mountEvent({ type: 'unknown_type' })
|
|
211
|
+
const iconWrapper = wrapper.find('.rounded-full')
|
|
212
|
+
expect(iconWrapper.classes()).toContain('bg-gray-500')
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
it('aligns date text to the right for inbound events in splitView', () => {
|
|
216
|
+
const wrapper = mountEvent({ direction: 'inbound' }, { splitView: true })
|
|
217
|
+
expect(wrapper.find('.extra-small-normal').classes()).toContain('text-right')
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
it('does not align date text to the right for outbound events', () => {
|
|
221
|
+
const wrapper = mountEvent({ direction: 'outbound' }, { splitView: true })
|
|
222
|
+
expect(wrapper.find('.extra-small-normal').classes()).not.toContain('text-right')
|
|
223
|
+
})
|
|
224
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import TimelineLanes from './TimelineLanes.vue'
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Components/Molecules/Timeline Lanes',
|
|
6
|
+
component: TimelineLanes,
|
|
7
|
+
} satisfies Meta<typeof TimelineLanes>
|
|
8
|
+
|
|
9
|
+
type Story = StoryObj<typeof TimelineLanes>
|
|
10
|
+
|
|
11
|
+
export const Default: Story = {
|
|
12
|
+
args: {},
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const CustomLabels: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
leftLabel: 'Nexxtmove',
|
|
18
|
+
rightLabel: 'Contact',
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const WithoutTooltips: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
leftLabel: 'Nexxtmove',
|
|
25
|
+
rightLabel: 'Contact',
|
|
26
|
+
leftTooltip: '',
|
|
27
|
+
rightTooltip: '',
|
|
28
|
+
},
|
|
29
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import TimelineLanes from './TimelineLanes.vue'
|
|
4
|
+
|
|
5
|
+
const mountLanes = (props = {}) => mount(TimelineLanes, { props })
|
|
6
|
+
|
|
7
|
+
describe('TimelineLanes', () => {
|
|
8
|
+
it('defaults to the Outbound and Inbound labels', () => {
|
|
9
|
+
const wrapper = mountLanes()
|
|
10
|
+
expect(wrapper.text()).toContain('Outbound')
|
|
11
|
+
expect(wrapper.text()).toContain('Inbound')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('renders custom labels', () => {
|
|
15
|
+
const wrapper = mountLanes({ leftLabel: 'Nexxtmove', rightLabel: 'Contact' })
|
|
16
|
+
expect(wrapper.text()).toContain('Nexxtmove')
|
|
17
|
+
expect(wrapper.text()).toContain('Contact')
|
|
18
|
+
expect(wrapper.text()).not.toContain('Outbound')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('renders a tooltip trigger for each lane by default', () => {
|
|
22
|
+
const wrapper = mountLanes()
|
|
23
|
+
expect(wrapper.findAll('i.fa-circle-info')).toHaveLength(2)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('hides a tooltip when its text is empty', () => {
|
|
27
|
+
const wrapper = mountLanes({ leftTooltip: '', rightTooltip: '' })
|
|
28
|
+
expect(wrapper.findAll('i.fa-circle-info')).toHaveLength(0)
|
|
29
|
+
})
|
|
30
|
+
})
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/vue3-vite'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import NexxtToast from './Toast.vue'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Components/Molecules/Toast',
|
|
7
|
+
component: NexxtToast,
|
|
8
|
+
decorators: [
|
|
9
|
+
() => ({
|
|
10
|
+
template:
|
|
11
|
+
'<div style="padding: 24px; display: flex; justify-content: center;"><story /></div>',
|
|
12
|
+
}),
|
|
13
|
+
],
|
|
14
|
+
} satisfies Meta<typeof NexxtToast>
|
|
15
|
+
|
|
16
|
+
type Story = StoryObj<typeof NexxtToast>
|
|
17
|
+
|
|
18
|
+
const render = (args: Story['args']) => ({
|
|
19
|
+
components: { NexxtToast },
|
|
20
|
+
setup() {
|
|
21
|
+
const visible = ref(true)
|
|
22
|
+
return { args, visible }
|
|
23
|
+
},
|
|
24
|
+
template: `
|
|
25
|
+
<div style="display: flex; flex-direction: column; align-items: center; gap: 12px; min-height: 80px;">
|
|
26
|
+
<NexxtToast v-if="visible" v-bind="args" @dismiss="visible = false" />
|
|
27
|
+
<div v-else style="display: flex; flex-direction: column; align-items: center; gap: 8px;">
|
|
28
|
+
<span style="font-size: 13px; color: #6b7280;">Toast dismissed by parent</span>
|
|
29
|
+
<button
|
|
30
|
+
style="font-size: 12px; padding: 4px 12px; border-radius: 6px; border: 1px solid #d1d5db; cursor: pointer; background: white;"
|
|
31
|
+
@click="visible = true"
|
|
32
|
+
>
|
|
33
|
+
Reset
|
|
34
|
+
</button>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
`,
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
export const Info: Story = {
|
|
41
|
+
render,
|
|
42
|
+
args: {
|
|
43
|
+
variant: 'info',
|
|
44
|
+
title: 'Nieuwe update beschikbaar',
|
|
45
|
+
message: 'Er is een nieuwe versie beschikbaar. Vernieuw de pagina om bij te werken.',
|
|
46
|
+
},
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const Success: Story = {
|
|
50
|
+
render,
|
|
51
|
+
args: {
|
|
52
|
+
variant: 'success',
|
|
53
|
+
title: 'Opgeslagen',
|
|
54
|
+
message: 'Je wijzigingen zijn succesvol opgeslagen.',
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const Warning: Story = {
|
|
59
|
+
render,
|
|
60
|
+
args: {
|
|
61
|
+
variant: 'warning',
|
|
62
|
+
title: 'Let op',
|
|
63
|
+
message: 'Je sessie verloopt over 5 minuten.',
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const Error: Story = {
|
|
68
|
+
render,
|
|
69
|
+
args: {
|
|
70
|
+
variant: 'error',
|
|
71
|
+
title: 'Er is iets misgegaan',
|
|
72
|
+
message: 'De actie kon niet worden voltooid. Probeer het opnieuw.',
|
|
73
|
+
},
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export const TitleOnly: Story = {
|
|
77
|
+
render,
|
|
78
|
+
args: {
|
|
79
|
+
variant: 'success',
|
|
80
|
+
title: 'Opgeslagen',
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const MessageOnly: Story = {
|
|
85
|
+
render,
|
|
86
|
+
args: {
|
|
87
|
+
variant: 'info',
|
|
88
|
+
message: 'Je wijzigingen zijn succesvol opgeslagen.',
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const NotDismissible: Story = {
|
|
93
|
+
render,
|
|
94
|
+
args: {
|
|
95
|
+
variant: 'warning',
|
|
96
|
+
title: 'Verplichte melding',
|
|
97
|
+
message: 'Deze melding kan niet worden gesloten.',
|
|
98
|
+
dismissible: false,
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const AutoClose: Story = {
|
|
103
|
+
render,
|
|
104
|
+
args: {
|
|
105
|
+
variant: 'success',
|
|
106
|
+
title: 'Opgeslagen',
|
|
107
|
+
message: 'Verdwijnt automatisch na 4 seconden.',
|
|
108
|
+
autoClose: 4000,
|
|
109
|
+
},
|
|
110
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import NexxtToast from './Toast.vue'
|
|
4
|
+
|
|
5
|
+
describe('NexxtToast', () => {
|
|
6
|
+
it('renders title and message', () => {
|
|
7
|
+
const wrapper = mount(NexxtToast, {
|
|
8
|
+
props: { title: 'Opgeslagen', message: 'Je wijzigingen zijn opgeslagen.' },
|
|
9
|
+
})
|
|
10
|
+
expect(wrapper.text()).toContain('Opgeslagen')
|
|
11
|
+
expect(wrapper.text()).toContain('Je wijzigingen zijn opgeslagen.')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('renders only title when no message is provided', () => {
|
|
15
|
+
const wrapper = mount(NexxtToast, { props: { title: 'Alleen titel' } })
|
|
16
|
+
expect(wrapper.findAll('p')).toHaveLength(1)
|
|
17
|
+
expect(wrapper.find('p').text()).toBe('Alleen titel')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('renders only message when no title is provided', () => {
|
|
21
|
+
const wrapper = mount(NexxtToast, { props: { message: 'Alleen bericht' } })
|
|
22
|
+
expect(wrapper.findAll('p')).toHaveLength(1)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('renders slot content', () => {
|
|
26
|
+
const wrapper = mount(NexxtToast, {
|
|
27
|
+
slots: { default: '<span class="custom">Custom content</span>' },
|
|
28
|
+
})
|
|
29
|
+
expect(wrapper.find('.custom').text()).toBe('Custom content')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('emits dismiss when close button is clicked', async () => {
|
|
33
|
+
const wrapper = mount(NexxtToast, { props: { title: 'Test' } })
|
|
34
|
+
await wrapper.find('button').trigger('click')
|
|
35
|
+
expect(wrapper.emitted('dismiss')).toHaveLength(1)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('hides close button when dismissible is false', () => {
|
|
39
|
+
const wrapper = mount(NexxtToast, { props: { title: 'Test', dismissible: false } })
|
|
40
|
+
expect(wrapper.find('button').exists()).toBe(false)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('has role status for non-error variants', () => {
|
|
44
|
+
const wrapper = mount(NexxtToast, { props: { title: 'Test' } })
|
|
45
|
+
expect(wrapper.find('[role="status"]').exists()).toBe(true)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('has role alert for error variant', () => {
|
|
49
|
+
const wrapper = mount(NexxtToast, { props: { variant: 'error', title: 'Test' } })
|
|
50
|
+
expect(wrapper.find('[role="alert"]').exists()).toBe(true)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it.each(['info', 'success', 'warning', 'error'] as const)(
|
|
54
|
+
'renders %s variant with correct toast class',
|
|
55
|
+
(variant) => {
|
|
56
|
+
const wrapper = mount(NexxtToast, { props: { variant, title: 'Test' } })
|
|
57
|
+
const root = wrapper.find('[role="alert"], [role="status"]')
|
|
58
|
+
expect(root.classes()).toContain(`toast-${variant}`)
|
|
59
|
+
},
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
it('shows the SVG timer circle when autoClose is set', () => {
|
|
63
|
+
const wrapper = mount(NexxtToast, { props: { title: 'Test', autoClose: 3000 } })
|
|
64
|
+
expect(wrapper.find('svg').exists()).toBe(true)
|
|
65
|
+
expect(wrapper.find('circle').exists()).toBe(true)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('does not show SVG timer circle without autoClose', () => {
|
|
69
|
+
const wrapper = mount(NexxtToast, { props: { title: 'Test' } })
|
|
70
|
+
expect(wrapper.find('svg').exists()).toBe(false)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('sets the correct animation duration on the timer circle', () => {
|
|
74
|
+
const wrapper = mount(NexxtToast, { props: { title: 'Test', autoClose: 5000 } })
|
|
75
|
+
const circle = wrapper.find('circle')
|
|
76
|
+
expect(circle.attributes('style')).toContain('animation-duration: 5000ms')
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
describe('autoClose timer', () => {
|
|
80
|
+
beforeEach(() => vi.useFakeTimers())
|
|
81
|
+
afterEach(() => vi.useRealTimers())
|
|
82
|
+
|
|
83
|
+
it('emits dismiss after autoClose ms', async () => {
|
|
84
|
+
const wrapper = mount(NexxtToast, { props: { title: 'Test', autoClose: 3000 } })
|
|
85
|
+
expect(wrapper.emitted('dismiss')).toBeFalsy()
|
|
86
|
+
vi.advanceTimersByTime(3000)
|
|
87
|
+
expect(wrapper.emitted('dismiss')).toHaveLength(1)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('does not emit dismiss when autoClose is 0', async () => {
|
|
91
|
+
const wrapper = mount(NexxtToast, { props: { title: 'Test', autoClose: 0 } })
|
|
92
|
+
vi.advanceTimersByTime(10000)
|
|
93
|
+
expect(wrapper.emitted('dismiss')).toBeFalsy()
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('clears the timer on unmount', () => {
|
|
97
|
+
const wrapper = mount(NexxtToast, { props: { title: 'Test', autoClose: 3000 } })
|
|
98
|
+
wrapper.unmount()
|
|
99
|
+
vi.advanceTimersByTime(3000)
|
|
100
|
+
// No error thrown and no emit after unmount
|
|
101
|
+
})
|
|
102
|
+
})
|
|
103
|
+
})
|