@zap-wunschlachen/wl-shared-components 1.0.35 → 1.0.38
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/App.vue +2 -7
- package/package.json +1 -1
- package/src/components/Audio/Waveform.vue +1 -0
- package/src/components/Button/Button.vue +39 -1
- package/src/components/CheckBox/CheckBox.css +29 -0
- package/src/components/CheckBox/Checkbox.vue +10 -2
- package/src/components/Dialog/Dialog.vue +14 -5
- package/src/components/Input/Input.vue +8 -2
- package/src/components/Loader/Loader.css +20 -0
- package/src/components/Loader/Loader.vue +1 -0
- package/src/components/OtpInput/OtpInput.vue +1 -1
- package/src/components/Select/Select.vue +1 -0
- package/src/components/StagingBanner/StagingBanner.css +19 -0
- package/src/components/StagingBanner/StagingBanner.vue +82 -0
- package/src/components/accessibility.css +218 -0
- package/src/components/index.ts +1 -0
- package/tests/unit/accessibility/component-a11y.spec.ts +469 -0
- package/tests/unit/components/Accordion/AccordionGroup.spec.ts +228 -0
- package/tests/unit/components/Accordion/AccordionItem.spec.ts +292 -0
- package/tests/unit/components/Appointment/AnamneseNotification.spec.ts +176 -0
- package/tests/unit/components/Background/Background.spec.ts +177 -0
- package/tests/unit/components/ErrorPage/ErrorPage.spec.ts +313 -0
- package/tests/unit/components/ErrorPage/ErrorPageLogo.spec.ts +153 -0
- package/tests/unit/components/Icons/AdvanceAppointments.spec.ts +61 -0
- package/tests/unit/components/Icons/Logo.spec.ts +228 -0
- package/tests/unit/components/Icons/MiniLogo.spec.ts +38 -0
- package/tests/unit/components/Icons/SolidArrowRight.spec.ts +49 -0
- package/tests/unit/components/Loader/Loader.spec.ts +197 -0
- package/tests/unit/components/MaintenanceBanner/MaintenanceBanner.spec.ts +302 -0
- package/tests/unit/utils/accessibility.spec.ts +318 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import AccordionItem from '@components/Accordion/AccordionItem.vue';
|
|
4
|
+
|
|
5
|
+
describe('AccordionItem', () => {
|
|
6
|
+
describe('Default Behavior', () => {
|
|
7
|
+
it('renders with default props', () => {
|
|
8
|
+
const wrapper = mount(AccordionItem, {
|
|
9
|
+
props: {
|
|
10
|
+
value: 'panel-1'
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
15
|
+
expect(wrapper.vm.title).toBe('Default Title');
|
|
16
|
+
expect(wrapper.vm.text).toBe('Default text');
|
|
17
|
+
expect(wrapper.vm.variant).toBe('outlined');
|
|
18
|
+
expect(wrapper.vm.bgColor).toBe('var(--Soft-Concrete-0)');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('renders with custom title and text', () => {
|
|
22
|
+
const wrapper = mount(AccordionItem, {
|
|
23
|
+
props: {
|
|
24
|
+
value: 'panel-1',
|
|
25
|
+
title: 'Custom Title',
|
|
26
|
+
text: 'Custom content text'
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(wrapper.vm.title).toBe('Custom Title');
|
|
31
|
+
expect(wrapper.vm.text).toBe('Custom content text');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('Props', () => {
|
|
36
|
+
it('accepts and applies variant prop - outlined', () => {
|
|
37
|
+
const wrapper = mount(AccordionItem, {
|
|
38
|
+
props: {
|
|
39
|
+
value: 'panel-1',
|
|
40
|
+
variant: 'outlined'
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
expect(wrapper.vm.variant).toBe('outlined');
|
|
45
|
+
expect(wrapper.find('.outlined-style').exists()).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('accepts and applies variant prop - plain', () => {
|
|
49
|
+
const wrapper = mount(AccordionItem, {
|
|
50
|
+
props: {
|
|
51
|
+
value: 'panel-1',
|
|
52
|
+
variant: 'plain'
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
expect(wrapper.vm.variant).toBe('plain');
|
|
57
|
+
expect(wrapper.find('.plain-style').exists()).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('accepts string value', () => {
|
|
61
|
+
const wrapper = mount(AccordionItem, {
|
|
62
|
+
props: {
|
|
63
|
+
value: 'string-value'
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(wrapper.vm.value).toBe('string-value');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('accepts number value', () => {
|
|
71
|
+
const wrapper = mount(AccordionItem, {
|
|
72
|
+
props: {
|
|
73
|
+
value: 42
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
expect(wrapper.vm.value).toBe(42);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('accepts custom background color', () => {
|
|
81
|
+
const wrapper = mount(AccordionItem, {
|
|
82
|
+
props: {
|
|
83
|
+
value: 'panel-1',
|
|
84
|
+
bgColor: '#FFFFFF'
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(wrapper.vm.bgColor).toBe('#FFFFFF');
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe('Slots', () => {
|
|
93
|
+
it('accepts title slot', () => {
|
|
94
|
+
const wrapper = mount(AccordionItem, {
|
|
95
|
+
props: {
|
|
96
|
+
value: 'panel-1'
|
|
97
|
+
},
|
|
98
|
+
slots: {
|
|
99
|
+
title: '<span class="custom-title">Slot Title</span>'
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(wrapper.find('.custom-title').exists()).toBe(true);
|
|
104
|
+
expect(wrapper.text()).toContain('Slot Title');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('accepts content slot', () => {
|
|
108
|
+
const wrapper = mount(AccordionItem, {
|
|
109
|
+
props: {
|
|
110
|
+
value: 'panel-1'
|
|
111
|
+
},
|
|
112
|
+
slots: {
|
|
113
|
+
content: '<div class="custom-content">Slot Content</div>'
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
expect(wrapper.find('.custom-content').exists()).toBe(true);
|
|
118
|
+
expect(wrapper.text()).toContain('Slot Content');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('uses title prop as default content', () => {
|
|
122
|
+
const wrapper = mount(AccordionItem, {
|
|
123
|
+
props: {
|
|
124
|
+
value: 'panel-1',
|
|
125
|
+
title: 'Prop Title'
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
expect(wrapper.vm.title).toBe('Prop Title');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('uses text prop as default content', () => {
|
|
133
|
+
const wrapper = mount(AccordionItem, {
|
|
134
|
+
props: {
|
|
135
|
+
value: 'panel-1',
|
|
136
|
+
text: 'Prop Text Content'
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
expect(wrapper.vm.text).toBe('Prop Text Content');
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe('Accessibility', () => {
|
|
145
|
+
it('has proper ARIA attributes on trigger and panel', async () => {
|
|
146
|
+
const wrapper = mount(AccordionItem, {
|
|
147
|
+
props: {
|
|
148
|
+
value: 'panel-1',
|
|
149
|
+
title: 'Accessible Title',
|
|
150
|
+
text: 'Test Content'
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Find the interactive trigger (use data-testid or role)
|
|
155
|
+
const trigger = wrapper.find('[data-testid="root"] [role="button"], [data-testid="root"] button, [role="button"]');
|
|
156
|
+
expect(trigger.exists()).toBe(true);
|
|
157
|
+
|
|
158
|
+
// Trigger should expose aria attributes
|
|
159
|
+
const expanded = trigger.attributes('aria-expanded');
|
|
160
|
+
const controls = trigger.attributes('aria-controls');
|
|
161
|
+
const labelled = trigger.attributes('aria-labelledby');
|
|
162
|
+
|
|
163
|
+
expect(expanded).toBeDefined();
|
|
164
|
+
expect(controls).toBeDefined();
|
|
165
|
+
expect(labelled).toBeDefined();
|
|
166
|
+
|
|
167
|
+
// Panel should exist and have role region and matching id
|
|
168
|
+
const panelId = controls || '';
|
|
169
|
+
const panel = panelId ? wrapper.find(`#${panelId}`) : wrapper.find('[role="region"]');
|
|
170
|
+
expect(panel.exists()).toBe(true);
|
|
171
|
+
expect(panel.attributes('role')).toBe('region');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('toggles expanded state via Enter and Space keys and manages focus', async () => {
|
|
175
|
+
const wrapper = mount(AccordionItem, {
|
|
176
|
+
attachTo: document.body,
|
|
177
|
+
props: {
|
|
178
|
+
value: 'panel-1',
|
|
179
|
+
title: 'Accessible Title',
|
|
180
|
+
text: 'Test Content'
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const trigger = wrapper.find('[data-testid="root"] [role="button"], [data-testid="root"] button, [role="button"]');
|
|
185
|
+
expect(trigger.exists()).toBe(true);
|
|
186
|
+
|
|
187
|
+
// Initial state should be collapsed
|
|
188
|
+
expect(trigger.attributes('aria-expanded')).toBe('false');
|
|
189
|
+
|
|
190
|
+
// Press Enter to expand
|
|
191
|
+
await trigger.trigger('keydown.enter');
|
|
192
|
+
await wrapper.vm.$nextTick();
|
|
193
|
+
|
|
194
|
+
expect(trigger.attributes('aria-expanded')).toBe('true');
|
|
195
|
+
|
|
196
|
+
// Focus should remain or move to trigger; ensure trigger is focused
|
|
197
|
+
trigger.element.focus();
|
|
198
|
+
expect(document.activeElement).toBe(trigger.element);
|
|
199
|
+
|
|
200
|
+
// Press Space to collapse
|
|
201
|
+
await trigger.trigger('keydown.space');
|
|
202
|
+
await wrapper.vm.$nextTick();
|
|
203
|
+
|
|
204
|
+
expect(trigger.attributes('aria-expanded')).toBe('false');
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
describe('Edge Cases', () => {
|
|
209
|
+
it('handles empty title', () => {
|
|
210
|
+
const wrapper = mount(AccordionItem, {
|
|
211
|
+
props: {
|
|
212
|
+
value: 'panel-1',
|
|
213
|
+
title: ''
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
expect(wrapper.vm.title).toBe('');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('handles empty text', () => {
|
|
221
|
+
const wrapper = mount(AccordionItem, {
|
|
222
|
+
props: {
|
|
223
|
+
value: 'panel-1',
|
|
224
|
+
text: ''
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(wrapper.vm.text).toBe('');
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('handles very long title text', () => {
|
|
232
|
+
const longTitle = 'A'.repeat(500);
|
|
233
|
+
const wrapper = mount(AccordionItem, {
|
|
234
|
+
props: {
|
|
235
|
+
value: 'panel-1',
|
|
236
|
+
title: longTitle
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
expect(wrapper.vm.title).toBe(longTitle);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('handles special characters in title and text', () => {
|
|
244
|
+
const wrapper = mount(AccordionItem, {
|
|
245
|
+
props: {
|
|
246
|
+
value: 'panel-1',
|
|
247
|
+
title: 'Title with <special> & "characters"',
|
|
248
|
+
text: 'Content with äöü ñ émojis 🎉'
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
expect(wrapper.vm.title).toBe('Title with <special> & "characters"');
|
|
253
|
+
expect(wrapper.vm.text).toBe('Content with äöü ñ émojis 🎉');
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('handles value of 0', () => {
|
|
257
|
+
const wrapper = mount(AccordionItem, {
|
|
258
|
+
props: {
|
|
259
|
+
value: 0
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
expect(wrapper.vm.value).toBe(0);
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
describe('Variant Styling', () => {
|
|
268
|
+
it('applies outlined-style class for outlined variant', () => {
|
|
269
|
+
const wrapper = mount(AccordionItem, {
|
|
270
|
+
props: {
|
|
271
|
+
value: 'panel-1',
|
|
272
|
+
variant: 'outlined'
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
expect(wrapper.find('.outlined-style').exists()).toBe(true);
|
|
277
|
+
expect(wrapper.find('.plain-style').exists()).toBe(false);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
it('applies plain-style class for plain variant', () => {
|
|
281
|
+
const wrapper = mount(AccordionItem, {
|
|
282
|
+
props: {
|
|
283
|
+
value: 'panel-1',
|
|
284
|
+
variant: 'plain'
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
expect(wrapper.find('.plain-style').exists()).toBe(true);
|
|
289
|
+
expect(wrapper.find('.outlined-style').exists()).toBe(false);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
});
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import AnamneseNotification from '@components/Appointment/Card/AnamneseNotification.vue';
|
|
4
|
+
|
|
5
|
+
// Mock vue-i18n
|
|
6
|
+
vi.mock('vue-i18n', () => ({
|
|
7
|
+
useI18n: () => ({
|
|
8
|
+
t: (key: string) => {
|
|
9
|
+
const translations: Record<string, string> = {
|
|
10
|
+
'wl.appointment_card.fill_form_title': 'Bitte füllen Sie das Formular aus',
|
|
11
|
+
'wl.appointment_card.fill_form_description': 'Vor Ihrem Termin bitten wir Sie, den Anamnesebogen auszufüllen.',
|
|
12
|
+
'wl.appointment_card.anamnese_form': 'Anamnesebogen ausfüllen'
|
|
13
|
+
};
|
|
14
|
+
return translations[key] || key;
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
// Mock Button component
|
|
20
|
+
vi.mock('@components/Button/Button.vue', () => ({
|
|
21
|
+
default: {
|
|
22
|
+
name: 'Button',
|
|
23
|
+
template: '<button class="wl-button" @click="$emit(\'click\')">{{ label }}</button>',
|
|
24
|
+
props: ['variant', 'label'],
|
|
25
|
+
emits: ['click']
|
|
26
|
+
}
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
describe('AnamneseNotification', () => {
|
|
30
|
+
describe('Default Behavior', () => {
|
|
31
|
+
it('renders notification container', () => {
|
|
32
|
+
const wrapper = mount(AnamneseNotification);
|
|
33
|
+
expect(wrapper.find('.main-container').exists()).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('renders title text', () => {
|
|
37
|
+
const wrapper = mount(AnamneseNotification);
|
|
38
|
+
expect(wrapper.text()).toContain('Bitte füllen Sie das Formular aus');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('renders description text', () => {
|
|
42
|
+
const wrapper = mount(AnamneseNotification);
|
|
43
|
+
expect(wrapper.text()).toContain('Vor Ihrem Termin bitten wir Sie');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('renders action button', () => {
|
|
47
|
+
const wrapper = mount(AnamneseNotification);
|
|
48
|
+
const button = wrapper.find('.wl-button');
|
|
49
|
+
expect(button.exists()).toBe(true);
|
|
50
|
+
expect(button.text()).toBe('Anamnesebogen ausfüllen');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('Events', () => {
|
|
55
|
+
it('emits fillAnamnese event on button click', async () => {
|
|
56
|
+
const wrapper = mount(AnamneseNotification);
|
|
57
|
+
|
|
58
|
+
const button = wrapper.find('button');
|
|
59
|
+
await button.trigger('click');
|
|
60
|
+
|
|
61
|
+
expect(wrapper.emitted('fillAnamnese')).toBeTruthy();
|
|
62
|
+
expect(wrapper.emitted('fillAnamnese')!.length).toBe(1);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('emits fillAnamnese event multiple times on multiple clicks', async () => {
|
|
66
|
+
const wrapper = mount(AnamneseNotification);
|
|
67
|
+
|
|
68
|
+
const button = wrapper.find('button');
|
|
69
|
+
await button.trigger('click');
|
|
70
|
+
await button.trigger('click');
|
|
71
|
+
await button.trigger('click');
|
|
72
|
+
|
|
73
|
+
expect(wrapper.emitted('fillAnamnese')).toBeTruthy();
|
|
74
|
+
expect(wrapper.emitted('fillAnamnese')!.length).toBe(3);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('Accessibility', () => {
|
|
79
|
+
it('has proper text hierarchy', () => {
|
|
80
|
+
const wrapper = mount(AnamneseNotification);
|
|
81
|
+
|
|
82
|
+
const paragraphs = wrapper.findAll('p');
|
|
83
|
+
expect(paragraphs.length).toBeGreaterThanOrEqual(1);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('has accessible button', () => {
|
|
87
|
+
const wrapper = mount(AnamneseNotification);
|
|
88
|
+
|
|
89
|
+
const button = wrapper.find('button');
|
|
90
|
+
expect(button.exists()).toBe(true);
|
|
91
|
+
expect(button.text()).toBeTruthy();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('provides meaningful content for screen readers', () => {
|
|
95
|
+
const wrapper = mount(AnamneseNotification);
|
|
96
|
+
|
|
97
|
+
// Title should be clear
|
|
98
|
+
expect(wrapper.text()).toContain('Bitte füllen Sie das Formular aus');
|
|
99
|
+
|
|
100
|
+
// Description should provide context
|
|
101
|
+
expect(wrapper.text()).toContain('Anamnesebogen');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('has proper text container structure', () => {
|
|
105
|
+
const wrapper = mount(AnamneseNotification);
|
|
106
|
+
|
|
107
|
+
expect(wrapper.find('.text-container').exists()).toBe(true);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('description has smaller text class', () => {
|
|
111
|
+
const wrapper = mount(AnamneseNotification);
|
|
112
|
+
|
|
113
|
+
expect(wrapper.find('.p-small').exists()).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('Visual Structure', () => {
|
|
118
|
+
it('has main container', () => {
|
|
119
|
+
const wrapper = mount(AnamneseNotification);
|
|
120
|
+
expect(wrapper.find('.main-container').exists()).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('has text container', () => {
|
|
124
|
+
const wrapper = mount(AnamneseNotification);
|
|
125
|
+
expect(wrapper.find('.text-container').exists()).toBe(true);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('button is outside text container', () => {
|
|
129
|
+
const wrapper = mount(AnamneseNotification);
|
|
130
|
+
|
|
131
|
+
const textContainer = wrapper.find('.text-container');
|
|
132
|
+
const button = textContainer.find('button');
|
|
133
|
+
|
|
134
|
+
// Button should not be inside text container
|
|
135
|
+
expect(button.exists()).toBe(false);
|
|
136
|
+
|
|
137
|
+
// But should exist in main container
|
|
138
|
+
expect(wrapper.find('button').exists()).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('uses translation for title', () => {
|
|
143
|
+
const wrapper = mount(AnamneseNotification);
|
|
144
|
+
|
|
145
|
+
const paragraphs = wrapper.findAll('p');
|
|
146
|
+
expect(paragraphs.length).toBeGreaterThan(0);
|
|
147
|
+
expect(paragraphs[0].text()).toBe('Bitte füllen Sie das Formular aus');
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('uses translation for description', () => {
|
|
152
|
+
const wrapper = mount(AnamneseNotification);
|
|
153
|
+
|
|
154
|
+
const smallP = wrapper.find('.p-small');
|
|
155
|
+
expect(smallP.text()).toContain('Anamnesebogen');
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('uses translation for button label', () => {
|
|
159
|
+
const wrapper = mount(AnamneseNotification);
|
|
160
|
+
|
|
161
|
+
const button = wrapper.find('.wl-button');
|
|
162
|
+
expect(button.text()).toBe('Anamnesebogen ausfüllen');
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
describe('Button Configuration', () => {
|
|
167
|
+
it('button has outlined variant', () => {
|
|
168
|
+
const wrapper = mount(AnamneseNotification);
|
|
169
|
+
|
|
170
|
+
// Button component receives variant prop
|
|
171
|
+
const buttonComponent = wrapper.findComponent({ name: 'Button' });
|
|
172
|
+
expect(buttonComponent.exists()).toBe(true);
|
|
173
|
+
expect(buttonComponent.props('variant')).toBe('outlined');
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import Background from '@components/Background/Background.vue';
|
|
4
|
+
|
|
5
|
+
// Mock siteColors
|
|
6
|
+
vi.mock('@/utils/index', () => ({
|
|
7
|
+
siteColors: {
|
|
8
|
+
domain: 'domain-dental'
|
|
9
|
+
}
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
// Mock child background components
|
|
13
|
+
vi.mock('@components/Background/WunschlachenBackground.vue', () => ({
|
|
14
|
+
default: {
|
|
15
|
+
name: 'WunschlachenBackground',
|
|
16
|
+
template: '<svg class="wunschlachen-background"></svg>'
|
|
17
|
+
}
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
vi.mock('@components/Background/WhiteCocoonBackground.vue', () => ({
|
|
21
|
+
default: {
|
|
22
|
+
name: 'WhiteCocoonBackground',
|
|
23
|
+
template: '<svg class="white-cocoon-background"></svg>'
|
|
24
|
+
}
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
describe('Background', () => {
|
|
28
|
+
describe('Default Behavior', () => {
|
|
29
|
+
it('renders background container', () => {
|
|
30
|
+
const wrapper = mount(Background);
|
|
31
|
+
expect(wrapper.find('.background').exists()).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('has background__content wrapper', () => {
|
|
35
|
+
const wrapper = mount(Background);
|
|
36
|
+
expect(wrapper.find('.background__content').exists()).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('renders background SVG', () => {
|
|
40
|
+
const wrapper = mount(Background);
|
|
41
|
+
expect(wrapper.find('.background__svg').exists()).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('Domain-specific Rendering', () => {
|
|
46
|
+
it('renders WunschlachenBackground for dental domain', () => {
|
|
47
|
+
const wrapper = mount(Background);
|
|
48
|
+
|
|
49
|
+
expect(wrapper.find('.wunschlachen-background').exists()).toBe(true);
|
|
50
|
+
expect(wrapper.find('.white-cocoon-background').exists()).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('does not have cocoon modifier class for dental domain', () => {
|
|
54
|
+
const wrapper = mount(Background);
|
|
55
|
+
expect(wrapper.find('.background--cocoon').exists()).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('Slots', () => {
|
|
60
|
+
it('renders default slot content', () => {
|
|
61
|
+
const wrapper = mount(Background, {
|
|
62
|
+
slots: {
|
|
63
|
+
default: '<div class="test-content">Test Content</div>'
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
expect(wrapper.find('.test-content').exists()).toBe(true);
|
|
68
|
+
expect(wrapper.find('.test-content').text()).toBe('Test Content');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('renders multiple slot elements', () => {
|
|
72
|
+
const wrapper = mount(Background, {
|
|
73
|
+
slots: {
|
|
74
|
+
default: `
|
|
75
|
+
<header class="slot-header">Header</header>
|
|
76
|
+
<main class="slot-main">Main Content</main>
|
|
77
|
+
<footer class="slot-footer">Footer</footer>
|
|
78
|
+
`
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
expect(wrapper.find('.slot-header').exists()).toBe(true);
|
|
83
|
+
expect(wrapper.find('.slot-main').exists()).toBe(true);
|
|
84
|
+
expect(wrapper.find('.slot-footer').exists()).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('preserves slot content structure', () => {
|
|
88
|
+
const wrapper = mount(Background, {
|
|
89
|
+
slots: {
|
|
90
|
+
default: '<div class="nested"><span class="inner">Nested Content</span></div>'
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
expect(wrapper.find('.nested .inner').exists()).toBe(true);
|
|
95
|
+
expect(wrapper.find('.inner').text()).toBe('Nested Content');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('Accessibility', () => {
|
|
100
|
+
it('slot content is accessible within background', () => {
|
|
101
|
+
const wrapper = mount(Background, {
|
|
102
|
+
slots: {
|
|
103
|
+
default: '<main role="main"><h1>Accessible Content</h1></main>'
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
expect(wrapper.find('[role="main"]').exists()).toBe(true);
|
|
108
|
+
expect(wrapper.find('h1').text()).toBe('Accessible Content');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('background SVG does not interfere with content accessibility', () => {
|
|
112
|
+
const wrapper = mount(Background, {
|
|
113
|
+
slots: {
|
|
114
|
+
default: '<button class="test-button">Click Me</button>'
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Content should be in background__content, separate from background SVG
|
|
119
|
+
const content = wrapper.find('.background__content');
|
|
120
|
+
expect(content.find('.test-button').exists()).toBe(true);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('maintains proper z-index layering for content', () => {
|
|
124
|
+
const wrapper = mount(Background, {
|
|
125
|
+
slots: {
|
|
126
|
+
default: '<div class="foreground-content">Foreground</div>'
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Content should be separate from background SVG
|
|
131
|
+
const svg = wrapper.find('.background__svg');
|
|
132
|
+
const content = wrapper.find('.background__content');
|
|
133
|
+
|
|
134
|
+
expect(svg.exists()).toBe(true);
|
|
135
|
+
expect(content.exists()).toBe(true);
|
|
136
|
+
expect(content.find('.foreground-content').exists()).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
describe('Visual Structure', () => {
|
|
141
|
+
it('has proper class structure', () => {
|
|
142
|
+
const wrapper = mount(Background);
|
|
143
|
+
|
|
144
|
+
expect(wrapper.find('.background').exists()).toBe(true);
|
|
145
|
+
expect(wrapper.find('.background__svg').exists()).toBe(true);
|
|
146
|
+
expect(wrapper.find('.background__content').exists()).toBe(true);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('SVG is positioned as background element', () => {
|
|
150
|
+
const wrapper = mount(Background);
|
|
151
|
+
|
|
152
|
+
const backgroundEl = wrapper.find('.background');
|
|
153
|
+
const svgEl = wrapper.find('.background__svg');
|
|
154
|
+
|
|
155
|
+
expect(backgroundEl.element.contains(svgEl.element)).toBe(true);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('Edge Cases', () => {
|
|
160
|
+
it('renders correctly with no slot content', () => {
|
|
161
|
+
const wrapper = mount(Background);
|
|
162
|
+
|
|
163
|
+
expect(wrapper.find('.background').exists()).toBe(true);
|
|
164
|
+
expect(wrapper.find('.background__content').exists()).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('handles empty string slot content', () => {
|
|
168
|
+
const wrapper = mount(Background, {
|
|
169
|
+
slots: {
|
|
170
|
+
default: ''
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
expect(wrapper.find('.background').exists()).toBe(true);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
});
|