@datametria/vue-components
Version:
DATAMETRIA Vue.js 3 Component Library with Multi-Brand Theming - 51 components + 10 composables with theming support, WCAG 2.2 AA, dark mode, responsive system
367 lines (299 loc) • 11.2 kB
text/typescript
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount } from '@vue/test-utils'
import DatametriaMenu from '../DatametriaMenu.vue'
describe('DatametriaMenu', () => {
const mockItems = [
{ key: '1', label: 'Item 1', action: vi.fn() },
{ key: '2', label: 'Item 2', description: 'Description 2' },
{ key: '3', label: 'Item 3', disabled: true },
{ key: 'divider', divider: true },
{ key: '4', label: 'Item 4', shortcut: '⌘K' }
]
beforeEach(() => {
vi.clearAllMocks()
})
describe('Renderização', () => {
it('renderiza corretamente', () => {
const wrapper = mount(DatametriaMenu)
expect(wrapper.find('.dm-menu').exists()).toBe(true)
})
it('renderiza trigger padrão', () => {
const wrapper = mount(DatametriaMenu, {
props: { triggerText: 'Abrir Menu' }
})
expect(wrapper.find('.dm-menu__button').text()).toContain('Abrir Menu')
})
it('renderiza items quando aberto', async () => {
const wrapper = mount(DatametriaMenu, {
props: { items: mockItems },
attachTo: document.body
})
await wrapper.find('.dm-menu__button').trigger('click')
await wrapper.vm.$nextTick()
expect(wrapper.emitted('open')).toBeTruthy()
})
it('renderiza chevron icon', () => {
const wrapper = mount(DatametriaMenu)
expect(wrapper.find('.dm-menu__chevron').exists()).toBe(true)
})
})
describe('Props', () => {
it('aceita triggerText customizado', () => {
const wrapper = mount(DatametriaMenu, {
props: { triggerText: 'Custom Text' }
})
expect(wrapper.find('.dm-menu__button').text()).toContain('Custom Text')
})
it('aceita items array', () => {
const wrapper = mount(DatametriaMenu, {
props: { items: mockItems }
})
expect(wrapper.props('items')).toEqual(mockItems)
})
it('aceita placement', () => {
const wrapper = mount(DatametriaMenu, {
props: { placement: 'bottom-end' }
})
expect(wrapper.props('placement')).toBe('bottom-end')
})
it('aceita disabled', () => {
const wrapper = mount(DatametriaMenu, {
props: { disabled: true }
})
expect(wrapper.find('.dm-menu').classes()).toContain('dm-menu--disabled')
expect(wrapper.find('.dm-menu__button').element.disabled).toBe(true)
})
it('aceita fullWidth', () => {
const wrapper = mount(DatametriaMenu, {
props: { fullWidth: true }
})
expect(wrapper.props('fullWidth')).toBe(true)
})
it('aceita showBackdrop', () => {
const wrapper = mount(DatametriaMenu, {
props: { showBackdrop: true }
})
expect(wrapper.props('showBackdrop')).toBe(true)
})
it('aceita closeOnItemClick', () => {
const wrapper = mount(DatametriaMenu, {
props: { closeOnItemClick: false }
})
expect(wrapper.props('closeOnItemClick')).toBe(false)
})
it('aceita offset customizado', () => {
const wrapper = mount(DatametriaMenu, {
props: { offset: 8 }
})
expect(wrapper.props('offset')).toBe(8)
})
})
describe('Interação', () => {
it('abre menu ao clicar no trigger', async () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
await wrapper.find('.dm-menu__button').trigger('click')
expect(wrapper.emitted('open')).toBeTruthy()
})
it('fecha menu ao clicar novamente no trigger', async () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
const button = wrapper.find('.dm-menu__button')
await button.trigger('click')
await button.trigger('click')
expect(wrapper.emitted('close')).toBeTruthy()
})
it('emite item-click ao clicar em item', async () => {
const wrapper = mount(DatametriaMenu, {
props: { items: mockItems },
attachTo: document.body
})
await wrapper.find('.dm-menu__button').trigger('click')
await wrapper.vm.$nextTick()
const exposed = wrapper.vm as any
exposed.handleItemClick(mockItems[0], 0)
expect(wrapper.emitted('item-click')).toBeTruthy()
expect(wrapper.emitted('item-click')?.[0]).toEqual([mockItems[0], 0])
})
it('executa action do item ao clicar', async () => {
const wrapper = mount(DatametriaMenu, {
props: { items: mockItems },
attachTo: document.body
})
const exposed = wrapper.vm as any
exposed.handleItemClick(mockItems[0], 0)
expect(mockItems[0].action).toHaveBeenCalled()
})
it('não executa action de item disabled', async () => {
const disabledItem = { ...mockItems[2], action: vi.fn() }
const wrapper = mount(DatametriaMenu, {
props: { items: [disabledItem] },
attachTo: document.body
})
const exposed = wrapper.vm as any
exposed.handleItemClick(disabledItem, 0)
expect(wrapper.emitted('item-click')).toBeFalsy()
})
it('fecha menu após clicar em item quando closeOnItemClick=true', async () => {
const wrapper = mount(DatametriaMenu, {
props: { items: mockItems, closeOnItemClick: true },
attachTo: document.body
})
await wrapper.find('.dm-menu__button').trigger('click')
const exposed = wrapper.vm as any
exposed.handleItemClick(mockItems[0], 0)
expect(wrapper.emitted('close')).toBeTruthy()
})
it('não fecha menu após clicar em item quando closeOnItemClick=false', async () => {
const wrapper = mount(DatametriaMenu, {
props: { items: mockItems, closeOnItemClick: false },
attachTo: document.body
})
await wrapper.find('.dm-menu__button').trigger('click')
const exposed = wrapper.vm as any
exposed.handleItemClick(mockItems[0], 0)
expect(wrapper.emitted('close')).toBeFalsy()
})
})
describe('Teclado', () => {
it('abre menu com Enter', async () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
await wrapper.find('.dm-menu__trigger').trigger('keydown', { key: 'Enter' })
expect(wrapper.emitted('open')).toBeTruthy()
})
it('abre menu com Space', async () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
await wrapper.find('.dm-menu__trigger').trigger('keydown', { key: ' ' })
expect(wrapper.emitted('open')).toBeTruthy()
})
it('abre menu com ArrowDown', async () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
await wrapper.find('.dm-menu__trigger').trigger('keydown', { key: 'ArrowDown' })
expect(wrapper.emitted('open')).toBeTruthy()
})
it('fecha menu com Escape', async () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
await wrapper.find('.dm-menu__button').trigger('click')
await wrapper.find('.dm-menu__trigger').trigger('keydown', { key: 'Escape' })
expect(wrapper.emitted('close')).toBeTruthy()
})
})
describe('Acessibilidade', () => {
it('tem atributos ARIA corretos no trigger', () => {
const wrapper = mount(DatametriaMenu)
const trigger = wrapper.find('.dm-menu__trigger')
expect(trigger.attributes('aria-expanded')).toBe('false')
expect(trigger.attributes('aria-haspopup')).toBe('true')
expect(trigger.attributes('aria-controls')).toBeDefined()
})
it('atualiza aria-expanded quando abre', async () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
await wrapper.find('.dm-menu__button').trigger('click')
expect(wrapper.find('.dm-menu__trigger').attributes('aria-expanded')).toBe('true')
})
it('button tem type="button"', () => {
const wrapper = mount(DatametriaMenu)
expect(wrapper.find('.dm-menu__button').attributes('type')).toBe('button')
})
})
describe('Estados', () => {
it('aplica classe disabled quando disabled=true', () => {
const wrapper = mount(DatametriaMenu, {
props: { disabled: true }
})
expect(wrapper.find('.dm-menu').classes()).toContain('dm-menu--disabled')
})
it('não abre quando disabled', async () => {
const wrapper = mount(DatametriaMenu, {
props: { disabled: true },
attachTo: document.body
})
await wrapper.find('.dm-menu__button').trigger('click')
expect(wrapper.emitted('open')).toBeFalsy()
})
it('rotaciona chevron quando aberto', async () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
await wrapper.find('.dm-menu__button').trigger('click')
expect(wrapper.find('.dm-menu__chevron').classes()).toContain('dm-menu__chevron--open')
})
})
describe('CSS Variables', () => {
it('usa CSS Variables padronizadas', () => {
const wrapper = mount(DatametriaMenu)
const button = wrapper.find('.dm-menu__button')
const styles = button.element.style
// Verifica que o componente está pronto para usar CSS Variables
expect(button.exists()).toBe(true)
})
it('aplica estilos com fallbacks', () => {
const wrapper = mount(DatametriaMenu)
expect(wrapper.find('.dm-menu__button').exists()).toBe(true)
})
})
describe('Métodos Expostos', () => {
it('expõe método open', () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
const exposed = wrapper.vm as any
expect(typeof exposed.open).toBe('function')
})
it('expõe método close', () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
const exposed = wrapper.vm as any
expect(typeof exposed.close).toBe('function')
})
it('expõe método toggle', () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
const exposed = wrapper.vm as any
expect(typeof exposed.toggle).toBe('function')
})
it('expõe computed isOpen', () => {
const wrapper = mount(DatametriaMenu, {
attachTo: document.body
})
const exposed = wrapper.vm as any
expect(exposed.isOpen).toBeDefined()
})
})
describe('Slots', () => {
it('aceita slot trigger customizado', () => {
const wrapper = mount(DatametriaMenu, {
slots: {
trigger: '<button class="custom-trigger">Custom</button>'
}
})
expect(wrapper.find('.custom-trigger').exists()).toBe(true)
})
it('aceita slot default para items customizados', async () => {
const wrapper = mount(DatametriaMenu, {
slots: {
default: '<div class="custom-items">Custom Items</div>'
},
attachTo: document.body
})
await wrapper.find('.dm-menu__button').trigger('click')
await wrapper.vm.$nextTick()
// Slot default só aparece quando menu está aberto (dentro do Teleport)
expect(wrapper.emitted('open')).toBeTruthy()
})
})
})