@zap-wunschlachen/wl-shared-components 1.0.12 → 1.0.13
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/.github/workflows/playwright.yml +205 -205
- package/.github/workflows/static.yml +61 -61
- package/.github/workflows/update-snapshots.yml +37 -37
- package/.prettierrc +5 -5
- package/.storybook/main.ts +18 -18
- package/.storybook/preview.ts +37 -37
- package/.storybook/storyWrapper.vue +18 -18
- package/.storybook/withVuetifyTheme.decorator.ts +21 -21
- package/App.vue +147 -147
- package/README.md +56 -56
- package/heroicons.ts +75 -75
- package/index.html +19 -19
- package/package.json +67 -67
- package/playwright.config.ts +48 -48
- package/public/background.svg +60 -60
- package/public/style.css +187 -187
- package/public/technologies.svg +22 -22
- package/src/assets/css/base.css +235 -235
- package/src/assets/css/variables.css +96 -96
- package/src/components/Accordion/Accordion.css +59 -59
- package/src/components/Accordion/AccordionGroup.vue +51 -51
- package/src/components/Accordion/AccordionItem.vue +66 -66
- package/src/components/Appointment/Card/Actions.css +28 -28
- package/src/components/Appointment/Card/Actions.vue +72 -72
- package/src/components/Appointment/Card/Card.css +80 -80
- package/src/components/Appointment/Card/Card.vue +87 -81
- package/src/components/Appointment/Card/Details.css +50 -50
- package/src/components/Appointment/Card/Details.vue +43 -43
- package/src/components/Audio/Audio.vue +187 -187
- package/src/components/Audio/Waveform.vue +117 -117
- package/src/components/Button/Button.vue +119 -119
- package/src/components/CheckBox/CheckBox.css +185 -185
- package/src/components/CheckBox/Checkbox.vue +130 -130
- package/src/components/DateInput/DateInput.css +2 -2
- package/src/components/DateInput/DateInput.vue +262 -262
- package/src/components/Dialog/Dialog.css +6 -6
- package/src/components/Dialog/Dialog.vue +29 -29
- package/src/components/EditField/EditField.css +19 -19
- package/src/components/EditField/EditField.vue +202 -202
- package/src/components/IconBullet/IconBullet.vue +86 -86
- package/src/components/IconBullet/IconBulletList.vue +41 -41
- package/src/components/Icons/AdvanceAppointments.vue +153 -153
- package/src/components/Icons/Audio/CloudFailed.vue +20 -20
- package/src/components/Icons/Audio/CloudSaved.vue +21 -21
- package/src/components/Icons/Audio/Delete.vue +15 -15
- package/src/components/Icons/Audio/Pause.vue +18 -18
- package/src/components/Icons/Audio/Play.vue +15 -15
- package/src/components/Icons/CalendarNotification.vue +126 -126
- package/src/components/Icons/Chair.vue +32 -32
- package/src/components/Icons/ChairNotification.vue +35 -35
- package/src/components/Icons/Circle.vue +66 -66
- package/src/components/Icons/FavIcon.vue +22 -22
- package/src/components/Icons/FilledCircle.vue +11 -11
- package/src/components/Icons/Group3.vue +46 -46
- package/src/components/Icons/RingNotification.vue +54 -54
- package/src/components/Icons/SolidArrowRight.vue +14 -14
- package/src/components/Icons/calendar.vue +17 -17
- package/src/components/Icons/checkbox.vue +19 -19
- package/src/components/Icons/outlineChecked.vue +27 -27
- package/src/components/Icons/play.vue +5 -5
- package/src/components/Input/Input.css +187 -187
- package/src/components/Input/Input.vue +247 -247
- package/src/components/Laboratory/AppointmentCard/AppointmentCard.css +7 -7
- package/src/components/Laboratory/AppointmentCard/AppointmentCard.vue +116 -116
- package/src/components/Laboratory/ChatBoxImage/ChatBoxImage.vue +81 -81
- package/src/components/Laboratory/ChatMessage/ChatMessage.vue +113 -113
- package/src/components/Laboratory/ChatMessage/ChatMessageBadge.css +4 -4
- package/src/components/Laboratory/ChatMessage/ChatMessageBadge.vue +99 -99
- package/src/components/Laboratory/ChatNotification/ChatNotification.vue +130 -130
- package/src/components/Laboratory/DocumentCard/DocumentCard.css +3 -3
- package/src/components/Laboratory/DocumentCard/DocumentCard.vue +50 -50
- package/src/components/Laboratory/DocumentCard/DocumentCardItem.vue +53 -53
- package/src/components/Laboratory/InfoCard/InfoCard.vue +162 -162
- package/src/components/Laboratory/MainColumnsBar/MainColumnsBar.vue +102 -102
- package/src/components/Laboratory/ProgressCircle/ProgressCircle.vue +152 -152
- package/src/components/Laboratory/ProgressLinear/ProgressLinear.css +33 -33
- package/src/components/Laboratory/ProgressLinear/ProgressLinear.vue +75 -75
- package/src/components/Laboratory/SelectionColumnBar/SelectionColumnBar.vue +92 -92
- package/src/components/Laboratory/StatusNotification/StatusNotification.vue +49 -49
- package/src/components/Laboratory/TagLabel/TagLabel.vue +126 -126
- package/src/components/Laboratory/TagLabelGroup/TagLabelGroup.vue +97 -97
- package/src/components/Laboratory/TicketCard/TicketCard.css +3 -3
- package/src/components/Laboratory/TicketCard/TicketCard.vue +143 -143
- package/src/components/Laboratory/TimeLine/TimeLineEvent.css +18 -18
- package/src/components/Laboratory/TimeLine/TimeLineEvent.vue +119 -119
- package/src/components/Laboratory/TimeLine/Timeline.css +4 -4
- package/src/components/Laboratory/TimeLine/Timeline.vue +30 -30
- package/src/components/Modal/Modal.css +5 -5
- package/src/components/Modal/Modal.vue +22 -22
- package/src/components/NotificationBubble/NotificationBubble.css +4 -4
- package/src/components/NotificationBubble/NotificationBubble.vue +90 -90
- package/src/components/OtpInput/OtpInput.css +39 -39
- package/src/components/OtpInput/OtpInput.vue +143 -143
- package/src/components/PhoneInput/PhoneInput.css +31 -31
- package/src/components/PhoneInput/PhoneInput.vue +113 -113
- package/src/components/Select/Select.css +150 -150
- package/src/components/Select/Select.vue +304 -304
- package/src/components/TextArea/TextArea.css +3 -3
- package/src/components/TextArea/TextArea.vue +126 -126
- package/src/components/TickBox/TickBox.css +49 -49
- package/src/components/TickBox/TickBox.vue +126 -126
- package/src/components/index.ts +22 -22
- package/src/constants/iconEnums.ts +3 -3
- package/src/i18n/i18n.ts +15 -15
- package/src/i18n/locales/de.json +27 -27
- package/src/i18n/locales/en.json +27 -27
- package/src/index.ts +31 -31
- package/src/main.ts +11 -11
- package/src/plugins/vuetify.ts +131 -131
- package/src/shims-vue.d.ts +10 -10
- package/src/stories/Accordion.stories.ts +650 -650
- package/src/stories/Audio.stories.ts +28 -28
- package/src/stories/Button.stories.ts +263 -263
- package/src/stories/CheckBox.stories.ts +348 -348
- package/src/stories/DateInput.stories.ts +53 -53
- package/src/stories/Dialog.stories.ts +147 -147
- package/src/stories/EditField.stories.ts +78 -78
- package/src/stories/IconBullet/IconBullet.stories.ts +201 -201
- package/src/stories/IconBullet/IconBulletList.stories.ts +275 -275
- package/src/stories/Input.stories.ts +351 -351
- package/src/stories/Laboratory/Cards/AppointmentCard/AppointmentCard.stories.ts +260 -260
- package/src/stories/Laboratory/Cards/DocumentCard/DocumentCard.stories.ts +176 -176
- package/src/stories/Laboratory/Cards/DocumentCard/DocumentCardItem.stories.ts +119 -119
- package/src/stories/Laboratory/Cards/InfoCard/InfoCard.stories.ts +320 -320
- package/src/stories/Laboratory/Cards/TicketCard/TicketCard.stories.ts +335 -335
- package/src/stories/Laboratory/Chat/ChatBoxImage.stories.ts +82 -82
- package/src/stories/Laboratory/Chat/ChatMessage.stories.ts +198 -198
- package/src/stories/Laboratory/Chat/ChatMessageBadge.stories.ts +204 -204
- package/src/stories/Laboratory/Chat/ChatNotification.stories.ts +144 -144
- package/src/stories/Laboratory/Chat/ProgressLinear.stories.ts +186 -186
- package/src/stories/Laboratory/Chat/StatusNotification.stories.ts +111 -111
- package/src/stories/Laboratory/MainColumnsBar.stories.ts +48 -48
- package/src/stories/Laboratory/ProgressCircle.stories.ts +261 -261
- package/src/stories/Laboratory/SelectionColumnBar.stories.ts +234 -234
- package/src/stories/Laboratory/TagLabel.stories.ts +418 -418
- package/src/stories/Laboratory/TagLabelGroup.stories.ts +234 -234
- package/src/stories/Laboratory/Timeline.stories.ts +403 -403
- package/src/stories/NotificationBubble.stories.ts +194 -194
- package/src/stories/OtpInput.stories.ts +100 -100
- package/src/stories/PhoneInput.stories.ts +52 -52
- package/src/stories/Select.stories.ts +419 -419
- package/src/stories/TextArea.stories.ts +112 -112
- package/src/stories/TickBox.stories.ts +294 -294
- package/src/stories/v-icon.stories.ts +91 -91
- package/src/utils/index.ts +41 -41
- package/src/vite-env.d.ts +1 -1
- package/tests/e2e/README.md +220 -220
- package/tests/e2e/accessibility.spec.ts +638 -638
- package/tests/e2e/accordion.spec.ts +42 -42
- package/tests/e2e/additional-components.spec.ts +437 -437
- package/tests/e2e/all-components.spec.ts +135 -135
- package/tests/e2e/appointment-card.spec.ts +816 -816
- package/tests/e2e/button-fixed.spec.ts +58 -58
- package/tests/e2e/button.spec.ts +76 -76
- package/tests/e2e/checkbox.spec.ts +50 -50
- package/tests/e2e/date-input.spec.ts +46 -46
- package/tests/e2e/debug.spec.ts +51 -51
- package/tests/e2e/dialog.spec.ts +58 -58
- package/tests/e2e/input.spec.ts +55 -55
- package/tests/e2e/laboratory-components.spec.ts +320 -320
- package/tests/e2e/otp-input.spec.ts +50 -50
- package/tests/e2e/select.spec.ts +52 -52
- package/tests/e2e/storybook-utils.ts +59 -59
- package/tests/e2e/test-basic.spec.ts +33 -33
- package/tests/e2e/visual-regression.spec.ts +350 -350
- package/tests/unit/components/Accordion/AccordionGroup.spec.ts.skip +342 -342
- package/tests/unit/components/Accordion/AccordionItem.spec.ts.skip +383 -383
- package/tests/unit/components/Appointment/Card/Actions.spec.ts +407 -407
- package/tests/unit/components/Appointment/Card/Card.spec.ts +485 -485
- package/tests/unit/components/Appointment/Card/Details.spec.ts +397 -397
- package/tests/unit/components/Audio/Audio.spec.ts +403 -403
- package/tests/unit/components/Audio/Waveform.spec.ts +483 -483
- package/tests/unit/components/Core/Button.spec.ts +336 -336
- package/tests/unit/components/Core/Checkbox.spec.ts +544 -544
- package/tests/unit/components/Core/DateInput.spec.ts +690 -690
- package/tests/unit/components/Core/Dialog.spec.ts +485 -485
- package/tests/unit/components/Core/EditField.spec.ts +782 -782
- package/tests/unit/components/Core/Input.spec.ts +512 -512
- package/tests/unit/components/Core/Modal.spec.ts +518 -518
- package/tests/unit/components/Core/NotificationBubble.spec.ts +606 -606
- package/tests/unit/components/Core/OtpInput.spec.ts +708 -708
- package/tests/unit/components/Core/PhoneInput.spec.ts +619 -619
- package/tests/unit/components/Core/Select.spec.ts +712 -712
- package/tests/unit/components/Core/TextArea.spec.ts +565 -565
- package/tests/unit/components/Core/TickBox.spec.ts +779 -779
- package/tests/unit/components/IconBullet/IconBullet.spec.ts +356 -356
- package/tests/unit/components/IconBullet/IconBulletList.spec.ts +371 -371
- package/tests/unit/components/Icons/Audio/CloudFailed.spec.ts +108 -108
- package/tests/unit/components/Icons/Audio/CloudSaved.spec.ts +149 -149
- package/tests/unit/components/Icons/Audio/Delete.spec.ts +158 -158
- package/tests/unit/components/Icons/Audio/Pause.spec.ts +208 -208
- package/tests/unit/components/Icons/Audio/Play.spec.ts +217 -217
- package/tests/unit/components/Icons/CalendarNotification.spec.ts +186 -186
- package/tests/unit/components/Icons/Chair.spec.ts +234 -234
- package/tests/unit/components/Icons/ChairNotification.spec.ts +311 -311
- package/tests/unit/components/Icons/Circle.spec.ts +255 -255
- package/tests/unit/components/Icons/FavIcon.spec.ts +251 -251
- package/tests/unit/components/Icons/FilledCircle.spec.ts +274 -274
- package/tests/unit/components/Icons/Group3.spec.ts +355 -355
- package/tests/unit/components/Icons/RingNotification.spec.ts +393 -393
- package/tests/unit/components/Icons/calendar.spec.ts +286 -286
- package/tests/unit/components/Icons/checkbox.spec.ts +315 -315
- package/tests/unit/components/Icons/outlineChecked.spec.ts +434 -434
- package/tests/unit/components/Icons/play.spec.ts +308 -308
- package/tests/unit/components/Laboratory/AppointmentCard.spec.ts +167 -167
- package/tests/unit/components/Laboratory/ChatBoxImage.spec.ts +179 -179
- package/tests/unit/components/Laboratory/ChatMessage.spec.ts +263 -263
- package/tests/unit/components/Laboratory/ChatMessageBadge.spec.ts +282 -282
- package/tests/unit/components/Laboratory/ChatNotification.spec.ts +256 -256
- package/tests/unit/components/Laboratory/DocumentCard.spec.ts +228 -228
- package/tests/unit/components/Laboratory/DocumentCardItem.spec.ts +236 -236
- package/tests/unit/components/Laboratory/InfoCard.spec.ts +308 -308
- package/tests/unit/components/Laboratory/MainColumnsBar.spec.ts +251 -251
- package/tests/unit/components/Laboratory/ProgressCircle.spec.ts +290 -290
- package/tests/unit/components/Laboratory/ProgressLinear.spec.ts +275 -275
- package/tests/unit/components/Laboratory/SelectionColumnBar.spec.ts +288 -288
- package/tests/unit/components/Laboratory/StatusNotification.spec.ts +296 -296
- package/tests/unit/components/Laboratory/TagLabel.spec.ts +353 -353
- package/tests/unit/components/Laboratory/TagLabelGroup.spec.ts +377 -377
- package/tests/unit/components/Laboratory/TicketCard.spec.ts +351 -351
- package/tests/unit/components/Laboratory/TimeLineEvent.spec.ts +381 -381
- package/tests/unit/components/Laboratory/Timeline.spec.ts +419 -419
- package/tests/unit/constants/iconEnums.spec.ts +39 -39
- package/tests/unit/i18n/i18n.spec.ts +88 -88
- package/tests/unit/plugins/vuetify.spec.ts +220 -220
- package/tests/unit/setup.ts +189 -189
- package/tests/unit/src/components/index.spec.ts.skip +192 -192
- package/tests/unit/src/index.spec.ts.skip +182 -182
- package/tests/unit/src/main.spec.ts +151 -151
- package/tsconfig.json +26 -26
- package/vite.config.ts +29 -29
- package/vitest.config.ts +83 -83
|
@@ -1,309 +1,309 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { mount } from '@vue/test-utils';
|
|
3
|
-
import Play from '@components/Icons/play.vue';
|
|
4
|
-
|
|
5
|
-
describe('Play Icon', () => {
|
|
6
|
-
describe('Rendering', () => {
|
|
7
|
-
it('renders as SVG element', () => {
|
|
8
|
-
const wrapper = mount(Play);
|
|
9
|
-
expect(wrapper.find('svg').exists()).toBe(true);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('has correct SVG attributes', () => {
|
|
13
|
-
const wrapper = mount(Play);
|
|
14
|
-
const svg = wrapper.find('svg');
|
|
15
|
-
|
|
16
|
-
expect(svg.attributes('xmlns')).toBe('http://www.w3.org/2000/svg');
|
|
17
|
-
expect(svg.attributes('width')).toBe('24');
|
|
18
|
-
expect(svg.attributes('height')).toBe('24');
|
|
19
|
-
expect(svg.attributes('viewBox')).toBe('0 0 24 24');
|
|
20
|
-
expect(svg.attributes('fill')).toBe('none');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('contains exactly 2 path elements', () => {
|
|
24
|
-
const wrapper = mount(Play);
|
|
25
|
-
const paths = wrapper.findAll('path');
|
|
26
|
-
expect(paths).toHaveLength(2);
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe('Path Structure', () => {
|
|
31
|
-
it('first path represents circle background', () => {
|
|
32
|
-
const wrapper = mount(Play);
|
|
33
|
-
const paths = wrapper.findAll('path');
|
|
34
|
-
|
|
35
|
-
const circlePath = paths[0];
|
|
36
|
-
expect(circlePath.attributes('d')).toContain('M21 12C21 16.9706');
|
|
37
|
-
expect(circlePath.attributes('stroke')).toBe('#172774');
|
|
38
|
-
expect(circlePath.attributes('stroke-width')).toBe('1.5');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('second path represents play triangle', () => {
|
|
42
|
-
const wrapper = mount(Play);
|
|
43
|
-
const paths = wrapper.findAll('path');
|
|
44
|
-
|
|
45
|
-
const trianglePath = paths[1];
|
|
46
|
-
expect(trianglePath.attributes('d')).toContain('M15.9099 11.6722');
|
|
47
|
-
expect(trianglePath.attributes('stroke')).toBe('#172774');
|
|
48
|
-
expect(trianglePath.attributes('stroke-width')).toBe('1.5');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('circle path forms complete circle', () => {
|
|
52
|
-
const wrapper = mount(Play);
|
|
53
|
-
const paths = wrapper.findAll('path');
|
|
54
|
-
|
|
55
|
-
const circlePath = paths[0];
|
|
56
|
-
const pathData = circlePath.attributes('d');
|
|
57
|
-
|
|
58
|
-
// Should contain circle definition with center at 12,12 and radius 9
|
|
59
|
-
expect(pathData).toContain('21 12C21 16.9706'); // Right side
|
|
60
|
-
expect(pathData).toContain('16.9706 21 12 21'); // Bottom
|
|
61
|
-
expect(pathData).toContain('7.02944 21 3 16.9706'); // Left side
|
|
62
|
-
expect(pathData).toContain('3 12C3 7.02944'); // Top
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('triangle path forms play arrow', () => {
|
|
66
|
-
const wrapper = mount(Play);
|
|
67
|
-
const paths = wrapper.findAll('path');
|
|
68
|
-
|
|
69
|
-
const trianglePath = paths[1];
|
|
70
|
-
const pathData = trianglePath.attributes('d');
|
|
71
|
-
|
|
72
|
-
// Should contain triangle vertices
|
|
73
|
-
expect(pathData).toContain('15.9099 11.6722'); // Right point
|
|
74
|
-
expect(pathData).toContain('10.3071 15.4405'); // Bottom left
|
|
75
|
-
expect(pathData).toContain('9.75 15.1127'); // Bottom edge
|
|
76
|
-
expect(pathData).toContain('8.88732C9.75 8.60139'); // Top edge
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
describe('Visual Properties', () => {
|
|
81
|
-
it('all strokes use correct brand color', () => {
|
|
82
|
-
const wrapper = mount(Play);
|
|
83
|
-
const paths = wrapper.findAll('path');
|
|
84
|
-
|
|
85
|
-
paths.forEach(path => {
|
|
86
|
-
expect(path.attributes('stroke')).toBe('#172774');
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('all paths have correct stroke width', () => {
|
|
91
|
-
const wrapper = mount(Play);
|
|
92
|
-
const paths = wrapper.findAll('path');
|
|
93
|
-
|
|
94
|
-
paths.forEach(path => {
|
|
95
|
-
expect(path.attributes('stroke-width')).toBe('1.5');
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('all paths have rounded line caps and joins', () => {
|
|
100
|
-
const wrapper = mount(Play);
|
|
101
|
-
const paths = wrapper.findAll('path');
|
|
102
|
-
|
|
103
|
-
paths.forEach(path => {
|
|
104
|
-
expect(path.attributes('stroke-linecap')).toBe('round');
|
|
105
|
-
expect(path.attributes('stroke-linejoin')).toBe('round');
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('paths have no fill (outline style)', () => {
|
|
110
|
-
const wrapper = mount(Play);
|
|
111
|
-
const svg = wrapper.find('svg');
|
|
112
|
-
|
|
113
|
-
expect(svg.attributes('fill')).toBe('none');
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
describe('Play Button Geometry', () => {
|
|
118
|
-
it('circle is centered in viewBox', () => {
|
|
119
|
-
const wrapper = mount(Play);
|
|
120
|
-
const paths = wrapper.findAll('path');
|
|
121
|
-
|
|
122
|
-
const circlePath = paths[0];
|
|
123
|
-
const pathData = circlePath.attributes('d');
|
|
124
|
-
|
|
125
|
-
// Circle centered at 12,12 with radius 9
|
|
126
|
-
expect(pathData).toContain('12C21 16.9706'); // Center coordinates
|
|
127
|
-
expect(pathData).toContain('21 12 21C7.02944'); // Center coordinates
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('play triangle is centered horizontally', () => {
|
|
131
|
-
const wrapper = mount(Play);
|
|
132
|
-
const paths = wrapper.findAll('path');
|
|
133
|
-
|
|
134
|
-
const trianglePath = paths[1];
|
|
135
|
-
const pathData = trianglePath.attributes('d');
|
|
136
|
-
|
|
137
|
-
// Triangle should be centered around x=12
|
|
138
|
-
expect(pathData).toContain('15.9099'); // Right point
|
|
139
|
-
expect(pathData).toContain('10.3071'); // Left side
|
|
140
|
-
expect(pathData).toContain('9.75'); // Left edge
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('play triangle points to the right', () => {
|
|
144
|
-
const wrapper = mount(Play);
|
|
145
|
-
const paths = wrapper.findAll('path');
|
|
146
|
-
|
|
147
|
-
const trianglePath = paths[1];
|
|
148
|
-
const pathData = trianglePath.attributes('d');
|
|
149
|
-
|
|
150
|
-
// Right-pointing triangle
|
|
151
|
-
expect(pathData).toMatch(/15\.9099.*11\.6722/); // Right point
|
|
152
|
-
expect(pathData).toMatch(/10\.3071.*15\.4405/); // Bottom left
|
|
153
|
-
expect(pathData).toMatch(/8\.88732/); // Top left
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('maintains proper play button proportions', () => {
|
|
157
|
-
const wrapper = mount(Play);
|
|
158
|
-
const svg = wrapper.find('svg');
|
|
159
|
-
|
|
160
|
-
// Standard play button is square
|
|
161
|
-
expect(svg.attributes('width')).toBe(svg.attributes('height'));
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
describe('Component Structure', () => {
|
|
166
|
-
it('uses standard 24x24 size', () => {
|
|
167
|
-
const wrapper = mount(Play);
|
|
168
|
-
const svg = wrapper.find('svg');
|
|
169
|
-
|
|
170
|
-
expect(svg.attributes('width')).toBe('24');
|
|
171
|
-
expect(svg.attributes('height')).toBe('24');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('suitable for media control usage', () => {
|
|
175
|
-
const wrapper = mount(Play);
|
|
176
|
-
const paths = wrapper.findAll('path');
|
|
177
|
-
|
|
178
|
-
// Circle + triangle is standard play button design
|
|
179
|
-
expect(paths).toHaveLength(2);
|
|
180
|
-
expect(paths[0].attributes('d')).toContain('12C21'); // Circle
|
|
181
|
-
expect(paths[1].attributes('d')).toContain('15.9099'); // Triangle
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
describe('Accessibility', () => {
|
|
186
|
-
it('svg is properly structured for screen readers', () => {
|
|
187
|
-
const wrapper = mount(Play);
|
|
188
|
-
const svg = wrapper.find('svg');
|
|
189
|
-
|
|
190
|
-
expect(svg.element.tagName.toLowerCase()).toBe('svg');
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('uses clear outline style for visibility', () => {
|
|
194
|
-
const wrapper = mount(Play);
|
|
195
|
-
const paths = wrapper.findAll('path');
|
|
196
|
-
|
|
197
|
-
// Outline style with good contrast
|
|
198
|
-
paths.forEach(path => {
|
|
199
|
-
expect(path.attributes('stroke')).toBe('#172774');
|
|
200
|
-
expect(path.attributes('stroke-width')).toBe('1.5');
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
describe('Component Integration', () => {
|
|
206
|
-
it('can be mounted without props', () => {
|
|
207
|
-
expect(() => {
|
|
208
|
-
mount(Play);
|
|
209
|
-
}).not.toThrow();
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it('renders consistently on multiple mounts', () => {
|
|
213
|
-
const wrapper1 = mount(Play);
|
|
214
|
-
const wrapper2 = mount(Play);
|
|
215
|
-
|
|
216
|
-
expect(wrapper1.html()).toBe(wrapper2.html());
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
it('maintains play button structure integrity', () => {
|
|
220
|
-
const wrapper = mount(Play);
|
|
221
|
-
const paths = wrapper.findAll('path');
|
|
222
|
-
|
|
223
|
-
expect(paths).toHaveLength(2);
|
|
224
|
-
paths.forEach(path => {
|
|
225
|
-
expect(path.attributes('d')).toBeTruthy();
|
|
226
|
-
expect(path.attributes('stroke')).toBeTruthy();
|
|
227
|
-
expect(path.attributes('stroke-width')).toBeTruthy();
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it('suitable for media player controls', () => {
|
|
232
|
-
const wrapper = mount(Play);
|
|
233
|
-
|
|
234
|
-
// Standard media control size and appearance
|
|
235
|
-
expect(wrapper.find('svg').attributes('width')).toBe('24');
|
|
236
|
-
expect(wrapper.find('svg').attributes('height')).toBe('24');
|
|
237
|
-
expect(wrapper.findAll('path')).toHaveLength(2);
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
describe('Icon Semantics', () => {
|
|
242
|
-
it('represents play action with universal design', () => {
|
|
243
|
-
const wrapper = mount(Play);
|
|
244
|
-
const paths = wrapper.findAll('path');
|
|
245
|
-
|
|
246
|
-
// Universal play symbol: circle + right-pointing triangle
|
|
247
|
-
const circlePath = paths[0].attributes('d');
|
|
248
|
-
const trianglePath = paths[1].attributes('d');
|
|
249
|
-
|
|
250
|
-
expect(circlePath).toMatch(/C21 16\.9706.*C3 7\.02944/); // Circle
|
|
251
|
-
expect(trianglePath).toMatch(/15\.9099.*11\.6722/); // Right-pointing
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
it('uses appropriate size for media controls', () => {
|
|
255
|
-
const wrapper = mount(Play);
|
|
256
|
-
const svg = wrapper.find('svg');
|
|
257
|
-
|
|
258
|
-
// 24px is standard for media control buttons
|
|
259
|
-
expect(svg.attributes('width')).toBe('24');
|
|
260
|
-
expect(svg.attributes('height')).toBe('24');
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
it('provides clear visual affordance', () => {
|
|
264
|
-
const wrapper = mount(Play);
|
|
265
|
-
const paths = wrapper.findAll('path');
|
|
266
|
-
|
|
267
|
-
// Clear outline with good stroke weight
|
|
268
|
-
paths.forEach(path => {
|
|
269
|
-
expect(path.attributes('stroke')).toBeTruthy();
|
|
270
|
-
expect(parseFloat(path.attributes('stroke-width'))).toBeGreaterThan(1);
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
describe('Visual Design', () => {
|
|
276
|
-
it('provides recognizable play button appearance', () => {
|
|
277
|
-
const wrapper = mount(Play);
|
|
278
|
-
const paths = wrapper.findAll('path');
|
|
279
|
-
|
|
280
|
-
// Standard play button elements
|
|
281
|
-
expect(paths[0].attributes('d')).toContain('21 12C21'); // Circular boundary
|
|
282
|
-
expect(paths[1].attributes('d')).toContain('15.9099'); // Triangle pointing right
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
it('uses consistent stroke styling', () => {
|
|
286
|
-
const wrapper = mount(Play);
|
|
287
|
-
const paths = wrapper.findAll('path');
|
|
288
|
-
|
|
289
|
-
paths.forEach(path => {
|
|
290
|
-
expect(path.attributes('stroke')).toBe('#172774');
|
|
291
|
-
expect(path.attributes('stroke-width')).toBe('1.5');
|
|
292
|
-
expect(path.attributes('stroke-linecap')).toBe('round');
|
|
293
|
-
expect(path.attributes('stroke-linejoin')).toBe('round');
|
|
294
|
-
});
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
it('balances circle and triangle proportions', () => {
|
|
298
|
-
const wrapper = mount(Play);
|
|
299
|
-
const paths = wrapper.findAll('path');
|
|
300
|
-
|
|
301
|
-
const circlePath = paths[0].attributes('d');
|
|
302
|
-
const trianglePath = paths[1].attributes('d');
|
|
303
|
-
|
|
304
|
-
// Triangle should be proportional to circle
|
|
305
|
-
expect(circlePath).toContain('21 12'); // Circle radius ~9
|
|
306
|
-
expect(trianglePath).toMatch(/15\.9099.*9\.75/); // Triangle width ~6
|
|
307
|
-
});
|
|
308
|
-
});
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import Play from '@components/Icons/play.vue';
|
|
4
|
+
|
|
5
|
+
describe('Play Icon', () => {
|
|
6
|
+
describe('Rendering', () => {
|
|
7
|
+
it('renders as SVG element', () => {
|
|
8
|
+
const wrapper = mount(Play);
|
|
9
|
+
expect(wrapper.find('svg').exists()).toBe(true);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('has correct SVG attributes', () => {
|
|
13
|
+
const wrapper = mount(Play);
|
|
14
|
+
const svg = wrapper.find('svg');
|
|
15
|
+
|
|
16
|
+
expect(svg.attributes('xmlns')).toBe('http://www.w3.org/2000/svg');
|
|
17
|
+
expect(svg.attributes('width')).toBe('24');
|
|
18
|
+
expect(svg.attributes('height')).toBe('24');
|
|
19
|
+
expect(svg.attributes('viewBox')).toBe('0 0 24 24');
|
|
20
|
+
expect(svg.attributes('fill')).toBe('none');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('contains exactly 2 path elements', () => {
|
|
24
|
+
const wrapper = mount(Play);
|
|
25
|
+
const paths = wrapper.findAll('path');
|
|
26
|
+
expect(paths).toHaveLength(2);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('Path Structure', () => {
|
|
31
|
+
it('first path represents circle background', () => {
|
|
32
|
+
const wrapper = mount(Play);
|
|
33
|
+
const paths = wrapper.findAll('path');
|
|
34
|
+
|
|
35
|
+
const circlePath = paths[0];
|
|
36
|
+
expect(circlePath.attributes('d')).toContain('M21 12C21 16.9706');
|
|
37
|
+
expect(circlePath.attributes('stroke')).toBe('#172774');
|
|
38
|
+
expect(circlePath.attributes('stroke-width')).toBe('1.5');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('second path represents play triangle', () => {
|
|
42
|
+
const wrapper = mount(Play);
|
|
43
|
+
const paths = wrapper.findAll('path');
|
|
44
|
+
|
|
45
|
+
const trianglePath = paths[1];
|
|
46
|
+
expect(trianglePath.attributes('d')).toContain('M15.9099 11.6722');
|
|
47
|
+
expect(trianglePath.attributes('stroke')).toBe('#172774');
|
|
48
|
+
expect(trianglePath.attributes('stroke-width')).toBe('1.5');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('circle path forms complete circle', () => {
|
|
52
|
+
const wrapper = mount(Play);
|
|
53
|
+
const paths = wrapper.findAll('path');
|
|
54
|
+
|
|
55
|
+
const circlePath = paths[0];
|
|
56
|
+
const pathData = circlePath.attributes('d');
|
|
57
|
+
|
|
58
|
+
// Should contain circle definition with center at 12,12 and radius 9
|
|
59
|
+
expect(pathData).toContain('21 12C21 16.9706'); // Right side
|
|
60
|
+
expect(pathData).toContain('16.9706 21 12 21'); // Bottom
|
|
61
|
+
expect(pathData).toContain('7.02944 21 3 16.9706'); // Left side
|
|
62
|
+
expect(pathData).toContain('3 12C3 7.02944'); // Top
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('triangle path forms play arrow', () => {
|
|
66
|
+
const wrapper = mount(Play);
|
|
67
|
+
const paths = wrapper.findAll('path');
|
|
68
|
+
|
|
69
|
+
const trianglePath = paths[1];
|
|
70
|
+
const pathData = trianglePath.attributes('d');
|
|
71
|
+
|
|
72
|
+
// Should contain triangle vertices
|
|
73
|
+
expect(pathData).toContain('15.9099 11.6722'); // Right point
|
|
74
|
+
expect(pathData).toContain('10.3071 15.4405'); // Bottom left
|
|
75
|
+
expect(pathData).toContain('9.75 15.1127'); // Bottom edge
|
|
76
|
+
expect(pathData).toContain('8.88732C9.75 8.60139'); // Top edge
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('Visual Properties', () => {
|
|
81
|
+
it('all strokes use correct brand color', () => {
|
|
82
|
+
const wrapper = mount(Play);
|
|
83
|
+
const paths = wrapper.findAll('path');
|
|
84
|
+
|
|
85
|
+
paths.forEach(path => {
|
|
86
|
+
expect(path.attributes('stroke')).toBe('#172774');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('all paths have correct stroke width', () => {
|
|
91
|
+
const wrapper = mount(Play);
|
|
92
|
+
const paths = wrapper.findAll('path');
|
|
93
|
+
|
|
94
|
+
paths.forEach(path => {
|
|
95
|
+
expect(path.attributes('stroke-width')).toBe('1.5');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('all paths have rounded line caps and joins', () => {
|
|
100
|
+
const wrapper = mount(Play);
|
|
101
|
+
const paths = wrapper.findAll('path');
|
|
102
|
+
|
|
103
|
+
paths.forEach(path => {
|
|
104
|
+
expect(path.attributes('stroke-linecap')).toBe('round');
|
|
105
|
+
expect(path.attributes('stroke-linejoin')).toBe('round');
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('paths have no fill (outline style)', () => {
|
|
110
|
+
const wrapper = mount(Play);
|
|
111
|
+
const svg = wrapper.find('svg');
|
|
112
|
+
|
|
113
|
+
expect(svg.attributes('fill')).toBe('none');
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe('Play Button Geometry', () => {
|
|
118
|
+
it('circle is centered in viewBox', () => {
|
|
119
|
+
const wrapper = mount(Play);
|
|
120
|
+
const paths = wrapper.findAll('path');
|
|
121
|
+
|
|
122
|
+
const circlePath = paths[0];
|
|
123
|
+
const pathData = circlePath.attributes('d');
|
|
124
|
+
|
|
125
|
+
// Circle centered at 12,12 with radius 9
|
|
126
|
+
expect(pathData).toContain('12C21 16.9706'); // Center coordinates
|
|
127
|
+
expect(pathData).toContain('21 12 21C7.02944'); // Center coordinates
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('play triangle is centered horizontally', () => {
|
|
131
|
+
const wrapper = mount(Play);
|
|
132
|
+
const paths = wrapper.findAll('path');
|
|
133
|
+
|
|
134
|
+
const trianglePath = paths[1];
|
|
135
|
+
const pathData = trianglePath.attributes('d');
|
|
136
|
+
|
|
137
|
+
// Triangle should be centered around x=12
|
|
138
|
+
expect(pathData).toContain('15.9099'); // Right point
|
|
139
|
+
expect(pathData).toContain('10.3071'); // Left side
|
|
140
|
+
expect(pathData).toContain('9.75'); // Left edge
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('play triangle points to the right', () => {
|
|
144
|
+
const wrapper = mount(Play);
|
|
145
|
+
const paths = wrapper.findAll('path');
|
|
146
|
+
|
|
147
|
+
const trianglePath = paths[1];
|
|
148
|
+
const pathData = trianglePath.attributes('d');
|
|
149
|
+
|
|
150
|
+
// Right-pointing triangle
|
|
151
|
+
expect(pathData).toMatch(/15\.9099.*11\.6722/); // Right point
|
|
152
|
+
expect(pathData).toMatch(/10\.3071.*15\.4405/); // Bottom left
|
|
153
|
+
expect(pathData).toMatch(/8\.88732/); // Top left
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('maintains proper play button proportions', () => {
|
|
157
|
+
const wrapper = mount(Play);
|
|
158
|
+
const svg = wrapper.find('svg');
|
|
159
|
+
|
|
160
|
+
// Standard play button is square
|
|
161
|
+
expect(svg.attributes('width')).toBe(svg.attributes('height'));
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('Component Structure', () => {
|
|
166
|
+
it('uses standard 24x24 size', () => {
|
|
167
|
+
const wrapper = mount(Play);
|
|
168
|
+
const svg = wrapper.find('svg');
|
|
169
|
+
|
|
170
|
+
expect(svg.attributes('width')).toBe('24');
|
|
171
|
+
expect(svg.attributes('height')).toBe('24');
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('suitable for media control usage', () => {
|
|
175
|
+
const wrapper = mount(Play);
|
|
176
|
+
const paths = wrapper.findAll('path');
|
|
177
|
+
|
|
178
|
+
// Circle + triangle is standard play button design
|
|
179
|
+
expect(paths).toHaveLength(2);
|
|
180
|
+
expect(paths[0].attributes('d')).toContain('12C21'); // Circle
|
|
181
|
+
expect(paths[1].attributes('d')).toContain('15.9099'); // Triangle
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe('Accessibility', () => {
|
|
186
|
+
it('svg is properly structured for screen readers', () => {
|
|
187
|
+
const wrapper = mount(Play);
|
|
188
|
+
const svg = wrapper.find('svg');
|
|
189
|
+
|
|
190
|
+
expect(svg.element.tagName.toLowerCase()).toBe('svg');
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('uses clear outline style for visibility', () => {
|
|
194
|
+
const wrapper = mount(Play);
|
|
195
|
+
const paths = wrapper.findAll('path');
|
|
196
|
+
|
|
197
|
+
// Outline style with good contrast
|
|
198
|
+
paths.forEach(path => {
|
|
199
|
+
expect(path.attributes('stroke')).toBe('#172774');
|
|
200
|
+
expect(path.attributes('stroke-width')).toBe('1.5');
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe('Component Integration', () => {
|
|
206
|
+
it('can be mounted without props', () => {
|
|
207
|
+
expect(() => {
|
|
208
|
+
mount(Play);
|
|
209
|
+
}).not.toThrow();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('renders consistently on multiple mounts', () => {
|
|
213
|
+
const wrapper1 = mount(Play);
|
|
214
|
+
const wrapper2 = mount(Play);
|
|
215
|
+
|
|
216
|
+
expect(wrapper1.html()).toBe(wrapper2.html());
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('maintains play button structure integrity', () => {
|
|
220
|
+
const wrapper = mount(Play);
|
|
221
|
+
const paths = wrapper.findAll('path');
|
|
222
|
+
|
|
223
|
+
expect(paths).toHaveLength(2);
|
|
224
|
+
paths.forEach(path => {
|
|
225
|
+
expect(path.attributes('d')).toBeTruthy();
|
|
226
|
+
expect(path.attributes('stroke')).toBeTruthy();
|
|
227
|
+
expect(path.attributes('stroke-width')).toBeTruthy();
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('suitable for media player controls', () => {
|
|
232
|
+
const wrapper = mount(Play);
|
|
233
|
+
|
|
234
|
+
// Standard media control size and appearance
|
|
235
|
+
expect(wrapper.find('svg').attributes('width')).toBe('24');
|
|
236
|
+
expect(wrapper.find('svg').attributes('height')).toBe('24');
|
|
237
|
+
expect(wrapper.findAll('path')).toHaveLength(2);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('Icon Semantics', () => {
|
|
242
|
+
it('represents play action with universal design', () => {
|
|
243
|
+
const wrapper = mount(Play);
|
|
244
|
+
const paths = wrapper.findAll('path');
|
|
245
|
+
|
|
246
|
+
// Universal play symbol: circle + right-pointing triangle
|
|
247
|
+
const circlePath = paths[0].attributes('d');
|
|
248
|
+
const trianglePath = paths[1].attributes('d');
|
|
249
|
+
|
|
250
|
+
expect(circlePath).toMatch(/C21 16\.9706.*C3 7\.02944/); // Circle
|
|
251
|
+
expect(trianglePath).toMatch(/15\.9099.*11\.6722/); // Right-pointing
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('uses appropriate size for media controls', () => {
|
|
255
|
+
const wrapper = mount(Play);
|
|
256
|
+
const svg = wrapper.find('svg');
|
|
257
|
+
|
|
258
|
+
// 24px is standard for media control buttons
|
|
259
|
+
expect(svg.attributes('width')).toBe('24');
|
|
260
|
+
expect(svg.attributes('height')).toBe('24');
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('provides clear visual affordance', () => {
|
|
264
|
+
const wrapper = mount(Play);
|
|
265
|
+
const paths = wrapper.findAll('path');
|
|
266
|
+
|
|
267
|
+
// Clear outline with good stroke weight
|
|
268
|
+
paths.forEach(path => {
|
|
269
|
+
expect(path.attributes('stroke')).toBeTruthy();
|
|
270
|
+
expect(parseFloat(path.attributes('stroke-width'))).toBeGreaterThan(1);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
describe('Visual Design', () => {
|
|
276
|
+
it('provides recognizable play button appearance', () => {
|
|
277
|
+
const wrapper = mount(Play);
|
|
278
|
+
const paths = wrapper.findAll('path');
|
|
279
|
+
|
|
280
|
+
// Standard play button elements
|
|
281
|
+
expect(paths[0].attributes('d')).toContain('21 12C21'); // Circular boundary
|
|
282
|
+
expect(paths[1].attributes('d')).toContain('15.9099'); // Triangle pointing right
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('uses consistent stroke styling', () => {
|
|
286
|
+
const wrapper = mount(Play);
|
|
287
|
+
const paths = wrapper.findAll('path');
|
|
288
|
+
|
|
289
|
+
paths.forEach(path => {
|
|
290
|
+
expect(path.attributes('stroke')).toBe('#172774');
|
|
291
|
+
expect(path.attributes('stroke-width')).toBe('1.5');
|
|
292
|
+
expect(path.attributes('stroke-linecap')).toBe('round');
|
|
293
|
+
expect(path.attributes('stroke-linejoin')).toBe('round');
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('balances circle and triangle proportions', () => {
|
|
298
|
+
const wrapper = mount(Play);
|
|
299
|
+
const paths = wrapper.findAll('path');
|
|
300
|
+
|
|
301
|
+
const circlePath = paths[0].attributes('d');
|
|
302
|
+
const trianglePath = paths[1].attributes('d');
|
|
303
|
+
|
|
304
|
+
// Triangle should be proportional to circle
|
|
305
|
+
expect(circlePath).toContain('21 12'); // Circle radius ~9
|
|
306
|
+
expect(trianglePath).toMatch(/15\.9099.*9\.75/); // Triangle width ~6
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
309
|
});
|