@htlkg/components 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/composables/index.js +206 -19
- package/dist/composables/index.js.map +1 -1
- package/package.json +40 -40
- package/src/composables/__test-useTable__.ts +34 -0
- package/src/composables/index.ts +1 -1
- package/src/composables/useTable.md +350 -0
- package/src/composables/useTable.ts +328 -27
- package/src/data/Table.demo.vue +26 -10
- package/src/data/Table.vue +13 -39
- package/src/forms/JsonSchemaForm.test.ts +98 -168
- package/src/forms/JsonSchemaForm.unit.test.ts +97 -45
- package/src/forms/JsonSchemaForm.vue +17 -1
- package/src/index.ts +3 -0
- package/src/navigation/AdminWrapper.vue +198 -0
- package/src/navigation/Tabs.test.ts +55 -27
- package/src/navigation/index.ts +1 -0
- package/src/overlays/Alert.test.ts +39 -74
- package/src/overlays/Drawer.test.ts +57 -23
- package/src/overlays/Modal.test.ts +54 -42
- package/src/stores/index.ts +7 -0
- package/src/stores/user.ts +33 -0
- package/src/test-setup.ts +235 -0
|
@@ -24,38 +24,37 @@ describe('Tabs Component', () => {
|
|
|
24
24
|
const wrapper = mount(Tabs, {
|
|
25
25
|
props: {
|
|
26
26
|
tabs: mockTabs,
|
|
27
|
-
|
|
28
|
-
'onUpdate:
|
|
27
|
+
modelValue: 'tab1',
|
|
28
|
+
'onUpdate:modelValue': (value: string) => wrapper.setProps({ modelValue: value })
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
expect(wrapper.props('
|
|
32
|
+
expect(wrapper.props('modelValue')).toBe('tab1');
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
|
|
34
|
+
// Click on tab2
|
|
35
|
+
const buttons = wrapper.findAll('button');
|
|
36
|
+
await buttons[1].trigger('click');
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
expect(wrapper.emitted('update:
|
|
40
|
-
expect(wrapper.emitted('update:activeTab')?.[0]).toEqual(['tab2']);
|
|
38
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
|
|
39
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['tab2']);
|
|
41
40
|
});
|
|
42
41
|
|
|
43
42
|
it('emits tab-change event when tab is clicked', async () => {
|
|
44
43
|
const wrapper = mount(Tabs, {
|
|
45
44
|
props: {
|
|
46
45
|
tabs: mockTabs,
|
|
47
|
-
|
|
46
|
+
modelValue: 'tab1'
|
|
48
47
|
}
|
|
49
48
|
});
|
|
50
49
|
|
|
51
|
-
const
|
|
52
|
-
|
|
50
|
+
const buttons = wrapper.findAll('button');
|
|
51
|
+
await buttons[1].trigger('click');
|
|
53
52
|
|
|
54
53
|
expect(wrapper.emitted('tab-change')).toBeTruthy();
|
|
55
54
|
expect(wrapper.emitted('tab-change')?.[0]).toEqual(['tab2']);
|
|
56
55
|
});
|
|
57
56
|
|
|
58
|
-
it('defaults to first tab when no
|
|
57
|
+
it('defaults to first tab when no modelValue is provided', () => {
|
|
59
58
|
const wrapper = mount(Tabs, {
|
|
60
59
|
props: {
|
|
61
60
|
tabs: mockTabs
|
|
@@ -63,14 +62,14 @@ describe('Tabs Component', () => {
|
|
|
63
62
|
});
|
|
64
63
|
|
|
65
64
|
const component = wrapper.vm as any;
|
|
66
|
-
expect(component.
|
|
65
|
+
expect(component.getActiveTab()).toBe('tab1');
|
|
67
66
|
});
|
|
68
67
|
|
|
69
|
-
it('exposes setActiveTab method', () => {
|
|
68
|
+
it('exposes setActiveTab method', async () => {
|
|
70
69
|
const wrapper = mount(Tabs, {
|
|
71
70
|
props: {
|
|
72
71
|
tabs: mockTabs,
|
|
73
|
-
|
|
72
|
+
modelValue: 'tab1'
|
|
74
73
|
}
|
|
75
74
|
});
|
|
76
75
|
|
|
@@ -79,14 +78,15 @@ describe('Tabs Component', () => {
|
|
|
79
78
|
expect(typeof component.setActiveTab).toBe('function');
|
|
80
79
|
|
|
81
80
|
component.setActiveTab('tab3');
|
|
82
|
-
|
|
81
|
+
await wrapper.vm.$nextTick();
|
|
82
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
it('exposes getActiveTab method', () => {
|
|
86
86
|
const wrapper = mount(Tabs, {
|
|
87
87
|
props: {
|
|
88
88
|
tabs: mockTabs,
|
|
89
|
-
|
|
89
|
+
modelValue: 'tab2'
|
|
90
90
|
}
|
|
91
91
|
});
|
|
92
92
|
|
|
@@ -100,7 +100,7 @@ describe('Tabs Component', () => {
|
|
|
100
100
|
const wrapper = mount(Tabs, {
|
|
101
101
|
props: {
|
|
102
102
|
tabs: mockTabs,
|
|
103
|
-
|
|
103
|
+
modelValue: 'tab1'
|
|
104
104
|
}
|
|
105
105
|
});
|
|
106
106
|
|
|
@@ -108,15 +108,15 @@ describe('Tabs Component', () => {
|
|
|
108
108
|
component.nextTab();
|
|
109
109
|
|
|
110
110
|
await wrapper.vm.$nextTick();
|
|
111
|
-
expect(wrapper.emitted('update:
|
|
112
|
-
expect(wrapper.emitted('update:
|
|
111
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
|
|
112
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['tab2']);
|
|
113
113
|
});
|
|
114
114
|
|
|
115
115
|
it('exposes previousTab method', async () => {
|
|
116
116
|
const wrapper = mount(Tabs, {
|
|
117
117
|
props: {
|
|
118
118
|
tabs: mockTabs,
|
|
119
|
-
|
|
119
|
+
modelValue: 'tab2'
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
|
|
@@ -124,15 +124,15 @@ describe('Tabs Component', () => {
|
|
|
124
124
|
component.previousTab();
|
|
125
125
|
|
|
126
126
|
await wrapper.vm.$nextTick();
|
|
127
|
-
expect(wrapper.emitted('update:
|
|
128
|
-
expect(wrapper.emitted('update:
|
|
127
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy();
|
|
128
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['tab1']);
|
|
129
129
|
});
|
|
130
130
|
|
|
131
131
|
it('does not go beyond last tab with nextTab', async () => {
|
|
132
132
|
const wrapper = mount(Tabs, {
|
|
133
133
|
props: {
|
|
134
134
|
tabs: mockTabs,
|
|
135
|
-
|
|
135
|
+
modelValue: 'tab3'
|
|
136
136
|
}
|
|
137
137
|
});
|
|
138
138
|
|
|
@@ -142,13 +142,14 @@ describe('Tabs Component', () => {
|
|
|
142
142
|
await wrapper.vm.$nextTick();
|
|
143
143
|
// Should not emit since we're already at the last tab
|
|
144
144
|
expect(component.getActiveTab()).toBe('tab3');
|
|
145
|
+
expect(wrapper.emitted('update:modelValue')).toBeFalsy();
|
|
145
146
|
});
|
|
146
147
|
|
|
147
148
|
it('does not go before first tab with previousTab', async () => {
|
|
148
149
|
const wrapper = mount(Tabs, {
|
|
149
150
|
props: {
|
|
150
151
|
tabs: mockTabs,
|
|
151
|
-
|
|
152
|
+
modelValue: 'tab1'
|
|
152
153
|
}
|
|
153
154
|
});
|
|
154
155
|
|
|
@@ -158,13 +159,14 @@ describe('Tabs Component', () => {
|
|
|
158
159
|
await wrapper.vm.$nextTick();
|
|
159
160
|
// Should not emit since we're already at the first tab
|
|
160
161
|
expect(component.getActiveTab()).toBe('tab1');
|
|
162
|
+
expect(wrapper.emitted('update:modelValue')).toBeFalsy();
|
|
161
163
|
});
|
|
162
164
|
|
|
163
165
|
it('renders tab content slot', () => {
|
|
164
166
|
const wrapper = mount(Tabs, {
|
|
165
167
|
props: {
|
|
166
168
|
tabs: mockTabs,
|
|
167
|
-
|
|
169
|
+
modelValue: 'tab1'
|
|
168
170
|
},
|
|
169
171
|
slots: {
|
|
170
172
|
tab1: '<div class="tab1-content">Tab 1 Content</div>'
|
|
@@ -172,5 +174,31 @@ describe('Tabs Component', () => {
|
|
|
172
174
|
});
|
|
173
175
|
|
|
174
176
|
expect(wrapper.find('.tabs-content').exists()).toBe(true);
|
|
177
|
+
expect(wrapper.html()).toContain('Tab 1 Content');
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('renders tab labels', () => {
|
|
181
|
+
const wrapper = mount(Tabs, {
|
|
182
|
+
props: {
|
|
183
|
+
tabs: mockTabs
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
expect(wrapper.text()).toContain('Tab 1');
|
|
188
|
+
expect(wrapper.text()).toContain('Tab 2');
|
|
189
|
+
expect(wrapper.text()).toContain('Tab 3');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('shows count badges when provided', () => {
|
|
193
|
+
const wrapper = mount(Tabs, {
|
|
194
|
+
props: {
|
|
195
|
+
tabs: mockTabs,
|
|
196
|
+
modelValue: 'tab1'
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Tab 1 has count 5, Tab 2 has count 10
|
|
201
|
+
expect(wrapper.text()).toContain('5');
|
|
202
|
+
expect(wrapper.text()).toContain('10');
|
|
175
203
|
});
|
|
176
204
|
});
|
package/src/navigation/index.ts
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { shallowMount } from '@vue/test-utils';
|
|
3
|
+
import { h, defineComponent } from 'vue';
|
|
4
|
+
|
|
5
|
+
// Mock the @hotelinking/ui module before importing the component
|
|
6
|
+
vi.mock('@hotelinking/ui', () => ({
|
|
7
|
+
uiAlert: defineComponent({
|
|
8
|
+
name: 'uiAlert',
|
|
9
|
+
props: ['title', 'type', 'actions', 'loading'],
|
|
10
|
+
emits: ['alert-event'],
|
|
11
|
+
setup(props, { slots, emit }) {
|
|
12
|
+
return () => h('div', { class: 'ui-alert', 'data-type': props.type }, [
|
|
13
|
+
h('div', { class: 'alert-title' }, props.title),
|
|
14
|
+
slots.default?.(),
|
|
15
|
+
props.actions?.map((action: any, index: number) =>
|
|
16
|
+
h('button', {
|
|
17
|
+
key: index,
|
|
18
|
+
class: 'alert-action',
|
|
19
|
+
onClick: () => emit('alert-event', action.event)
|
|
20
|
+
}, action.name)
|
|
21
|
+
)
|
|
22
|
+
]);
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
// Import after mocking
|
|
3
28
|
import Alert from './Alert.vue';
|
|
4
29
|
|
|
5
30
|
describe('Alert Component', () => {
|
|
6
31
|
it('renders with basic props', () => {
|
|
7
|
-
const wrapper =
|
|
32
|
+
const wrapper = shallowMount(Alert, {
|
|
8
33
|
props: {
|
|
9
34
|
title: 'Test Alert',
|
|
10
35
|
type: 'info'
|
|
@@ -18,7 +43,7 @@ describe('Alert Component', () => {
|
|
|
18
43
|
const types = ['info', 'success', 'warning', 'danger'] as const;
|
|
19
44
|
|
|
20
45
|
types.forEach(type => {
|
|
21
|
-
const wrapper =
|
|
46
|
+
const wrapper = shallowMount(Alert, {
|
|
22
47
|
props: {
|
|
23
48
|
title: 'Test Alert',
|
|
24
49
|
type
|
|
@@ -35,7 +60,7 @@ describe('Alert Component', () => {
|
|
|
35
60
|
{ name: 'Cancel', event: 'cancel' }
|
|
36
61
|
];
|
|
37
62
|
|
|
38
|
-
const wrapper =
|
|
63
|
+
const wrapper = shallowMount(Alert, {
|
|
39
64
|
props: {
|
|
40
65
|
title: 'Test Alert',
|
|
41
66
|
type: 'warning',
|
|
@@ -47,25 +72,8 @@ describe('Alert Component', () => {
|
|
|
47
72
|
expect(wrapper.props('actions')).toEqual(actions);
|
|
48
73
|
});
|
|
49
74
|
|
|
50
|
-
it('emits alertEvent when action is triggered', async () => {
|
|
51
|
-
const wrapper = mount(Alert, {
|
|
52
|
-
props: {
|
|
53
|
-
title: 'Test Alert',
|
|
54
|
-
type: 'info',
|
|
55
|
-
actions: [{ name: 'OK', event: 'ok' }]
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
const component = wrapper.vm as any;
|
|
60
|
-
if (component.handleAlertEvent) {
|
|
61
|
-
component.handleAlertEvent('ok');
|
|
62
|
-
expect(wrapper.emitted('alertEvent')).toBeTruthy();
|
|
63
|
-
expect(wrapper.emitted('alertEvent')?.[0]).toEqual(['ok']);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
75
|
it('renders with show prop', () => {
|
|
68
|
-
const wrapper =
|
|
76
|
+
const wrapper = shallowMount(Alert, {
|
|
69
77
|
props: {
|
|
70
78
|
title: 'Test Alert',
|
|
71
79
|
type: 'info',
|
|
@@ -78,7 +86,7 @@ describe('Alert Component', () => {
|
|
|
78
86
|
});
|
|
79
87
|
|
|
80
88
|
it('hides when show is false', () => {
|
|
81
|
-
const wrapper =
|
|
89
|
+
const wrapper = shallowMount(Alert, {
|
|
82
90
|
props: {
|
|
83
91
|
title: 'Test Alert',
|
|
84
92
|
type: 'info',
|
|
@@ -86,28 +94,12 @@ describe('Alert Component', () => {
|
|
|
86
94
|
}
|
|
87
95
|
});
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
it('supports v-model for show state', async () => {
|
|
93
|
-
const wrapper = mount(Alert, {
|
|
94
|
-
props: {
|
|
95
|
-
title: 'Test Alert',
|
|
96
|
-
type: 'info',
|
|
97
|
-
show: false,
|
|
98
|
-
'onUpdate:show': (value: boolean) => wrapper.setProps({ show: value })
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const component = wrapper.vm as any;
|
|
103
|
-
component.show();
|
|
104
|
-
|
|
105
|
-
await wrapper.vm.$nextTick();
|
|
106
|
-
expect(wrapper.emitted('update:show')).toBeTruthy();
|
|
97
|
+
// When show is false, the alert should not render its content
|
|
98
|
+
expect(wrapper.find('.ui-alert').exists()).toBe(false);
|
|
107
99
|
});
|
|
108
100
|
|
|
109
101
|
it('exposes show, hide, and toggle methods', () => {
|
|
110
|
-
const wrapper =
|
|
102
|
+
const wrapper = shallowMount(Alert, {
|
|
111
103
|
props: {
|
|
112
104
|
title: 'Test Alert',
|
|
113
105
|
type: 'info'
|
|
@@ -115,40 +107,13 @@ describe('Alert Component', () => {
|
|
|
115
107
|
});
|
|
116
108
|
|
|
117
109
|
const component = wrapper.vm as any;
|
|
118
|
-
expect(component.show).
|
|
119
|
-
expect(component.hide).
|
|
120
|
-
expect(component.toggle).
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('renders with loading state', () => {
|
|
124
|
-
const wrapper = mount(Alert, {
|
|
125
|
-
props: {
|
|
126
|
-
title: 'Loading Alert',
|
|
127
|
-
type: 'info',
|
|
128
|
-
loading: true
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
expect(wrapper.exists()).toBe(true);
|
|
133
|
-
expect(wrapper.props('loading')).toBe(true);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('renders slot content', () => {
|
|
137
|
-
const wrapper = mount(Alert, {
|
|
138
|
-
props: {
|
|
139
|
-
title: 'Test Alert',
|
|
140
|
-
type: 'info'
|
|
141
|
-
},
|
|
142
|
-
slots: {
|
|
143
|
-
default: '<p>Custom alert content</p>'
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
expect(wrapper.html()).toContain('Custom alert content');
|
|
110
|
+
expect(typeof component.show).toBe('function');
|
|
111
|
+
expect(typeof component.hide).toBe('function');
|
|
112
|
+
expect(typeof component.toggle).toBe('function');
|
|
148
113
|
});
|
|
149
114
|
|
|
150
115
|
it('emits close event when hidden', async () => {
|
|
151
|
-
const wrapper =
|
|
116
|
+
const wrapper = shallowMount(Alert, {
|
|
152
117
|
props: {
|
|
153
118
|
title: 'Test Alert',
|
|
154
119
|
type: 'info',
|
|
@@ -12,24 +12,18 @@ describe('Drawer Component', () => {
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
expect(wrapper.exists()).toBe(true);
|
|
15
|
+
expect(wrapper.find('.fixed').exists()).toBe(true);
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
it('
|
|
18
|
+
it('does not render when closed', () => {
|
|
18
19
|
const wrapper = mount(Drawer, {
|
|
19
20
|
props: {
|
|
20
21
|
open: false,
|
|
21
|
-
|
|
22
|
+
title: 'Test Drawer'
|
|
22
23
|
}
|
|
23
24
|
});
|
|
24
25
|
|
|
25
|
-
expect(wrapper.
|
|
26
|
-
|
|
27
|
-
const component = wrapper.vm as any;
|
|
28
|
-
if (component.open) {
|
|
29
|
-
component.open();
|
|
30
|
-
await wrapper.vm.$nextTick();
|
|
31
|
-
expect(wrapper.emitted('update:open')).toBeTruthy();
|
|
32
|
-
}
|
|
26
|
+
expect(wrapper.find('.fixed').exists()).toBe(false);
|
|
33
27
|
});
|
|
34
28
|
|
|
35
29
|
it('emits close event when drawer is closed', async () => {
|
|
@@ -40,15 +34,15 @@ describe('Drawer Component', () => {
|
|
|
40
34
|
});
|
|
41
35
|
|
|
42
36
|
const component = wrapper.vm as any;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
component.close();
|
|
38
|
+
|
|
39
|
+
await wrapper.vm.$nextTick();
|
|
40
|
+
expect(wrapper.emitted('update:open')).toBeTruthy();
|
|
41
|
+
expect(wrapper.emitted('update:open')?.[0]).toEqual([false]);
|
|
42
|
+
expect(wrapper.emitted('close')).toBeTruthy();
|
|
49
43
|
});
|
|
50
44
|
|
|
51
|
-
it('exposes open and
|
|
45
|
+
it('exposes open, close, and toggle methods', () => {
|
|
52
46
|
const wrapper = mount(Drawer, {
|
|
53
47
|
props: {
|
|
54
48
|
open: false
|
|
@@ -56,20 +50,19 @@ describe('Drawer Component', () => {
|
|
|
56
50
|
});
|
|
57
51
|
|
|
58
52
|
const component = wrapper.vm as any;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
53
|
+
expect(typeof component.open).toBe('function');
|
|
54
|
+
expect(typeof component.close).toBe('function');
|
|
55
|
+
expect(typeof component.toggle).toBe('function');
|
|
63
56
|
});
|
|
64
57
|
|
|
65
58
|
it('renders with different positions', () => {
|
|
66
|
-
const positions = ['left', 'right', 'top', 'bottom'];
|
|
59
|
+
const positions = ['left', 'right', 'top', 'bottom'] as const;
|
|
67
60
|
|
|
68
61
|
positions.forEach(position => {
|
|
69
62
|
const wrapper = mount(Drawer, {
|
|
70
63
|
props: {
|
|
71
64
|
open: true,
|
|
72
|
-
position
|
|
65
|
+
position
|
|
73
66
|
}
|
|
74
67
|
});
|
|
75
68
|
|
|
@@ -88,5 +81,46 @@ describe('Drawer Component', () => {
|
|
|
88
81
|
});
|
|
89
82
|
|
|
90
83
|
expect(wrapper.html()).toContain('drawer-content');
|
|
84
|
+
expect(wrapper.html()).toContain('Custom Content');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('closes when clicking overlay', async () => {
|
|
88
|
+
const wrapper = mount(Drawer, {
|
|
89
|
+
props: {
|
|
90
|
+
open: true
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Click the overlay (first fixed div)
|
|
95
|
+
await wrapper.find('.bg-black').trigger('click');
|
|
96
|
+
|
|
97
|
+
expect(wrapper.emitted('update:open')).toBeTruthy();
|
|
98
|
+
expect(wrapper.emitted('update:open')?.[0]).toEqual([false]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('does not close when clicking drawer content', async () => {
|
|
102
|
+
const wrapper = mount(Drawer, {
|
|
103
|
+
props: {
|
|
104
|
+
open: true
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Click the drawer content area (the white bg div)
|
|
109
|
+
const drawerContent = wrapper.find('.bg-white');
|
|
110
|
+
await drawerContent.trigger('click');
|
|
111
|
+
|
|
112
|
+
// Should not emit close
|
|
113
|
+
expect(wrapper.emitted('update:open')).toBeFalsy();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('displays title', () => {
|
|
117
|
+
const wrapper = mount(Drawer, {
|
|
118
|
+
props: {
|
|
119
|
+
open: true,
|
|
120
|
+
title: 'My Drawer Title'
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
expect(wrapper.text()).toContain('My Drawer Title');
|
|
91
125
|
});
|
|
92
126
|
});
|
|
@@ -1,5 +1,31 @@
|
|
|
1
|
-
import { describe, it, expect, beforeAll } from 'vitest';
|
|
2
|
-
import { mount } from '@vue/test-utils';
|
|
1
|
+
import { describe, it, expect, vi, beforeAll, beforeEach } from 'vitest';
|
|
2
|
+
import { mount, shallowMount } from '@vue/test-utils';
|
|
3
|
+
import { h, defineComponent } from 'vue';
|
|
4
|
+
|
|
5
|
+
// Mock the @hotelinking/ui module before importing the component
|
|
6
|
+
vi.mock('@hotelinking/ui', () => ({
|
|
7
|
+
uiModal: defineComponent({
|
|
8
|
+
name: 'uiModal',
|
|
9
|
+
props: ['title', 'content', 'modalName', 'open', 'actions'],
|
|
10
|
+
emits: ['modalAction'],
|
|
11
|
+
setup(props, { slots, emit }) {
|
|
12
|
+
return () => props.open ? h('div', { class: 'ui-modal' }, [
|
|
13
|
+
h('div', { class: 'modal-title' }, props.title),
|
|
14
|
+
h('div', { class: 'modal-content' }, props.content),
|
|
15
|
+
slots.default?.(),
|
|
16
|
+
props.actions?.map((action: any, index: number) =>
|
|
17
|
+
h('button', {
|
|
18
|
+
key: index,
|
|
19
|
+
class: 'modal-action',
|
|
20
|
+
onClick: () => emit('modalAction', { modal: props.modalName, action: action.value })
|
|
21
|
+
}, action.text)
|
|
22
|
+
)
|
|
23
|
+
]) : null;
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
// Import after mocking
|
|
3
29
|
import Modal from './Modal.vue';
|
|
4
30
|
|
|
5
31
|
// Mock ResizeObserver
|
|
@@ -13,7 +39,7 @@ beforeAll(() => {
|
|
|
13
39
|
|
|
14
40
|
describe('Modal Component', () => {
|
|
15
41
|
it('renders with basic props', () => {
|
|
16
|
-
const wrapper =
|
|
42
|
+
const wrapper = shallowMount(Modal, {
|
|
17
43
|
props: {
|
|
18
44
|
open: true,
|
|
19
45
|
title: 'Test Modal',
|
|
@@ -24,8 +50,19 @@ describe('Modal Component', () => {
|
|
|
24
50
|
expect(wrapper.exists()).toBe(true);
|
|
25
51
|
});
|
|
26
52
|
|
|
53
|
+
it('does not render modal content when closed', () => {
|
|
54
|
+
const wrapper = shallowMount(Modal, {
|
|
55
|
+
props: {
|
|
56
|
+
open: false,
|
|
57
|
+
title: 'Test Modal'
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
expect(wrapper.find('.ui-modal').exists()).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
|
|
27
64
|
it('supports v-model for open state', async () => {
|
|
28
|
-
const wrapper =
|
|
65
|
+
const wrapper = shallowMount(Modal, {
|
|
29
66
|
props: {
|
|
30
67
|
open: false,
|
|
31
68
|
'onUpdate:open': (value: boolean) => wrapper.setProps({ open: value })
|
|
@@ -34,7 +71,6 @@ describe('Modal Component', () => {
|
|
|
34
71
|
|
|
35
72
|
expect(wrapper.props('open')).toBe(false);
|
|
36
73
|
|
|
37
|
-
// Open the modal using exposed method
|
|
38
74
|
const component = wrapper.vm as any;
|
|
39
75
|
component.open();
|
|
40
76
|
|
|
@@ -44,7 +80,7 @@ describe('Modal Component', () => {
|
|
|
44
80
|
});
|
|
45
81
|
|
|
46
82
|
it('emits close event when modal is closed', async () => {
|
|
47
|
-
const wrapper =
|
|
83
|
+
const wrapper = shallowMount(Modal, {
|
|
48
84
|
props: {
|
|
49
85
|
open: true
|
|
50
86
|
}
|
|
@@ -60,23 +96,20 @@ describe('Modal Component', () => {
|
|
|
60
96
|
});
|
|
61
97
|
|
|
62
98
|
it('exposes open, close, and toggle methods', () => {
|
|
63
|
-
const wrapper =
|
|
99
|
+
const wrapper = shallowMount(Modal, {
|
|
64
100
|
props: {
|
|
65
101
|
open: false
|
|
66
102
|
}
|
|
67
103
|
});
|
|
68
104
|
|
|
69
105
|
const component = wrapper.vm as any;
|
|
70
|
-
expect(component.open).toBeDefined();
|
|
71
|
-
expect(component.close).toBeDefined();
|
|
72
|
-
expect(component.toggle).toBeDefined();
|
|
73
106
|
expect(typeof component.open).toBe('function');
|
|
74
107
|
expect(typeof component.close).toBe('function');
|
|
75
108
|
expect(typeof component.toggle).toBe('function');
|
|
76
109
|
});
|
|
77
110
|
|
|
78
|
-
it('
|
|
79
|
-
const wrapper =
|
|
111
|
+
it('renders with actions', () => {
|
|
112
|
+
const wrapper = shallowMount(Modal, {
|
|
80
113
|
props: {
|
|
81
114
|
open: true,
|
|
82
115
|
actions: [
|
|
@@ -86,43 +119,22 @@ describe('Modal Component', () => {
|
|
|
86
119
|
}
|
|
87
120
|
});
|
|
88
121
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
expect(wrapper.emitted('action')).toBeTruthy();
|
|
93
|
-
expect(wrapper.emitted('action')?.[0]).toEqual([{ value: 'confirm' }]);
|
|
122
|
+
expect(wrapper.exists()).toBe(true);
|
|
123
|
+
expect(wrapper.props('actions')).toHaveLength(2);
|
|
94
124
|
});
|
|
95
125
|
|
|
96
|
-
it('
|
|
97
|
-
const wrapper =
|
|
126
|
+
it('toggle method switches open state', async () => {
|
|
127
|
+
const wrapper = shallowMount(Modal, {
|
|
98
128
|
props: {
|
|
99
|
-
open:
|
|
129
|
+
open: false
|
|
100
130
|
}
|
|
101
131
|
});
|
|
102
132
|
|
|
103
133
|
const component = wrapper.vm as any;
|
|
104
|
-
|
|
105
|
-
|
|
134
|
+
|
|
135
|
+
// Toggle to open
|
|
136
|
+
component.toggle();
|
|
106
137
|
await wrapper.vm.$nextTick();
|
|
107
|
-
expect(wrapper.emitted('update:open')).
|
|
108
|
-
expect(wrapper.emitted('update:open')?.[0]).toEqual([false]);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('renders slots correctly', () => {
|
|
112
|
-
const wrapper = mount(Modal, {
|
|
113
|
-
props: {
|
|
114
|
-
open: true
|
|
115
|
-
},
|
|
116
|
-
slots: {
|
|
117
|
-
default: '<div class="custom-content">Custom Content</div>',
|
|
118
|
-
header: '<div class="custom-header">Custom Header</div>',
|
|
119
|
-
footer: '<div class="custom-footer">Custom Footer</div>'
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
// Modal uses uiModal which may not render slots immediately in test environment
|
|
124
|
-
// Just verify the component exists and has the right props
|
|
125
|
-
expect(wrapper.exists()).toBe(true);
|
|
126
|
-
expect(wrapper.props('open')).toBe(true);
|
|
138
|
+
expect(wrapper.emitted('update:open')?.[0]).toEqual([true]);
|
|
127
139
|
});
|
|
128
140
|
});
|