@zap-wunschlachen/wl-shared-components 1.0.35 → 1.0.37
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 +43 -38
- 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/audio/test.aac +0 -0
- package/public/background.svg +60 -60
- package/public/style.css +187 -187
- package/public/technologies.svg +22 -22
- package/src/assets/css/base.css +232 -232
- package/src/assets/css/variables.css +109 -109
- 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 +54 -54
- package/src/components/Appointment/Card/Actions.vue +99 -99
- package/src/components/Appointment/Card/AnamneseNotification.css +15 -15
- package/src/components/Appointment/Card/AnamneseNotification.vue +23 -23
- package/src/components/Appointment/Card/Card.css +80 -80
- package/src/components/Appointment/Card/Card.vue +93 -93
- 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 +118 -117
- package/src/components/Button/Button.vue +174 -136
- package/src/components/CheckBox/CheckBox.css +214 -185
- package/src/components/CheckBox/Checkbox.vue +138 -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 +38 -29
- package/src/components/EditField/EditField.css +19 -19
- package/src/components/EditField/EditField.vue +202 -202
- package/src/components/ErrorPage/ErrorPage.css +172 -172
- 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 +253 -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/Loader/Loader.css +71 -51
- package/src/components/Loader/Loader.vue +1 -0
- package/src/components/MaintenanceBanner/MaintenanceBanner.css +353 -353
- package/src/components/MaintenanceBanner/MaintenanceBanner.vue +127 -127
- package/src/components/MaintenanceBanner/MaintenanceIllustration.vue +54 -54
- 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 +151 -151
- 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 +316 -315
- 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/accessibility.css +218 -0
- package/src/components/index.ts +28 -28
- package/src/constants/iconEnums.ts +3 -3
- package/src/i18n/i18n.ts +15 -15
- package/src/i18n/locales/de.json +30 -30
- package/src/i18n/locales/en.json +30 -30
- package/src/index.ts +34 -34
- package/src/main.ts +11 -11
- package/src/plugins/vuetify.ts +141 -141
- 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 +109 -109
- 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/accessibility/component-a11y.spec.ts +469 -0
- package/tests/unit/components/Accordion/AccordionGroup.spec.ts +228 -0
- package/tests/unit/components/Accordion/AccordionGroup.spec.ts.skip +342 -342
- package/tests/unit/components/Accordion/AccordionItem.spec.ts +292 -0
- package/tests/unit/components/Accordion/AccordionItem.spec.ts.skip +383 -383
- package/tests/unit/components/Appointment/AnamneseNotification.spec.ts +176 -0
- 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/Background/Background.spec.ts +177 -0
- 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/ErrorPage/ErrorPage.spec.ts +313 -0
- package/tests/unit/components/ErrorPage/ErrorPageLogo.spec.ts +153 -0
- 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/AdvanceAppointments.spec.ts +61 -0
- 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/Logo.spec.ts +228 -0
- package/tests/unit/components/Icons/MiniLogo.spec.ts +38 -0
- package/tests/unit/components/Icons/RingNotification.spec.ts +393 -393
- package/tests/unit/components/Icons/SolidArrowRight.spec.ts +49 -0
- 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/components/Loader/Loader.spec.ts +197 -0
- package/tests/unit/components/MaintenanceBanner/MaintenanceBanner.spec.ts +302 -0
- 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/tests/unit/utils/accessibility.spec.ts +318 -0
- package/tsconfig.json +26 -26
- package/vite.config.ts +29 -29
- package/vitest.config.ts +83 -83
|
@@ -1,620 +1,620 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { mount } from '@vue/test-utils';
|
|
3
|
-
import { nextTick } from 'vue';
|
|
4
|
-
import PhoneInput from '@components/PhoneInput/PhoneInput.vue';
|
|
5
|
-
|
|
6
|
-
// Mock v-phone-input
|
|
7
|
-
vi.mock('v-phone-input', () => ({
|
|
8
|
-
VPhoneInput: {
|
|
9
|
-
template: '<div data-testid="v-phone-input"><slot /></div>',
|
|
10
|
-
props: [
|
|
11
|
-
'include-countries', 'aria-label', 'variant', 'label', 'appendInnerIcon',
|
|
12
|
-
'placeHolder', 'display-format', 'default-country', 'hide-details',
|
|
13
|
-
'aria-invalid', 'countryIconMode'
|
|
14
|
-
]
|
|
15
|
-
}
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
describe('PhoneInput', () => {
|
|
19
|
-
beforeEach(() => {
|
|
20
|
-
vi.clearAllMocks();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
// Test default behavior and rendering
|
|
24
|
-
describe('Default Behavior', () => {
|
|
25
|
-
it('renders with default props', () => {
|
|
26
|
-
const wrapper = mount(PhoneInput);
|
|
27
|
-
|
|
28
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
29
|
-
expect(wrapper.find('.wl-phone-input').exists()).toBe(true);
|
|
30
|
-
expect(wrapper.vm.state).toBe('default');
|
|
31
|
-
expect(wrapper.vm.placeholder).toBe('');
|
|
32
|
-
expect(wrapper.vm.countriesCodes).toEqual([]);
|
|
33
|
-
expect(wrapper.vm.defaultCountryCode).toBe('DE');
|
|
34
|
-
expect(wrapper.vm.appendInnerIcon).toBe('heroicons:phone');
|
|
35
|
-
expect(wrapper.vm.variant).toBe('outlined');
|
|
36
|
-
expect(wrapper.vm.borderOnHover).toBe(false);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('has data-testid for testing', () => {
|
|
40
|
-
const wrapper = mount(PhoneInput);
|
|
41
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('applies wl-phone-input CSS class', () => {
|
|
45
|
-
const wrapper = mount(PhoneInput);
|
|
46
|
-
expect(wrapper.find('.wl-phone-input').exists()).toBe(true);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('sets id attribute to "phone"', () => {
|
|
50
|
-
const wrapper = mount(PhoneInput);
|
|
51
|
-
// Since VPhoneInput is mocked, we can't directly test the id
|
|
52
|
-
// but we can verify the component renders correctly
|
|
53
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
// Test validation states
|
|
58
|
-
describe('Validation States', () => {
|
|
59
|
-
it('handles default state', () => {
|
|
60
|
-
const wrapper = mount(PhoneInput, {
|
|
61
|
-
props: {
|
|
62
|
-
state: 'default'
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
expect(wrapper.vm.state).toBe('default');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('handles error state', () => {
|
|
70
|
-
const wrapper = mount(PhoneInput, {
|
|
71
|
-
props: {
|
|
72
|
-
state: 'error'
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
expect(wrapper.vm.state).toBe('error');
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('handles success state', () => {
|
|
80
|
-
const wrapper = mount(PhoneInput, {
|
|
81
|
-
props: {
|
|
82
|
-
state: 'success'
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
expect(wrapper.vm.state).toBe('success');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('sets aria-invalid based on error state', () => {
|
|
90
|
-
const errorWrapper = mount(PhoneInput, {
|
|
91
|
-
props: {
|
|
92
|
-
state: 'error'
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
expect(errorWrapper.vm.state).toBe('error');
|
|
97
|
-
|
|
98
|
-
const defaultWrapper = mount(PhoneInput, {
|
|
99
|
-
props: {
|
|
100
|
-
state: 'default'
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
expect(defaultWrapper.vm.state).toBe('default');
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// Test placeholder functionality
|
|
109
|
-
describe('Placeholder', () => {
|
|
110
|
-
it('uses default empty placeholder', () => {
|
|
111
|
-
const wrapper = mount(PhoneInput);
|
|
112
|
-
expect(wrapper.vm.placeholder).toBe('');
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('accepts custom placeholder', () => {
|
|
116
|
-
const wrapper = mount(PhoneInput, {
|
|
117
|
-
props: {
|
|
118
|
-
placeholder: 'Enter your phone number'
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
expect(wrapper.vm.placeholder).toBe('Enter your phone number');
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('uses placeholder for aria-label', () => {
|
|
126
|
-
const wrapper = mount(PhoneInput, {
|
|
127
|
-
props: {
|
|
128
|
-
placeholder: 'Phone number'
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
expect(wrapper.vm.placeholder).toBe('Phone number');
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// Test country configuration
|
|
137
|
-
describe('Country Configuration', () => {
|
|
138
|
-
it('uses default country code DE', () => {
|
|
139
|
-
const wrapper = mount(PhoneInput);
|
|
140
|
-
expect(wrapper.vm.defaultCountryCode).toBe('DE');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('accepts custom default country code', () => {
|
|
144
|
-
const wrapper = mount(PhoneInput, {
|
|
145
|
-
props: {
|
|
146
|
-
defaultCountryCode: 'US'
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
expect(wrapper.vm.defaultCountryCode).toBe('US');
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it('uses empty countries list by default', () => {
|
|
154
|
-
const wrapper = mount(PhoneInput);
|
|
155
|
-
expect(wrapper.vm.countriesCodes).toEqual([]);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it('accepts custom countries list', () => {
|
|
159
|
-
const countries = ['US', 'GB', 'FR', 'DE'];
|
|
160
|
-
const wrapper = mount(PhoneInput, {
|
|
161
|
-
props: {
|
|
162
|
-
countriesCodes: countries
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
expect(wrapper.vm.countriesCodes).toEqual(countries);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('handles single country in list', () => {
|
|
170
|
-
const wrapper = mount(PhoneInput, {
|
|
171
|
-
props: {
|
|
172
|
-
countriesCodes: ['US']
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
expect(wrapper.vm.countriesCodes).toEqual(['US']);
|
|
177
|
-
});
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// Test icons and styling
|
|
181
|
-
describe('Icons and Styling', () => {
|
|
182
|
-
it('uses default phone icon', () => {
|
|
183
|
-
const wrapper = mount(PhoneInput);
|
|
184
|
-
expect(wrapper.vm.appendInnerIcon).toBe('heroicons:phone');
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('accepts custom append inner icon', () => {
|
|
188
|
-
const wrapper = mount(PhoneInput, {
|
|
189
|
-
props: {
|
|
190
|
-
appendInnerIcon: 'mdi-phone'
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
expect(wrapper.vm.appendInnerIcon).toBe('mdi-phone');
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('uses default outlined variant', () => {
|
|
198
|
-
const wrapper = mount(PhoneInput);
|
|
199
|
-
expect(wrapper.vm.variant).toBe('outlined');
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it('accepts custom variant', () => {
|
|
203
|
-
const variants = ['filled', 'outlined', 'underlined', 'solo'];
|
|
204
|
-
|
|
205
|
-
variants.forEach(variant => {
|
|
206
|
-
const wrapper = mount(PhoneInput, {
|
|
207
|
-
props: { variant }
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
expect(wrapper.vm.variant).toBe(variant);
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('handles border on hover', () => {
|
|
215
|
-
const wrapper = mount(PhoneInput, {
|
|
216
|
-
props: {
|
|
217
|
-
borderOnHover: true
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
expect(wrapper.find('.border-on-hover').exists()).toBe(true);
|
|
222
|
-
expect(wrapper.vm.borderOnHover).toBe(true);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it('does not apply border-on-hover class by default', () => {
|
|
226
|
-
const wrapper = mount(PhoneInput);
|
|
227
|
-
|
|
228
|
-
expect(wrapper.find('.border-on-hover').exists()).toBe(false);
|
|
229
|
-
expect(wrapper.vm.borderOnHover).toBe(false);
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
// Test event emission
|
|
234
|
-
describe('Event Emission', () => {
|
|
235
|
-
it('emits update:phone event', async () => {
|
|
236
|
-
const wrapper = mount(PhoneInput);
|
|
237
|
-
|
|
238
|
-
// Simulate the event that would be emitted by VPhoneInput
|
|
239
|
-
wrapper.vm.$emit('update:phone', '+1234567890');
|
|
240
|
-
|
|
241
|
-
expect(wrapper.emitted('update:phone')).toBeTruthy();
|
|
242
|
-
expect(wrapper.emitted('update:phone')?.[0]).toEqual(['+1234567890']);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
it('handles different phone number formats', async () => {
|
|
246
|
-
const wrapper = mount(PhoneInput);
|
|
247
|
-
|
|
248
|
-
const phoneNumbers = [
|
|
249
|
-
'+1 (555) 123-4567',
|
|
250
|
-
'+49 30 12345678',
|
|
251
|
-
'+44 20 7123 4567',
|
|
252
|
-
'555-123-4567'
|
|
253
|
-
];
|
|
254
|
-
|
|
255
|
-
phoneNumbers.forEach((phone, index) => {
|
|
256
|
-
wrapper.vm.$emit('update:phone', phone);
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
expect(wrapper.emitted('update:phone')).toHaveLength(phoneNumbers.length);
|
|
260
|
-
phoneNumbers.forEach((phone, index) => {
|
|
261
|
-
expect(wrapper.emitted('update:phone')?.[index]).toEqual([phone]);
|
|
262
|
-
});
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('handles empty phone number', async () => {
|
|
266
|
-
const wrapper = mount(PhoneInput);
|
|
267
|
-
|
|
268
|
-
wrapper.vm.$emit('update:phone', '');
|
|
269
|
-
|
|
270
|
-
expect(wrapper.emitted('update:phone')?.[0]).toEqual(['']);
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
// Test exposed methods
|
|
275
|
-
describe('Exposed Methods', () => {
|
|
276
|
-
it('exposes focus, blur, and select methods', () => {
|
|
277
|
-
const wrapper = mount(PhoneInput);
|
|
278
|
-
|
|
279
|
-
expect(wrapper.vm.focus).toBeDefined();
|
|
280
|
-
expect(wrapper.vm.blur).toBeDefined();
|
|
281
|
-
expect(wrapper.vm.select).toBeDefined();
|
|
282
|
-
expect(typeof wrapper.vm.focus).toBe('function');
|
|
283
|
-
expect(typeof wrapper.vm.blur).toBe('function');
|
|
284
|
-
expect(typeof wrapper.vm.select).toBe('function');
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
it('getNativeInput returns null with mocked component', () => {
|
|
288
|
-
const wrapper = mount(PhoneInput);
|
|
289
|
-
const nativeInput = wrapper.vm.getNativeInput();
|
|
290
|
-
|
|
291
|
-
expect(nativeInput).toBeUndefined();
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
it('focus method works with mocked input', async () => {
|
|
295
|
-
const wrapper = mount(PhoneInput);
|
|
296
|
-
|
|
297
|
-
// Get the real input element from the stub
|
|
298
|
-
const nativeInput = wrapper.vm.getNativeInput();
|
|
299
|
-
if (nativeInput) {
|
|
300
|
-
const focusSpy = vi.spyOn(nativeInput, 'focus');
|
|
301
|
-
|
|
302
|
-
wrapper.vm.focus();
|
|
303
|
-
await nextTick();
|
|
304
|
-
|
|
305
|
-
expect(focusSpy).toHaveBeenCalled();
|
|
306
|
-
} else {
|
|
307
|
-
// If no input is found, just verify the method exists
|
|
308
|
-
expect(wrapper.vm.focus).toBeDefined();
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it('blur method works with mocked input', async () => {
|
|
313
|
-
const wrapper = mount(PhoneInput);
|
|
314
|
-
|
|
315
|
-
// Get the real input element from the stub
|
|
316
|
-
const nativeInput = wrapper.vm.getNativeInput();
|
|
317
|
-
if (nativeInput) {
|
|
318
|
-
const blurSpy = vi.spyOn(nativeInput, 'blur');
|
|
319
|
-
|
|
320
|
-
wrapper.vm.blur();
|
|
321
|
-
await nextTick();
|
|
322
|
-
|
|
323
|
-
expect(blurSpy).toHaveBeenCalled();
|
|
324
|
-
} else {
|
|
325
|
-
// If no input is found, just verify the method exists
|
|
326
|
-
expect(wrapper.vm.blur).toBeDefined();
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
it('select method works with mocked input', async () => {
|
|
331
|
-
const wrapper = mount(PhoneInput);
|
|
332
|
-
|
|
333
|
-
// Get the real input element from the stub
|
|
334
|
-
const nativeInput = wrapper.vm.getNativeInput();
|
|
335
|
-
if (nativeInput) {
|
|
336
|
-
const selectSpy = vi.spyOn(nativeInput, 'select');
|
|
337
|
-
|
|
338
|
-
wrapper.vm.select();
|
|
339
|
-
await nextTick();
|
|
340
|
-
|
|
341
|
-
expect(selectSpy).toHaveBeenCalled();
|
|
342
|
-
} else {
|
|
343
|
-
// If no input is found, just verify the method exists
|
|
344
|
-
expect(wrapper.vm.select).toBeDefined();
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
it('handles null inputRef gracefully', () => {
|
|
349
|
-
const wrapper = mount(PhoneInput);
|
|
350
|
-
wrapper.vm.inputRef = null;
|
|
351
|
-
|
|
352
|
-
expect(() => wrapper.vm.focus()).not.toThrow();
|
|
353
|
-
expect(() => wrapper.vm.blur()).not.toThrow();
|
|
354
|
-
expect(() => wrapper.vm.select()).not.toThrow();
|
|
355
|
-
});
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
// Test VPhoneInput configuration
|
|
359
|
-
describe('VPhoneInput Configuration', () => {
|
|
360
|
-
it('configures VPhoneInput with correct props', () => {
|
|
361
|
-
const wrapper = mount(PhoneInput, {
|
|
362
|
-
props: {
|
|
363
|
-
placeholder: 'Enter phone',
|
|
364
|
-
variant: 'filled',
|
|
365
|
-
defaultCountryCode: 'US',
|
|
366
|
-
appendInnerIcon: 'mdi-phone',
|
|
367
|
-
borderOnHover: true
|
|
368
|
-
}
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
// With mocked VPhoneInput, verify the component renders
|
|
372
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
373
|
-
expect(wrapper.vm.placeholder).toBe('Enter phone');
|
|
374
|
-
expect(wrapper.vm.variant).toBe('filled');
|
|
375
|
-
expect(wrapper.vm.defaultCountryCode).toBe('US');
|
|
376
|
-
expect(wrapper.vm.appendInnerIcon).toBe('mdi-phone');
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
it('sets display format to international', () => {
|
|
380
|
-
const wrapper = mount(PhoneInput);
|
|
381
|
-
|
|
382
|
-
// Verify component renders correctly (display-format is hardcoded in template)
|
|
383
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
it('hides details by default', () => {
|
|
387
|
-
const wrapper = mount(PhoneInput);
|
|
388
|
-
|
|
389
|
-
// hide-details is hardcoded in template
|
|
390
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
it('uses svg country icon mode', () => {
|
|
394
|
-
const wrapper = mount(PhoneInput);
|
|
395
|
-
|
|
396
|
-
// countryIconMode="svg" is hardcoded in template
|
|
397
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
it('sets empty label', () => {
|
|
401
|
-
const wrapper = mount(PhoneInput);
|
|
402
|
-
|
|
403
|
-
// label="" is hardcoded in template
|
|
404
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
405
|
-
});
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
// Test accessibility
|
|
409
|
-
describe('Accessibility', () => {
|
|
410
|
-
it('has data-testid for testing', () => {
|
|
411
|
-
const wrapper = mount(PhoneInput);
|
|
412
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
it('sets aria-label from placeholder', () => {
|
|
416
|
-
const wrapper = mount(PhoneInput, {
|
|
417
|
-
props: {
|
|
418
|
-
placeholder: 'Enter your phone number'
|
|
419
|
-
}
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
expect(wrapper.vm.placeholder).toBe('Enter your phone number');
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
it('handles aria-invalid for error state', () => {
|
|
426
|
-
const wrapper = mount(PhoneInput, {
|
|
427
|
-
props: {
|
|
428
|
-
state: 'error'
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
expect(wrapper.vm.state).toBe('error');
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
it('provides meaningful placeholder text', () => {
|
|
436
|
-
const wrapper = mount(PhoneInput, {
|
|
437
|
-
props: {
|
|
438
|
-
placeholder: 'Phone number (including country code)'
|
|
439
|
-
}
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
expect(wrapper.vm.placeholder).toBe('Phone number (including country code)');
|
|
443
|
-
});
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
// Test edge cases
|
|
447
|
-
describe('Edge Cases', () => {
|
|
448
|
-
it('handles empty countries array', () => {
|
|
449
|
-
const wrapper = mount(PhoneInput, {
|
|
450
|
-
props: {
|
|
451
|
-
countriesCodes: []
|
|
452
|
-
}
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
expect(wrapper.vm.countriesCodes).toEqual([]);
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
it('handles invalid country codes gracefully', () => {
|
|
459
|
-
const wrapper = mount(PhoneInput, {
|
|
460
|
-
props: {
|
|
461
|
-
countriesCodes: ['XX', 'YY', 'ZZ'], // Invalid country codes
|
|
462
|
-
defaultCountryCode: 'XX'
|
|
463
|
-
}
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
expect(wrapper.vm.countriesCodes).toEqual(['XX', 'YY', 'ZZ']);
|
|
467
|
-
expect(wrapper.vm.defaultCountryCode).toBe('XX');
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
it('handles special characters in placeholder', () => {
|
|
471
|
-
const specialPlaceholder = 'Téléphone (avec indicatif pays) +33...';
|
|
472
|
-
const wrapper = mount(PhoneInput, {
|
|
473
|
-
props: {
|
|
474
|
-
placeholder: specialPlaceholder
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
expect(wrapper.vm.placeholder).toBe(specialPlaceholder);
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
it('handles empty string props', () => {
|
|
482
|
-
const wrapper = mount(PhoneInput, {
|
|
483
|
-
props: {
|
|
484
|
-
placeholder: '',
|
|
485
|
-
defaultCountryCode: '',
|
|
486
|
-
appendInnerIcon: '',
|
|
487
|
-
variant: ''
|
|
488
|
-
}
|
|
489
|
-
});
|
|
490
|
-
|
|
491
|
-
expect(wrapper.vm.placeholder).toBe('');
|
|
492
|
-
expect(wrapper.vm.defaultCountryCode).toBe('');
|
|
493
|
-
expect(wrapper.vm.appendInnerIcon).toBe('');
|
|
494
|
-
expect(wrapper.vm.variant).toBe('');
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
it('handles large countries list', () => {
|
|
498
|
-
// Create a large list of country codes
|
|
499
|
-
const largeCountriesList = Array.from({ length: 100 }, (_, i) =>
|
|
500
|
-
`C${i.toString().padStart(2, '0')}`
|
|
501
|
-
);
|
|
502
|
-
|
|
503
|
-
const wrapper = mount(PhoneInput, {
|
|
504
|
-
props: {
|
|
505
|
-
countriesCodes: largeCountriesList
|
|
506
|
-
}
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
expect(wrapper.vm.countriesCodes).toHaveLength(100);
|
|
510
|
-
});
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
// Test attributes inheritance
|
|
514
|
-
describe('Attributes Inheritance', () => {
|
|
515
|
-
it('inherits v-bind="$attrs"', () => {
|
|
516
|
-
const wrapper = mount(PhoneInput, {
|
|
517
|
-
attrs: {
|
|
518
|
-
disabled: true,
|
|
519
|
-
readonly: true,
|
|
520
|
-
'data-custom': 'test'
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
// With mocked VPhoneInput, verify component renders
|
|
525
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
526
|
-
});
|
|
527
|
-
|
|
528
|
-
it('handles class inheritance', () => {
|
|
529
|
-
const wrapper = mount(PhoneInput, {
|
|
530
|
-
attrs: {
|
|
531
|
-
class: 'custom-phone-class'
|
|
532
|
-
}
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
// Should still have wl-phone-input class
|
|
536
|
-
expect(wrapper.find('.wl-phone-input').exists()).toBe(true);
|
|
537
|
-
});
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
// Test complex scenarios
|
|
541
|
-
describe('Complex Scenarios', () => {
|
|
542
|
-
it('works with all props configured', () => {
|
|
543
|
-
const wrapper = mount(PhoneInput, {
|
|
544
|
-
props: {
|
|
545
|
-
state: 'success',
|
|
546
|
-
placeholder: 'Enter international phone number',
|
|
547
|
-
countriesCodes: ['US', 'GB', 'FR', 'DE', 'ES'],
|
|
548
|
-
defaultCountryCode: 'US',
|
|
549
|
-
appendInnerIcon: 'mdi-phone-classic',
|
|
550
|
-
variant: 'filled',
|
|
551
|
-
borderOnHover: true
|
|
552
|
-
}
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
expect(wrapper.vm.state).toBe('success');
|
|
556
|
-
expect(wrapper.vm.placeholder).toBe('Enter international phone number');
|
|
557
|
-
expect(wrapper.vm.countriesCodes).toEqual(['US', 'GB', 'FR', 'DE', 'ES']);
|
|
558
|
-
expect(wrapper.vm.defaultCountryCode).toBe('US');
|
|
559
|
-
expect(wrapper.vm.appendInnerIcon).toBe('mdi-phone-classic');
|
|
560
|
-
expect(wrapper.vm.variant).toBe('filled');
|
|
561
|
-
expect(wrapper.vm.borderOnHover).toBe(true);
|
|
562
|
-
expect(wrapper.find('.border-on-hover').exists()).toBe(true);
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
it('handles state changes', async () => {
|
|
566
|
-
const wrapper = mount(PhoneInput, {
|
|
567
|
-
props: {
|
|
568
|
-
state: 'default'
|
|
569
|
-
}
|
|
570
|
-
});
|
|
571
|
-
|
|
572
|
-
expect(wrapper.vm.state).toBe('default');
|
|
573
|
-
|
|
574
|
-
await wrapper.setProps({ state: 'error' });
|
|
575
|
-
expect(wrapper.vm.state).toBe('error');
|
|
576
|
-
|
|
577
|
-
await wrapper.setProps({ state: 'success' });
|
|
578
|
-
expect(wrapper.vm.state).toBe('success');
|
|
579
|
-
|
|
580
|
-
await wrapper.setProps({ state: 'default' });
|
|
581
|
-
expect(wrapper.vm.state).toBe('default');
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
it('handles rapid prop changes', async () => {
|
|
585
|
-
const wrapper = mount(PhoneInput, {
|
|
586
|
-
props: {
|
|
587
|
-
placeholder: 'Initial',
|
|
588
|
-
defaultCountryCode: 'DE'
|
|
589
|
-
}
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
await wrapper.setProps({
|
|
593
|
-
placeholder: 'Updated phone',
|
|
594
|
-
defaultCountryCode: 'US',
|
|
595
|
-
variant: 'filled'
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
expect(wrapper.vm.placeholder).toBe('Updated phone');
|
|
599
|
-
expect(wrapper.vm.defaultCountryCode).toBe('US');
|
|
600
|
-
expect(wrapper.vm.variant).toBe('filled');
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
it('maintains functionality across all validation states', () => {
|
|
604
|
-
const states = ['default', 'error', 'success'];
|
|
605
|
-
|
|
606
|
-
states.forEach(state => {
|
|
607
|
-
const wrapper = mount(PhoneInput, {
|
|
608
|
-
props: {
|
|
609
|
-
state: state as any,
|
|
610
|
-
placeholder: `Phone in ${state} state`
|
|
611
|
-
}
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
expect(wrapper.vm.state).toBe(state);
|
|
615
|
-
expect(wrapper.vm.placeholder).toBe(`Phone in ${state} state`);
|
|
616
|
-
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
617
|
-
});
|
|
618
|
-
});
|
|
619
|
-
});
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { mount } from '@vue/test-utils';
|
|
3
|
+
import { nextTick } from 'vue';
|
|
4
|
+
import PhoneInput from '@components/PhoneInput/PhoneInput.vue';
|
|
5
|
+
|
|
6
|
+
// Mock v-phone-input
|
|
7
|
+
vi.mock('v-phone-input', () => ({
|
|
8
|
+
VPhoneInput: {
|
|
9
|
+
template: '<div data-testid="v-phone-input"><slot /></div>',
|
|
10
|
+
props: [
|
|
11
|
+
'include-countries', 'aria-label', 'variant', 'label', 'appendInnerIcon',
|
|
12
|
+
'placeHolder', 'display-format', 'default-country', 'hide-details',
|
|
13
|
+
'aria-invalid', 'countryIconMode'
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
describe('PhoneInput', () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.clearAllMocks();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Test default behavior and rendering
|
|
24
|
+
describe('Default Behavior', () => {
|
|
25
|
+
it('renders with default props', () => {
|
|
26
|
+
const wrapper = mount(PhoneInput);
|
|
27
|
+
|
|
28
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
29
|
+
expect(wrapper.find('.wl-phone-input').exists()).toBe(true);
|
|
30
|
+
expect(wrapper.vm.state).toBe('default');
|
|
31
|
+
expect(wrapper.vm.placeholder).toBe('');
|
|
32
|
+
expect(wrapper.vm.countriesCodes).toEqual([]);
|
|
33
|
+
expect(wrapper.vm.defaultCountryCode).toBe('DE');
|
|
34
|
+
expect(wrapper.vm.appendInnerIcon).toBe('heroicons:phone');
|
|
35
|
+
expect(wrapper.vm.variant).toBe('outlined');
|
|
36
|
+
expect(wrapper.vm.borderOnHover).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('has data-testid for testing', () => {
|
|
40
|
+
const wrapper = mount(PhoneInput);
|
|
41
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('applies wl-phone-input CSS class', () => {
|
|
45
|
+
const wrapper = mount(PhoneInput);
|
|
46
|
+
expect(wrapper.find('.wl-phone-input').exists()).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('sets id attribute to "phone"', () => {
|
|
50
|
+
const wrapper = mount(PhoneInput);
|
|
51
|
+
// Since VPhoneInput is mocked, we can't directly test the id
|
|
52
|
+
// but we can verify the component renders correctly
|
|
53
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Test validation states
|
|
58
|
+
describe('Validation States', () => {
|
|
59
|
+
it('handles default state', () => {
|
|
60
|
+
const wrapper = mount(PhoneInput, {
|
|
61
|
+
props: {
|
|
62
|
+
state: 'default'
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
expect(wrapper.vm.state).toBe('default');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('handles error state', () => {
|
|
70
|
+
const wrapper = mount(PhoneInput, {
|
|
71
|
+
props: {
|
|
72
|
+
state: 'error'
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(wrapper.vm.state).toBe('error');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('handles success state', () => {
|
|
80
|
+
const wrapper = mount(PhoneInput, {
|
|
81
|
+
props: {
|
|
82
|
+
state: 'success'
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
expect(wrapper.vm.state).toBe('success');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('sets aria-invalid based on error state', () => {
|
|
90
|
+
const errorWrapper = mount(PhoneInput, {
|
|
91
|
+
props: {
|
|
92
|
+
state: 'error'
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(errorWrapper.vm.state).toBe('error');
|
|
97
|
+
|
|
98
|
+
const defaultWrapper = mount(PhoneInput, {
|
|
99
|
+
props: {
|
|
100
|
+
state: 'default'
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(defaultWrapper.vm.state).toBe('default');
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Test placeholder functionality
|
|
109
|
+
describe('Placeholder', () => {
|
|
110
|
+
it('uses default empty placeholder', () => {
|
|
111
|
+
const wrapper = mount(PhoneInput);
|
|
112
|
+
expect(wrapper.vm.placeholder).toBe('');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('accepts custom placeholder', () => {
|
|
116
|
+
const wrapper = mount(PhoneInput, {
|
|
117
|
+
props: {
|
|
118
|
+
placeholder: 'Enter your phone number'
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(wrapper.vm.placeholder).toBe('Enter your phone number');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('uses placeholder for aria-label', () => {
|
|
126
|
+
const wrapper = mount(PhoneInput, {
|
|
127
|
+
props: {
|
|
128
|
+
placeholder: 'Phone number'
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
expect(wrapper.vm.placeholder).toBe('Phone number');
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Test country configuration
|
|
137
|
+
describe('Country Configuration', () => {
|
|
138
|
+
it('uses default country code DE', () => {
|
|
139
|
+
const wrapper = mount(PhoneInput);
|
|
140
|
+
expect(wrapper.vm.defaultCountryCode).toBe('DE');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('accepts custom default country code', () => {
|
|
144
|
+
const wrapper = mount(PhoneInput, {
|
|
145
|
+
props: {
|
|
146
|
+
defaultCountryCode: 'US'
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
expect(wrapper.vm.defaultCountryCode).toBe('US');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('uses empty countries list by default', () => {
|
|
154
|
+
const wrapper = mount(PhoneInput);
|
|
155
|
+
expect(wrapper.vm.countriesCodes).toEqual([]);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('accepts custom countries list', () => {
|
|
159
|
+
const countries = ['US', 'GB', 'FR', 'DE'];
|
|
160
|
+
const wrapper = mount(PhoneInput, {
|
|
161
|
+
props: {
|
|
162
|
+
countriesCodes: countries
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
expect(wrapper.vm.countriesCodes).toEqual(countries);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('handles single country in list', () => {
|
|
170
|
+
const wrapper = mount(PhoneInput, {
|
|
171
|
+
props: {
|
|
172
|
+
countriesCodes: ['US']
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
expect(wrapper.vm.countriesCodes).toEqual(['US']);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Test icons and styling
|
|
181
|
+
describe('Icons and Styling', () => {
|
|
182
|
+
it('uses default phone icon', () => {
|
|
183
|
+
const wrapper = mount(PhoneInput);
|
|
184
|
+
expect(wrapper.vm.appendInnerIcon).toBe('heroicons:phone');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('accepts custom append inner icon', () => {
|
|
188
|
+
const wrapper = mount(PhoneInput, {
|
|
189
|
+
props: {
|
|
190
|
+
appendInnerIcon: 'mdi-phone'
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
expect(wrapper.vm.appendInnerIcon).toBe('mdi-phone');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('uses default outlined variant', () => {
|
|
198
|
+
const wrapper = mount(PhoneInput);
|
|
199
|
+
expect(wrapper.vm.variant).toBe('outlined');
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('accepts custom variant', () => {
|
|
203
|
+
const variants = ['filled', 'outlined', 'underlined', 'solo'];
|
|
204
|
+
|
|
205
|
+
variants.forEach(variant => {
|
|
206
|
+
const wrapper = mount(PhoneInput, {
|
|
207
|
+
props: { variant }
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
expect(wrapper.vm.variant).toBe(variant);
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('handles border on hover', () => {
|
|
215
|
+
const wrapper = mount(PhoneInput, {
|
|
216
|
+
props: {
|
|
217
|
+
borderOnHover: true
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
expect(wrapper.find('.border-on-hover').exists()).toBe(true);
|
|
222
|
+
expect(wrapper.vm.borderOnHover).toBe(true);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('does not apply border-on-hover class by default', () => {
|
|
226
|
+
const wrapper = mount(PhoneInput);
|
|
227
|
+
|
|
228
|
+
expect(wrapper.find('.border-on-hover').exists()).toBe(false);
|
|
229
|
+
expect(wrapper.vm.borderOnHover).toBe(false);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Test event emission
|
|
234
|
+
describe('Event Emission', () => {
|
|
235
|
+
it('emits update:phone event', async () => {
|
|
236
|
+
const wrapper = mount(PhoneInput);
|
|
237
|
+
|
|
238
|
+
// Simulate the event that would be emitted by VPhoneInput
|
|
239
|
+
wrapper.vm.$emit('update:phone', '+1234567890');
|
|
240
|
+
|
|
241
|
+
expect(wrapper.emitted('update:phone')).toBeTruthy();
|
|
242
|
+
expect(wrapper.emitted('update:phone')?.[0]).toEqual(['+1234567890']);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('handles different phone number formats', async () => {
|
|
246
|
+
const wrapper = mount(PhoneInput);
|
|
247
|
+
|
|
248
|
+
const phoneNumbers = [
|
|
249
|
+
'+1 (555) 123-4567',
|
|
250
|
+
'+49 30 12345678',
|
|
251
|
+
'+44 20 7123 4567',
|
|
252
|
+
'555-123-4567'
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
phoneNumbers.forEach((phone, index) => {
|
|
256
|
+
wrapper.vm.$emit('update:phone', phone);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
expect(wrapper.emitted('update:phone')).toHaveLength(phoneNumbers.length);
|
|
260
|
+
phoneNumbers.forEach((phone, index) => {
|
|
261
|
+
expect(wrapper.emitted('update:phone')?.[index]).toEqual([phone]);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('handles empty phone number', async () => {
|
|
266
|
+
const wrapper = mount(PhoneInput);
|
|
267
|
+
|
|
268
|
+
wrapper.vm.$emit('update:phone', '');
|
|
269
|
+
|
|
270
|
+
expect(wrapper.emitted('update:phone')?.[0]).toEqual(['']);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Test exposed methods
|
|
275
|
+
describe('Exposed Methods', () => {
|
|
276
|
+
it('exposes focus, blur, and select methods', () => {
|
|
277
|
+
const wrapper = mount(PhoneInput);
|
|
278
|
+
|
|
279
|
+
expect(wrapper.vm.focus).toBeDefined();
|
|
280
|
+
expect(wrapper.vm.blur).toBeDefined();
|
|
281
|
+
expect(wrapper.vm.select).toBeDefined();
|
|
282
|
+
expect(typeof wrapper.vm.focus).toBe('function');
|
|
283
|
+
expect(typeof wrapper.vm.blur).toBe('function');
|
|
284
|
+
expect(typeof wrapper.vm.select).toBe('function');
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('getNativeInput returns null with mocked component', () => {
|
|
288
|
+
const wrapper = mount(PhoneInput);
|
|
289
|
+
const nativeInput = wrapper.vm.getNativeInput();
|
|
290
|
+
|
|
291
|
+
expect(nativeInput).toBeUndefined();
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('focus method works with mocked input', async () => {
|
|
295
|
+
const wrapper = mount(PhoneInput);
|
|
296
|
+
|
|
297
|
+
// Get the real input element from the stub
|
|
298
|
+
const nativeInput = wrapper.vm.getNativeInput();
|
|
299
|
+
if (nativeInput) {
|
|
300
|
+
const focusSpy = vi.spyOn(nativeInput, 'focus');
|
|
301
|
+
|
|
302
|
+
wrapper.vm.focus();
|
|
303
|
+
await nextTick();
|
|
304
|
+
|
|
305
|
+
expect(focusSpy).toHaveBeenCalled();
|
|
306
|
+
} else {
|
|
307
|
+
// If no input is found, just verify the method exists
|
|
308
|
+
expect(wrapper.vm.focus).toBeDefined();
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('blur method works with mocked input', async () => {
|
|
313
|
+
const wrapper = mount(PhoneInput);
|
|
314
|
+
|
|
315
|
+
// Get the real input element from the stub
|
|
316
|
+
const nativeInput = wrapper.vm.getNativeInput();
|
|
317
|
+
if (nativeInput) {
|
|
318
|
+
const blurSpy = vi.spyOn(nativeInput, 'blur');
|
|
319
|
+
|
|
320
|
+
wrapper.vm.blur();
|
|
321
|
+
await nextTick();
|
|
322
|
+
|
|
323
|
+
expect(blurSpy).toHaveBeenCalled();
|
|
324
|
+
} else {
|
|
325
|
+
// If no input is found, just verify the method exists
|
|
326
|
+
expect(wrapper.vm.blur).toBeDefined();
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
it('select method works with mocked input', async () => {
|
|
331
|
+
const wrapper = mount(PhoneInput);
|
|
332
|
+
|
|
333
|
+
// Get the real input element from the stub
|
|
334
|
+
const nativeInput = wrapper.vm.getNativeInput();
|
|
335
|
+
if (nativeInput) {
|
|
336
|
+
const selectSpy = vi.spyOn(nativeInput, 'select');
|
|
337
|
+
|
|
338
|
+
wrapper.vm.select();
|
|
339
|
+
await nextTick();
|
|
340
|
+
|
|
341
|
+
expect(selectSpy).toHaveBeenCalled();
|
|
342
|
+
} else {
|
|
343
|
+
// If no input is found, just verify the method exists
|
|
344
|
+
expect(wrapper.vm.select).toBeDefined();
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('handles null inputRef gracefully', () => {
|
|
349
|
+
const wrapper = mount(PhoneInput);
|
|
350
|
+
wrapper.vm.inputRef = null;
|
|
351
|
+
|
|
352
|
+
expect(() => wrapper.vm.focus()).not.toThrow();
|
|
353
|
+
expect(() => wrapper.vm.blur()).not.toThrow();
|
|
354
|
+
expect(() => wrapper.vm.select()).not.toThrow();
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Test VPhoneInput configuration
|
|
359
|
+
describe('VPhoneInput Configuration', () => {
|
|
360
|
+
it('configures VPhoneInput with correct props', () => {
|
|
361
|
+
const wrapper = mount(PhoneInput, {
|
|
362
|
+
props: {
|
|
363
|
+
placeholder: 'Enter phone',
|
|
364
|
+
variant: 'filled',
|
|
365
|
+
defaultCountryCode: 'US',
|
|
366
|
+
appendInnerIcon: 'mdi-phone',
|
|
367
|
+
borderOnHover: true
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// With mocked VPhoneInput, verify the component renders
|
|
372
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
373
|
+
expect(wrapper.vm.placeholder).toBe('Enter phone');
|
|
374
|
+
expect(wrapper.vm.variant).toBe('filled');
|
|
375
|
+
expect(wrapper.vm.defaultCountryCode).toBe('US');
|
|
376
|
+
expect(wrapper.vm.appendInnerIcon).toBe('mdi-phone');
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('sets display format to international', () => {
|
|
380
|
+
const wrapper = mount(PhoneInput);
|
|
381
|
+
|
|
382
|
+
// Verify component renders correctly (display-format is hardcoded in template)
|
|
383
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
it('hides details by default', () => {
|
|
387
|
+
const wrapper = mount(PhoneInput);
|
|
388
|
+
|
|
389
|
+
// hide-details is hardcoded in template
|
|
390
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('uses svg country icon mode', () => {
|
|
394
|
+
const wrapper = mount(PhoneInput);
|
|
395
|
+
|
|
396
|
+
// countryIconMode="svg" is hardcoded in template
|
|
397
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('sets empty label', () => {
|
|
401
|
+
const wrapper = mount(PhoneInput);
|
|
402
|
+
|
|
403
|
+
// label="" is hardcoded in template
|
|
404
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
// Test accessibility
|
|
409
|
+
describe('Accessibility', () => {
|
|
410
|
+
it('has data-testid for testing', () => {
|
|
411
|
+
const wrapper = mount(PhoneInput);
|
|
412
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it('sets aria-label from placeholder', () => {
|
|
416
|
+
const wrapper = mount(PhoneInput, {
|
|
417
|
+
props: {
|
|
418
|
+
placeholder: 'Enter your phone number'
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
expect(wrapper.vm.placeholder).toBe('Enter your phone number');
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
it('handles aria-invalid for error state', () => {
|
|
426
|
+
const wrapper = mount(PhoneInput, {
|
|
427
|
+
props: {
|
|
428
|
+
state: 'error'
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
expect(wrapper.vm.state).toBe('error');
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('provides meaningful placeholder text', () => {
|
|
436
|
+
const wrapper = mount(PhoneInput, {
|
|
437
|
+
props: {
|
|
438
|
+
placeholder: 'Phone number (including country code)'
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
expect(wrapper.vm.placeholder).toBe('Phone number (including country code)');
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
// Test edge cases
|
|
447
|
+
describe('Edge Cases', () => {
|
|
448
|
+
it('handles empty countries array', () => {
|
|
449
|
+
const wrapper = mount(PhoneInput, {
|
|
450
|
+
props: {
|
|
451
|
+
countriesCodes: []
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
expect(wrapper.vm.countriesCodes).toEqual([]);
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
it('handles invalid country codes gracefully', () => {
|
|
459
|
+
const wrapper = mount(PhoneInput, {
|
|
460
|
+
props: {
|
|
461
|
+
countriesCodes: ['XX', 'YY', 'ZZ'], // Invalid country codes
|
|
462
|
+
defaultCountryCode: 'XX'
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
expect(wrapper.vm.countriesCodes).toEqual(['XX', 'YY', 'ZZ']);
|
|
467
|
+
expect(wrapper.vm.defaultCountryCode).toBe('XX');
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it('handles special characters in placeholder', () => {
|
|
471
|
+
const specialPlaceholder = 'Téléphone (avec indicatif pays) +33...';
|
|
472
|
+
const wrapper = mount(PhoneInput, {
|
|
473
|
+
props: {
|
|
474
|
+
placeholder: specialPlaceholder
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
expect(wrapper.vm.placeholder).toBe(specialPlaceholder);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
it('handles empty string props', () => {
|
|
482
|
+
const wrapper = mount(PhoneInput, {
|
|
483
|
+
props: {
|
|
484
|
+
placeholder: '',
|
|
485
|
+
defaultCountryCode: '',
|
|
486
|
+
appendInnerIcon: '',
|
|
487
|
+
variant: ''
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
expect(wrapper.vm.placeholder).toBe('');
|
|
492
|
+
expect(wrapper.vm.defaultCountryCode).toBe('');
|
|
493
|
+
expect(wrapper.vm.appendInnerIcon).toBe('');
|
|
494
|
+
expect(wrapper.vm.variant).toBe('');
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
it('handles large countries list', () => {
|
|
498
|
+
// Create a large list of country codes
|
|
499
|
+
const largeCountriesList = Array.from({ length: 100 }, (_, i) =>
|
|
500
|
+
`C${i.toString().padStart(2, '0')}`
|
|
501
|
+
);
|
|
502
|
+
|
|
503
|
+
const wrapper = mount(PhoneInput, {
|
|
504
|
+
props: {
|
|
505
|
+
countriesCodes: largeCountriesList
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
expect(wrapper.vm.countriesCodes).toHaveLength(100);
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Test attributes inheritance
|
|
514
|
+
describe('Attributes Inheritance', () => {
|
|
515
|
+
it('inherits v-bind="$attrs"', () => {
|
|
516
|
+
const wrapper = mount(PhoneInput, {
|
|
517
|
+
attrs: {
|
|
518
|
+
disabled: true,
|
|
519
|
+
readonly: true,
|
|
520
|
+
'data-custom': 'test'
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
// With mocked VPhoneInput, verify component renders
|
|
525
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
it('handles class inheritance', () => {
|
|
529
|
+
const wrapper = mount(PhoneInput, {
|
|
530
|
+
attrs: {
|
|
531
|
+
class: 'custom-phone-class'
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// Should still have wl-phone-input class
|
|
536
|
+
expect(wrapper.find('.wl-phone-input').exists()).toBe(true);
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
// Test complex scenarios
|
|
541
|
+
describe('Complex Scenarios', () => {
|
|
542
|
+
it('works with all props configured', () => {
|
|
543
|
+
const wrapper = mount(PhoneInput, {
|
|
544
|
+
props: {
|
|
545
|
+
state: 'success',
|
|
546
|
+
placeholder: 'Enter international phone number',
|
|
547
|
+
countriesCodes: ['US', 'GB', 'FR', 'DE', 'ES'],
|
|
548
|
+
defaultCountryCode: 'US',
|
|
549
|
+
appendInnerIcon: 'mdi-phone-classic',
|
|
550
|
+
variant: 'filled',
|
|
551
|
+
borderOnHover: true
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
expect(wrapper.vm.state).toBe('success');
|
|
556
|
+
expect(wrapper.vm.placeholder).toBe('Enter international phone number');
|
|
557
|
+
expect(wrapper.vm.countriesCodes).toEqual(['US', 'GB', 'FR', 'DE', 'ES']);
|
|
558
|
+
expect(wrapper.vm.defaultCountryCode).toBe('US');
|
|
559
|
+
expect(wrapper.vm.appendInnerIcon).toBe('mdi-phone-classic');
|
|
560
|
+
expect(wrapper.vm.variant).toBe('filled');
|
|
561
|
+
expect(wrapper.vm.borderOnHover).toBe(true);
|
|
562
|
+
expect(wrapper.find('.border-on-hover').exists()).toBe(true);
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
it('handles state changes', async () => {
|
|
566
|
+
const wrapper = mount(PhoneInput, {
|
|
567
|
+
props: {
|
|
568
|
+
state: 'default'
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
expect(wrapper.vm.state).toBe('default');
|
|
573
|
+
|
|
574
|
+
await wrapper.setProps({ state: 'error' });
|
|
575
|
+
expect(wrapper.vm.state).toBe('error');
|
|
576
|
+
|
|
577
|
+
await wrapper.setProps({ state: 'success' });
|
|
578
|
+
expect(wrapper.vm.state).toBe('success');
|
|
579
|
+
|
|
580
|
+
await wrapper.setProps({ state: 'default' });
|
|
581
|
+
expect(wrapper.vm.state).toBe('default');
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
it('handles rapid prop changes', async () => {
|
|
585
|
+
const wrapper = mount(PhoneInput, {
|
|
586
|
+
props: {
|
|
587
|
+
placeholder: 'Initial',
|
|
588
|
+
defaultCountryCode: 'DE'
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
await wrapper.setProps({
|
|
593
|
+
placeholder: 'Updated phone',
|
|
594
|
+
defaultCountryCode: 'US',
|
|
595
|
+
variant: 'filled'
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
expect(wrapper.vm.placeholder).toBe('Updated phone');
|
|
599
|
+
expect(wrapper.vm.defaultCountryCode).toBe('US');
|
|
600
|
+
expect(wrapper.vm.variant).toBe('filled');
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
it('maintains functionality across all validation states', () => {
|
|
604
|
+
const states = ['default', 'error', 'success'];
|
|
605
|
+
|
|
606
|
+
states.forEach(state => {
|
|
607
|
+
const wrapper = mount(PhoneInput, {
|
|
608
|
+
props: {
|
|
609
|
+
state: state as any,
|
|
610
|
+
placeholder: `Phone in ${state} state`
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
expect(wrapper.vm.state).toBe(state);
|
|
615
|
+
expect(wrapper.vm.placeholder).toBe(`Phone in ${state} state`);
|
|
616
|
+
expect(wrapper.find('[data-testid="root"]').exists()).toBe(true);
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
620
|
});
|