@datametria/vue-components 1.2.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +554 -657
- package/dist/index.es.js +2570 -1433
- package/dist/index.umd.js +10 -10
- package/dist/vue-components.css +1 -1
- package/package.json +102 -98
- package/src/components/DatametriaAlert.vue +137 -137
- package/src/components/DatametriaAutocomplete.vue +184 -138
- package/src/components/DatametriaAvatar.vue +177 -33
- package/src/components/DatametriaBadge.vue +98 -98
- package/src/components/DatametriaBreadcrumb.vue +21 -21
- package/src/components/DatametriaButton.vue +177 -165
- package/src/components/DatametriaCard.vue +12 -12
- package/src/components/DatametriaCheckbox.vue +8 -8
- package/src/components/DatametriaChip.vue +145 -149
- package/src/components/DatametriaContainer.vue +4 -4
- package/src/components/DatametriaDatePicker.vue +686 -68
- package/src/components/DatametriaDivider.vue +13 -13
- package/src/components/DatametriaFileUpload.vue +272 -140
- package/src/components/DatametriaFloatingBar.vue +126 -0
- package/src/components/DatametriaGrid.vue +3 -3
- package/src/components/DatametriaInput.vue +15 -15
- package/src/components/DatametriaMenu.vue +604 -619
- package/src/components/DatametriaModal.vue +16 -16
- package/src/components/DatametriaNavbar.vue +230 -252
- package/src/components/DatametriaPasswordInput.vue +430 -0
- package/src/components/DatametriaProgress.vue +18 -18
- package/src/components/DatametriaRadio.vue +20 -20
- package/src/components/DatametriaSelect.vue +15 -15
- package/src/components/DatametriaSidebar.vue +230 -0
- package/src/components/DatametriaSkeleton.vue +243 -239
- package/src/components/DatametriaSlider.vue +395 -407
- package/src/components/DatametriaSortableTable.vue +585 -0
- package/src/components/DatametriaSpinner.vue +7 -7
- package/src/components/DatametriaSwitch.vue +16 -16
- package/src/components/DatametriaTable.vue +14 -14
- package/src/components/DatametriaTabs.vue +150 -29
- package/src/components/DatametriaTextarea.vue +28 -28
- package/src/components/DatametriaTimePicker.vue +285 -285
- package/src/components/DatametriaToast.vue +176 -176
- package/src/components/DatametriaTooltip.vue +408 -408
- package/src/components/__tests__/DatametriaAlert.test.js +35 -35
- package/src/components/__tests__/DatametriaAlert.test.ts +190 -0
- package/src/components/__tests__/DatametriaAutocomplete.test.ts +180 -0
- package/src/components/__tests__/DatametriaAvatar.test.ts +152 -0
- package/src/components/__tests__/DatametriaBadge.test.js +29 -29
- package/src/components/__tests__/DatametriaBadge.test.ts +167 -0
- package/src/components/__tests__/DatametriaBreadcrumb.test.ts +75 -0
- package/src/components/__tests__/DatametriaButton.test.js +30 -30
- package/src/components/__tests__/DatametriaButton.test.ts +283 -0
- package/src/components/__tests__/DatametriaCard.test.ts +201 -0
- package/src/components/__tests__/DatametriaCheckbox.test.ts +47 -0
- package/src/components/__tests__/DatametriaChip.test.js +38 -38
- package/src/components/__tests__/DatametriaContainer.test.ts +52 -0
- package/src/components/__tests__/DatametriaDatePicker.test.ts +234 -0
- package/src/components/__tests__/DatametriaDivider.test.ts +54 -0
- package/src/components/__tests__/DatametriaFileUpload.test.ts +291 -0
- package/src/components/__tests__/DatametriaFloatingBar.test.ts +137 -0
- package/src/components/__tests__/DatametriaGrid.test.ts +31 -0
- package/src/components/__tests__/DatametriaInput.test.ts +72 -0
- package/src/components/__tests__/DatametriaMenu.test.ts +366 -0
- package/src/components/__tests__/DatametriaModal.test.ts +86 -0
- package/src/components/__tests__/DatametriaNavbar.test.js +48 -48
- package/src/components/__tests__/DatametriaNavbar.test.ts +203 -0
- package/src/components/__tests__/DatametriaPasswordInput.test.js +305 -0
- package/src/components/__tests__/DatametriaProgress.test.ts +90 -0
- package/src/components/__tests__/DatametriaRadio.test.ts +77 -0
- package/src/components/__tests__/DatametriaSelect.test.ts +77 -0
- package/src/components/__tests__/DatametriaSidebar.test.ts +169 -0
- package/src/components/__tests__/DatametriaSlider.test.ts +261 -0
- package/src/components/__tests__/DatametriaSortableTable.test.js +168 -0
- package/src/components/__tests__/DatametriaSpinner.test.ts +156 -0
- package/src/components/__tests__/DatametriaSwitch.test.ts +64 -0
- package/src/components/__tests__/DatametriaTable.test.ts +97 -0
- package/src/components/__tests__/DatametriaTabs.test.ts +232 -0
- package/src/components/__tests__/DatametriaTextarea.test.ts +66 -0
- package/src/components/__tests__/DatametriaToast.test.js +48 -48
- package/src/components/__tests__/DatametriaToast.test.ts +99 -0
- package/src/composables/useAccessibilityScale.ts +94 -94
- package/src/composables/useBreakpoints.ts +82 -82
- package/src/composables/useHapticFeedback.ts +439 -439
- package/src/composables/useRipple.ts +218 -218
- package/src/index.ts +70 -61
- package/src/stories/Variants.stories.js +95 -95
- package/src/styles/design-tokens.css +623 -623
- package/src/theme/ThemeProvider.vue +96 -0
- package/src/theme/__tests__/ThemeProvider.test.ts +208 -0
- package/src/theme/__tests__/constants.test.ts +31 -0
- package/src/theme/__tests__/presets.test.ts +166 -0
- package/src/theme/__tests__/tokens.test.ts +155 -0
- package/src/theme/__tests__/types.test.ts +153 -0
- package/src/theme/__tests__/useTheme.test.ts +146 -0
- package/src/theme/constants.ts +14 -0
- package/src/theme/index.ts +12 -0
- package/src/theme/presets/datametria.ts +94 -0
- package/src/theme/presets/default.ts +94 -0
- package/src/theme/presets/index.ts +8 -0
- package/src/theme/tokens/colors.ts +28 -0
- package/src/theme/tokens/index.ts +47 -0
- package/src/theme/tokens/spacing.ts +21 -0
- package/src/theme/tokens/typography.ts +35 -0
- package/src/theme/types.ts +111 -0
- package/src/theme/useTheme.ts +28 -0
- package/src/types/index.ts +19 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import DatametriaSelect from '../DatametriaSelect.vue'
|
|
4
|
+
|
|
5
|
+
describe('DatametriaSelect', () => {
|
|
6
|
+
const options = [
|
|
7
|
+
{ value: '1', label: 'Option 1' },
|
|
8
|
+
{ value: '2', label: 'Option 2' },
|
|
9
|
+
{ value: '3', label: 'Option 3' }
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
it('renders correctly', () => {
|
|
13
|
+
const wrapper = mount(DatametriaSelect, {
|
|
14
|
+
props: { options }
|
|
15
|
+
})
|
|
16
|
+
expect(wrapper.find('.datametria-select').exists()).toBe(true)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('renders label when provided', () => {
|
|
20
|
+
const wrapper = mount(DatametriaSelect, {
|
|
21
|
+
props: { options, label: 'Select Label' }
|
|
22
|
+
})
|
|
23
|
+
expect(wrapper.find('.datametria-select__label').text()).toContain('Select Label')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('shows required indicator', () => {
|
|
27
|
+
const wrapper = mount(DatametriaSelect, {
|
|
28
|
+
props: { options, label: 'Test', required: true }
|
|
29
|
+
})
|
|
30
|
+
expect(wrapper.find('.datametria-select__required').exists()).toBe(true)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('renders all options', () => {
|
|
34
|
+
const wrapper = mount(DatametriaSelect, {
|
|
35
|
+
props: { options }
|
|
36
|
+
})
|
|
37
|
+
const optionElements = wrapper.findAll('option')
|
|
38
|
+
expect(optionElements.length).toBeGreaterThanOrEqual(3)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('renders placeholder option', () => {
|
|
42
|
+
const wrapper = mount(DatametriaSelect, {
|
|
43
|
+
props: { options, placeholder: 'Choose option' }
|
|
44
|
+
})
|
|
45
|
+
const firstOption = wrapper.find('option')
|
|
46
|
+
expect(firstOption.text()).toBe('Choose option')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('binds modelValue correctly', () => {
|
|
50
|
+
const wrapper = mount(DatametriaSelect, {
|
|
51
|
+
props: { options, modelValue: '2' }
|
|
52
|
+
})
|
|
53
|
+
expect((wrapper.find('select').element as HTMLSelectElement).value).toBe('2')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('emits update:modelValue on change', async () => {
|
|
57
|
+
const wrapper = mount(DatametriaSelect, {
|
|
58
|
+
props: { options }
|
|
59
|
+
})
|
|
60
|
+
await wrapper.find('select').setValue('2')
|
|
61
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['2'])
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it('shows error message', () => {
|
|
65
|
+
const wrapper = mount(DatametriaSelect, {
|
|
66
|
+
props: { options, errorMessage: 'Error text' }
|
|
67
|
+
})
|
|
68
|
+
expect(wrapper.find('.datametria-select__error').text()).toBe('Error text')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('applies disabled state', () => {
|
|
72
|
+
const wrapper = mount(DatametriaSelect, {
|
|
73
|
+
props: { options, disabled: true }
|
|
74
|
+
})
|
|
75
|
+
expect(wrapper.find('select').attributes('disabled')).toBeDefined()
|
|
76
|
+
})
|
|
77
|
+
})
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import DatametriaSidebar from '../DatametriaSidebar.vue'
|
|
4
|
+
|
|
5
|
+
describe('DatametriaSidebar', () => {
|
|
6
|
+
it('renders correctly', () => {
|
|
7
|
+
const wrapper = mount(DatametriaSidebar)
|
|
8
|
+
expect(wrapper.find('.dm-sidebar').exists()).toBe(true)
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('applies position classes', () => {
|
|
12
|
+
const wrapperLeft = mount(DatametriaSidebar, { props: { position: 'left' } })
|
|
13
|
+
expect(wrapperLeft.find('.dm-sidebar--left').exists()).toBe(true)
|
|
14
|
+
|
|
15
|
+
const wrapperRight = mount(DatametriaSidebar, { props: { position: 'right' } })
|
|
16
|
+
expect(wrapperRight.find('.dm-sidebar--right').exists()).toBe(true)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('applies variant classes', () => {
|
|
20
|
+
const variants = ['light', 'dark', 'primary'] as const
|
|
21
|
+
variants.forEach(variant => {
|
|
22
|
+
const wrapper = mount(DatametriaSidebar, { props: { variant } })
|
|
23
|
+
expect(wrapper.find(`.dm-sidebar--${variant}`).exists()).toBe(true)
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('renders header slot', () => {
|
|
28
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
29
|
+
slots: { header: '<div class="test-header">Header</div>' }
|
|
30
|
+
})
|
|
31
|
+
expect(wrapper.find('.test-header').exists()).toBe(true)
|
|
32
|
+
expect(wrapper.find('.dm-sidebar__header').exists()).toBe(true)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('renders default slot content', () => {
|
|
36
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
37
|
+
slots: { default: '<div class="test-content">Content</div>' }
|
|
38
|
+
})
|
|
39
|
+
expect(wrapper.find('.test-content').exists()).toBe(true)
|
|
40
|
+
expect(wrapper.find('.dm-sidebar__content').exists()).toBe(true)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('renders footer slot', () => {
|
|
44
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
45
|
+
slots: { footer: '<div class="test-footer">Footer</div>' }
|
|
46
|
+
})
|
|
47
|
+
expect(wrapper.find('.test-footer').exists()).toBe(true)
|
|
48
|
+
expect(wrapper.find('.dm-sidebar__footer').exists()).toBe(true)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('shows toggle button when collapsible', () => {
|
|
52
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
53
|
+
props: { collapsible: true },
|
|
54
|
+
slots: { header: 'Header' }
|
|
55
|
+
})
|
|
56
|
+
expect(wrapper.find('.dm-sidebar__toggle').exists()).toBe(true)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('hides toggle button when not collapsible', () => {
|
|
60
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
61
|
+
props: { collapsible: false },
|
|
62
|
+
slots: { header: 'Header' }
|
|
63
|
+
})
|
|
64
|
+
expect(wrapper.find('.dm-sidebar__toggle').exists()).toBe(false)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('toggles open state when toggle button clicked', async () => {
|
|
68
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
69
|
+
props: { collapsible: true, defaultOpen: true },
|
|
70
|
+
slots: { header: 'Header' }
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
expect(wrapper.vm.isOpen).toBe(true)
|
|
74
|
+
expect(wrapper.find('.dm-sidebar--collapsed').exists()).toBe(false)
|
|
75
|
+
|
|
76
|
+
await wrapper.find('.dm-sidebar__toggle').trigger('click')
|
|
77
|
+
expect(wrapper.vm.isOpen).toBe(false)
|
|
78
|
+
expect(wrapper.find('.dm-sidebar--collapsed').exists()).toBe(true)
|
|
79
|
+
|
|
80
|
+
await wrapper.find('.dm-sidebar__toggle').trigger('click')
|
|
81
|
+
expect(wrapper.vm.isOpen).toBe(true)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('emits toggle event with correct value', async () => {
|
|
85
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
86
|
+
props: { collapsible: true, defaultOpen: true },
|
|
87
|
+
slots: { header: 'Header' }
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
await wrapper.find('.dm-sidebar__toggle').trigger('click')
|
|
91
|
+
expect(wrapper.emitted('toggle')).toBeTruthy()
|
|
92
|
+
expect(wrapper.emitted('toggle')?.[0]).toEqual([false])
|
|
93
|
+
|
|
94
|
+
await wrapper.find('.dm-sidebar__toggle').trigger('click')
|
|
95
|
+
expect(wrapper.emitted('toggle')?.[1]).toEqual([true])
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('emits open event when opening', async () => {
|
|
99
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
100
|
+
props: { collapsible: true, defaultOpen: false },
|
|
101
|
+
slots: { header: 'Header' }
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
await wrapper.find('.dm-sidebar__toggle').trigger('click')
|
|
105
|
+
expect(wrapper.emitted('open')).toBeTruthy()
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('emits close event when closing', async () => {
|
|
109
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
110
|
+
props: { collapsible: true, defaultOpen: true },
|
|
111
|
+
slots: { header: 'Header' }
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
await wrapper.find('.dm-sidebar__toggle').trigger('click')
|
|
115
|
+
expect(wrapper.emitted('close')).toBeTruthy()
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('respects defaultOpen prop', () => {
|
|
119
|
+
const wrapperOpen = mount(DatametriaSidebar, { props: { defaultOpen: true } })
|
|
120
|
+
expect(wrapperOpen.vm.isOpen).toBe(true)
|
|
121
|
+
|
|
122
|
+
const wrapperClosed = mount(DatametriaSidebar, { props: { defaultOpen: false } })
|
|
123
|
+
expect(wrapperClosed.vm.isOpen).toBe(false)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('updates isOpen when defaultOpen prop changes', async () => {
|
|
127
|
+
const wrapper = mount(DatametriaSidebar, { props: { defaultOpen: true } })
|
|
128
|
+
expect(wrapper.vm.isOpen).toBe(true)
|
|
129
|
+
|
|
130
|
+
await wrapper.setProps({ defaultOpen: false })
|
|
131
|
+
expect(wrapper.vm.isOpen).toBe(false)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('has correct aria attributes', () => {
|
|
135
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
136
|
+
props: { ariaLabel: 'Test sidebar', defaultOpen: true }
|
|
137
|
+
})
|
|
138
|
+
const sidebar = wrapper.find('.dm-sidebar')
|
|
139
|
+
expect(sidebar.attributes('role')).toBe('complementary')
|
|
140
|
+
expect(sidebar.attributes('aria-label')).toBe('Test sidebar')
|
|
141
|
+
expect(sidebar.attributes('aria-expanded')).toBe('true')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('exposes toggle method', () => {
|
|
145
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
146
|
+
props: { collapsible: true, defaultOpen: true }
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
expect(wrapper.vm.isOpen).toBe(true)
|
|
150
|
+
wrapper.vm.toggle()
|
|
151
|
+
expect(wrapper.vm.isOpen).toBe(false)
|
|
152
|
+
wrapper.vm.toggle()
|
|
153
|
+
expect(wrapper.vm.isOpen).toBe(true)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('applies collapsed class when closed and collapsible', () => {
|
|
157
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
158
|
+
props: { collapsible: true, defaultOpen: false }
|
|
159
|
+
})
|
|
160
|
+
expect(wrapper.find('.dm-sidebar--collapsed').exists()).toBe(true)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
it('does not apply collapsed class when open', () => {
|
|
164
|
+
const wrapper = mount(DatametriaSidebar, {
|
|
165
|
+
props: { collapsible: true, defaultOpen: true }
|
|
166
|
+
})
|
|
167
|
+
expect(wrapper.find('.dm-sidebar--collapsed').exists()).toBe(false)
|
|
168
|
+
})
|
|
169
|
+
})
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import DatametriaSlider from '../DatametriaSlider.vue'
|
|
4
|
+
|
|
5
|
+
describe('DatametriaSlider', () => {
|
|
6
|
+
describe('Renderização', () => {
|
|
7
|
+
it('renderiza corretamente', () => {
|
|
8
|
+
const wrapper = mount(DatametriaSlider, {
|
|
9
|
+
props: { modelValue: 50 }
|
|
10
|
+
})
|
|
11
|
+
expect(wrapper.find('.dm-slider').exists()).toBe(true)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('renderiza label', () => {
|
|
15
|
+
const wrapper = mount(DatametriaSlider, {
|
|
16
|
+
props: { modelValue: 50, label: 'Volume' }
|
|
17
|
+
})
|
|
18
|
+
expect(wrapper.text()).toContain('Volume')
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('renderiza valor quando showValue=true', () => {
|
|
22
|
+
const wrapper = mount(DatametriaSlider, {
|
|
23
|
+
props: { modelValue: 75, showValue: true }
|
|
24
|
+
})
|
|
25
|
+
expect(wrapper.find('.dm-slider__value').text()).toBe('75')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('não renderiza valor quando showValue=false', () => {
|
|
29
|
+
const wrapper = mount(DatametriaSlider, {
|
|
30
|
+
props: { modelValue: 75, showValue: false }
|
|
31
|
+
})
|
|
32
|
+
expect(wrapper.find('.dm-slider__value').exists()).toBe(false)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('renderiza min/max quando showMinMax=true', () => {
|
|
36
|
+
const wrapper = mount(DatametriaSlider, {
|
|
37
|
+
props: { modelValue: 50, min: 0, max: 100, showMinMax: true }
|
|
38
|
+
})
|
|
39
|
+
expect(wrapper.find('.dm-slider__min').text()).toBe('0')
|
|
40
|
+
expect(wrapper.find('.dm-slider__max').text()).toBe('100')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('renderiza required indicator', () => {
|
|
44
|
+
const wrapper = mount(DatametriaSlider, {
|
|
45
|
+
props: { modelValue: 50, label: 'Volume', required: true }
|
|
46
|
+
})
|
|
47
|
+
expect(wrapper.find('.dm-slider__required').exists()).toBe(true)
|
|
48
|
+
})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
describe('Props', () => {
|
|
52
|
+
it('aceita modelValue', () => {
|
|
53
|
+
const wrapper = mount(DatametriaSlider, {
|
|
54
|
+
props: { modelValue: 60 }
|
|
55
|
+
})
|
|
56
|
+
expect(wrapper.props('modelValue')).toBe(60)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('aceita min e max', () => {
|
|
60
|
+
const wrapper = mount(DatametriaSlider, {
|
|
61
|
+
props: { modelValue: 50, min: 10, max: 90 }
|
|
62
|
+
})
|
|
63
|
+
const input = wrapper.find('input')
|
|
64
|
+
expect(input.attributes('min')).toBe('10')
|
|
65
|
+
expect(input.attributes('max')).toBe('90')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('aceita step', () => {
|
|
69
|
+
const wrapper = mount(DatametriaSlider, {
|
|
70
|
+
props: { modelValue: 50, step: 5 }
|
|
71
|
+
})
|
|
72
|
+
expect(wrapper.find('input').attributes('step')).toBe('5')
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('aceita disabled', () => {
|
|
76
|
+
const wrapper = mount(DatametriaSlider, {
|
|
77
|
+
props: { modelValue: 50, disabled: true }
|
|
78
|
+
})
|
|
79
|
+
expect(wrapper.find('.dm-slider').classes()).toContain('dm-slider--disabled')
|
|
80
|
+
expect(wrapper.find('input').element.disabled).toBe(true)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('aceita errorMessage', () => {
|
|
84
|
+
const wrapper = mount(DatametriaSlider, {
|
|
85
|
+
props: { modelValue: 50, errorMessage: 'Valor inválido' }
|
|
86
|
+
})
|
|
87
|
+
expect(wrapper.find('.dm-slider__error').text()).toBe('Valor inválido')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('aceita helperText', () => {
|
|
91
|
+
const wrapper = mount(DatametriaSlider, {
|
|
92
|
+
props: { modelValue: 50, helperText: 'Ajuste o volume' }
|
|
93
|
+
})
|
|
94
|
+
expect(wrapper.find('.dm-slider__helper').text()).toBe('Ajuste o volume')
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
it('aceita formatter customizado', () => {
|
|
98
|
+
const wrapper = mount(DatametriaSlider, {
|
|
99
|
+
props: {
|
|
100
|
+
modelValue: 50,
|
|
101
|
+
showValue: true,
|
|
102
|
+
formatter: (v: number) => `${v}%`
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
expect(wrapper.find('.dm-slider__value').text()).toBe('50%')
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
describe('Interação', () => {
|
|
110
|
+
it('emite update:modelValue ao mudar input', async () => {
|
|
111
|
+
const wrapper = mount(DatametriaSlider, {
|
|
112
|
+
props: { modelValue: 50 }
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
const input = wrapper.find('input')
|
|
116
|
+
await input.setValue(75)
|
|
117
|
+
|
|
118
|
+
expect(wrapper.emitted('update:modelValue')).toBeTruthy()
|
|
119
|
+
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([75])
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('emite change ao mudar valor', async () => {
|
|
123
|
+
const wrapper = mount(DatametriaSlider, {
|
|
124
|
+
props: { modelValue: 50 }
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
const input = wrapper.find('input')
|
|
128
|
+
await input.trigger('change')
|
|
129
|
+
|
|
130
|
+
expect(wrapper.emitted('change')).toBeTruthy()
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it('emite focus ao focar', async () => {
|
|
134
|
+
const wrapper = mount(DatametriaSlider, {
|
|
135
|
+
props: { modelValue: 50 }
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
await wrapper.find('input').trigger('focus')
|
|
139
|
+
expect(wrapper.emitted('focus')).toBeTruthy()
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it('emite blur ao desfocar', async () => {
|
|
143
|
+
const wrapper = mount(DatametriaSlider, {
|
|
144
|
+
props: { modelValue: 50 }
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
await wrapper.find('input').trigger('blur')
|
|
148
|
+
expect(wrapper.emitted('blur')).toBeTruthy()
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
describe('Progress', () => {
|
|
153
|
+
it('calcula progressPercentage corretamente', () => {
|
|
154
|
+
const wrapper = mount(DatametriaSlider, {
|
|
155
|
+
props: { modelValue: 50, min: 0, max: 100 }
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
const progress = wrapper.find('.dm-slider__progress')
|
|
159
|
+
expect(progress.attributes('style')).toContain('width: 50%')
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('calcula progressPercentage com min diferente de 0', () => {
|
|
163
|
+
const wrapper = mount(DatametriaSlider, {
|
|
164
|
+
props: { modelValue: 50, min: 25, max: 75 }
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
const progress = wrapper.find('.dm-slider__progress')
|
|
168
|
+
expect(progress.attributes('style')).toContain('width: 50%')
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
describe('Acessibilidade', () => {
|
|
173
|
+
it('input tem type range', () => {
|
|
174
|
+
const wrapper = mount(DatametriaSlider, {
|
|
175
|
+
props: { modelValue: 50 }
|
|
176
|
+
})
|
|
177
|
+
expect(wrapper.find('input').attributes('type')).toBe('range')
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('input tem aria-valuemin', () => {
|
|
181
|
+
const wrapper = mount(DatametriaSlider, {
|
|
182
|
+
props: { modelValue: 50, min: 10 }
|
|
183
|
+
})
|
|
184
|
+
expect(wrapper.find('input').attributes('aria-valuemin')).toBe('10')
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('input tem aria-valuemax', () => {
|
|
188
|
+
const wrapper = mount(DatametriaSlider, {
|
|
189
|
+
props: { modelValue: 50, max: 90 }
|
|
190
|
+
})
|
|
191
|
+
expect(wrapper.find('input').attributes('aria-valuemax')).toBe('90')
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('input tem aria-valuenow', () => {
|
|
195
|
+
const wrapper = mount(DatametriaSlider, {
|
|
196
|
+
props: { modelValue: 60 }
|
|
197
|
+
})
|
|
198
|
+
expect(wrapper.find('input').attributes('aria-valuenow')).toBe('60')
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
it('input tem aria-valuetext com formatter', () => {
|
|
202
|
+
const wrapper = mount(DatametriaSlider, {
|
|
203
|
+
props: {
|
|
204
|
+
modelValue: 50,
|
|
205
|
+
formatter: (v: number) => `${v}%`
|
|
206
|
+
}
|
|
207
|
+
})
|
|
208
|
+
expect(wrapper.find('input').attributes('aria-valuetext')).toBe('50%')
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('error tem role alert', () => {
|
|
212
|
+
const wrapper = mount(DatametriaSlider, {
|
|
213
|
+
props: { modelValue: 50, errorMessage: 'Erro' }
|
|
214
|
+
})
|
|
215
|
+
expect(wrapper.find('.dm-slider__error').attributes('role')).toBe('alert')
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
it('input tem aria-describedby quando há error', () => {
|
|
219
|
+
const wrapper = mount(DatametriaSlider, {
|
|
220
|
+
props: { modelValue: 50, errorMessage: 'Erro' }
|
|
221
|
+
})
|
|
222
|
+
const input = wrapper.find('input')
|
|
223
|
+
expect(input.attributes('aria-describedby')).toBeDefined()
|
|
224
|
+
})
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
describe('Métodos Expostos', () => {
|
|
228
|
+
it('expõe método focus', () => {
|
|
229
|
+
const wrapper = mount(DatametriaSlider, {
|
|
230
|
+
props: { modelValue: 50 }
|
|
231
|
+
})
|
|
232
|
+
const exposed = wrapper.vm as any
|
|
233
|
+
expect(typeof exposed.focus).toBe('function')
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
it('expõe método blur', () => {
|
|
237
|
+
const wrapper = mount(DatametriaSlider, {
|
|
238
|
+
props: { modelValue: 50 }
|
|
239
|
+
})
|
|
240
|
+
const exposed = wrapper.vm as any
|
|
241
|
+
expect(typeof exposed.blur).toBe('function')
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it('expõe inputRef', () => {
|
|
245
|
+
const wrapper = mount(DatametriaSlider, {
|
|
246
|
+
props: { modelValue: 50 }
|
|
247
|
+
})
|
|
248
|
+
const exposed = wrapper.vm as any
|
|
249
|
+
expect(exposed.inputRef).toBeDefined()
|
|
250
|
+
})
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
describe('CSS Variables', () => {
|
|
254
|
+
it('usa CSS Variables padronizadas', () => {
|
|
255
|
+
const wrapper = mount(DatametriaSlider, {
|
|
256
|
+
props: { modelValue: 50 }
|
|
257
|
+
})
|
|
258
|
+
expect(wrapper.find('.dm-slider').exists()).toBe(true)
|
|
259
|
+
})
|
|
260
|
+
})
|
|
261
|
+
})
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { mount } from '@vue/test-utils'
|
|
3
|
+
import DatametriaSortableTable from '../DatametriaSortableTable.vue'
|
|
4
|
+
|
|
5
|
+
describe('DatametriaSortableTable', () => {
|
|
6
|
+
const columns = [
|
|
7
|
+
{ key: 'id', label: 'ID', width: '80px' },
|
|
8
|
+
{ key: 'name', label: 'Nome' },
|
|
9
|
+
{ key: 'email', label: 'Email' },
|
|
10
|
+
{ key: 'status', label: 'Status' }
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
const data = [
|
|
14
|
+
{ id: 1, name: 'João Silva', email: 'joao@example.com', status: 'Ativo' },
|
|
15
|
+
{ id: 2, name: 'Maria Santos', email: 'maria@example.com', status: 'Inativo' },
|
|
16
|
+
{ id: 3, name: 'Pedro Costa', email: 'pedro@example.com', status: 'Ativo' },
|
|
17
|
+
{ id: 4, name: 'Ana Oliveira', email: 'ana@example.com', status: 'Ativo' }
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
it('renders table with data', () => {
|
|
21
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
22
|
+
props: { columns, data }
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
expect(wrapper.find('.datametria-sortable-table').exists()).toBe(true)
|
|
26
|
+
expect(wrapper.findAll('.datametria-sortable-table__tr')).toHaveLength(4)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('renders search input when searchable', () => {
|
|
30
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
31
|
+
props: { columns, data, searchable: true }
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
expect(wrapper.find('.datametria-sortable-table__search-input').exists()).toBe(true)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('filters data by search query', async () => {
|
|
38
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
39
|
+
props: { columns, data, searchable: true }
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const searchInput = wrapper.find('.datametria-sortable-table__search-input')
|
|
43
|
+
await searchInput.setValue('João')
|
|
44
|
+
|
|
45
|
+
expect(wrapper.findAll('.datametria-sortable-table__tr')).toHaveLength(1)
|
|
46
|
+
expect(wrapper.text()).toContain('João Silva')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('sorts data when clicking column header', async () => {
|
|
50
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
51
|
+
props: { columns, data, paginated: false }
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const nameHeader = wrapper.findAll('.datametria-sortable-table__th')[1]
|
|
55
|
+
await nameHeader.trigger('click')
|
|
56
|
+
|
|
57
|
+
const rows = wrapper.findAll('.datametria-sortable-table__tr')
|
|
58
|
+
expect(rows[0].text()).toContain('Ana Oliveira')
|
|
59
|
+
expect(rows[3].text()).toContain('Pedro Costa')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('toggles sort order on second click', async () => {
|
|
63
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
64
|
+
props: { columns, data, paginated: false }
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
const nameHeader = wrapper.findAll('.datametria-sortable-table__th')[1]
|
|
68
|
+
await nameHeader.trigger('click') // Ascending
|
|
69
|
+
await nameHeader.trigger('click') // Descending
|
|
70
|
+
|
|
71
|
+
const rows = wrapper.findAll('.datametria-sortable-table__tr')
|
|
72
|
+
expect(rows[0].text()).toContain('Pedro Costa')
|
|
73
|
+
expect(rows[3].text()).toContain('Ana Oliveira')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('renders checkboxes when selectable', () => {
|
|
77
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
78
|
+
props: { columns, data, selectable: true }
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
expect(wrapper.findAll('input[type="checkbox"]').length).toBeGreaterThan(0)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('selects row when checkbox clicked', async () => {
|
|
85
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
86
|
+
props: { columns, data, selectable: true }
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const firstCheckbox = wrapper.findAll('input[type="checkbox"]')[1]
|
|
90
|
+
await firstCheckbox.setValue(true)
|
|
91
|
+
|
|
92
|
+
expect(wrapper.emitted('selection-change')).toBeTruthy()
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('renders pagination controls when paginated', () => {
|
|
96
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
97
|
+
props: { columns, data, paginated: true, pageSize: 2 }
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
expect(wrapper.find('.datametria-sortable-table__pagination').exists()).toBe(true)
|
|
101
|
+
expect(wrapper.text()).toContain('Página 1 de 2')
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('changes page when pagination button clicked', async () => {
|
|
105
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
106
|
+
props: { columns, data, paginated: true, pageSize: 2 }
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const nextButton = wrapper.findAll('.datametria-sortable-table__pagination-btn')[2]
|
|
110
|
+
await nextButton.trigger('click')
|
|
111
|
+
|
|
112
|
+
expect(wrapper.text()).toContain('Página 2 de 2')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('renders column filters when filterable', () => {
|
|
116
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
117
|
+
props: { columns, data, filterable: true }
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
expect(wrapper.findAll('.datametria-sortable-table__filter-input').length).toBeGreaterThan(0)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('filters by column filter', async () => {
|
|
124
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
125
|
+
props: { columns, data, filterable: true }
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const statusFilter = wrapper.findAll('.datametria-sortable-table__filter-input')[3]
|
|
129
|
+
await statusFilter.setValue('Inativo')
|
|
130
|
+
|
|
131
|
+
expect(wrapper.findAll('.datametria-sortable-table__tr')).toHaveLength(1)
|
|
132
|
+
expect(wrapper.text()).toContain('Maria Santos')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('shows empty state when no data', () => {
|
|
136
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
137
|
+
props: { columns, data: [] }
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
expect(wrapper.find('.datametria-sortable-table__empty').exists()).toBe(true)
|
|
141
|
+
expect(wrapper.text()).toContain('Nenhum dado encontrado')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('disables sorting for specific columns', async () => {
|
|
145
|
+
const columnsWithNonSortable = [
|
|
146
|
+
{ key: 'id', label: 'ID', sortable: false },
|
|
147
|
+
{ key: 'name', label: 'Nome' }
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
151
|
+
props: { columns: columnsWithNonSortable, data }
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const idHeader = wrapper.findAll('.datametria-sortable-table__th')[0]
|
|
155
|
+
expect(idHeader.classes()).not.toContain('datametria-sortable-table__th--sortable')
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it('changes page size', async () => {
|
|
159
|
+
const wrapper = mount(DatametriaSortableTable, {
|
|
160
|
+
props: { columns, data, paginated: true, pageSize: 2, pageSizeOptions: [2, 5, 10] }
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
const pageSizeSelect = wrapper.find('.datametria-sortable-table__page-size')
|
|
164
|
+
await pageSizeSelect.setValue(5)
|
|
165
|
+
|
|
166
|
+
expect(wrapper.findAll('.datametria-sortable-table__tr')).toHaveLength(4)
|
|
167
|
+
})
|
|
168
|
+
})
|