UNPKG

@mozaic-ds/vue

Version:

Mozaic-Vue is the Vue.js implementation of ADEO Design system

367 lines (307 loc) 10.2 kB
import { describe, it, expect, vi } from 'vitest'; import { mount } from '@vue/test-utils'; import MDrawer from '@/components/drawer/MDrawer.vue'; // Stubs for child components const stubs = { ArrowBack24: { template: '<svg />' }, Cross24: { template: '<svg />' }, MIconButton: { template: `<button @click="$emit('click')"><slot name="icon"/></button>`, }, MOverlay: { name: 'MOverlay', template: `<div class="overlay" @click="$emit('click', $event)"><slot/></div>`, }, }; describe('MDrawer component', () => { it('renders title and contentTitle when provided', () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Main Drawer Title', contentTitle: 'Drawer Content Title', }, slots: { default: '<p>Drawer content</p>', }, global: { stubs }, }); expect(wrapper.find('.mc-drawer__title').text()).toBe('Main Drawer Title'); expect(wrapper.find('.mc-drawer__content__title').text()).toBe( 'Drawer Content Title', ); expect(wrapper.find('.mc-drawer__content').text()).toContain( 'Drawer content', ); }); it('emits update:open false when close button is clicked', async () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test Title', }, global: { stubs }, }); const closeButton = wrapper.find('.mc-drawer__close'); await closeButton.trigger('click'); const emitted = wrapper.emitted('update:open'); expect(emitted).toBeTruthy(); expect(emitted![emitted!.length - 1]).toEqual([false]); }); it('emits back event when back button is clicked', async () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test Title', back: true, }, global: { stubs }, }); const backButton = wrapper.find('.mc-drawer__back'); await backButton.trigger('click'); expect(wrapper.emitted('back')).toBeTruthy(); }); it('renders footer slot when provided', () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test Title', }, slots: { footer: '<button>Footer Button</button>', }, global: { stubs }, }); expect(wrapper.find('.mc-drawer__footer').exists()).toBe(true); expect(wrapper.find('.mc-drawer__footer button').text()).toBe( 'Footer Button', ); }); it('applies correct class when extended and position is left', () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test Title', extended: true, position: 'left', }, global: { stubs }, }); const section = wrapper.find('section.mc-drawer'); expect(section.classes()).toContain('mc-drawer--extend'); expect(section.classes()).toContain('mc-drawer--left'); expect(section.classes()).toContain('is-open'); }); it('does not render back button if prop `back` is false', () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test Title', }, global: { stubs }, }); expect(wrapper.find('.mc-drawer__back').exists()).toBe(false); }); it('sets the focus on the title when the drawer opens', async () => { const wrapper = mount(MDrawer, { props: { title: 'Test Title', }, attachTo: document.body, global: { stubs }, }); const titleElement = wrapper.find('.mc-drawer__title').element; expect(document.activeElement).not.toBe(titleElement); await wrapper.setProps({ open: true }); expect(document.activeElement).toBe(titleElement); }); it('does not refocus the title when the drawer closes', async () => { const wrapper = mount(MDrawer, { props: { title: 'Test Title', open: true, }, attachTo: document.body, global: { stubs }, }); const titleElement = wrapper.find('.mc-drawer__title').element; expect(document.activeElement).toBe(titleElement); await wrapper.setProps({ open: false }); await wrapper.vm.$nextTick(); expect(document.activeElement).toBe(titleElement); }); it('emits update:open false when overlay is clicked and closeOnOverlay is true', async () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test Title', closeOnOverlay: true, }, global: { stubs }, }); await wrapper.find('.overlay').trigger('click'); const emitted = wrapper.emitted('update:open'); expect(emitted).toBeTruthy(); expect(emitted![emitted!.length - 1]).toEqual([false]); }); it('does not emit update:open when overlay is clicked and closeOnOverlay is false', async () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test Title', closeOnOverlay: false, }, global: { stubs }, }); await wrapper.find('.overlay').trigger('click'); const emitted = wrapper.emitted('update:open'); expect(emitted).toBeTruthy(); expect(emitted?.length).toBe(1); }); it('does not emit update:open when overlay is clicked and closeOnOverlay is not set', async () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test Title', }, global: { stubs }, }); await wrapper.find('.overlay').trigger('click'); const emitted = wrapper.emitted('update:open'); expect(emitted).toBeTruthy(); }); it('emits update:open false when pressing ESC key', async () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test Title', }, global: { stubs }, }); await wrapper .find('section.mc-drawer') .trigger('keydown', { key: 'Escape' }); expect(wrapper.emitted('update:open')).toBeTruthy(); expect(wrapper.emitted('update:open')!.at(-1)).toEqual([false]); }); it('stops Escape propagation after closing', async () => { const onDocumentKeydown = vi.fn(); document.addEventListener('keydown', onDocumentKeydown); const wrapper = mount(MDrawer, { props: { open: true, title: 'Test Title', }, attachTo: document.body, global: { stubs }, }); wrapper .find('section.mc-drawer') .element.dispatchEvent( new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }), ); expect(wrapper.emitted('update:open')!.at(-1)).toEqual([false]); expect(onDocumentKeydown).not.toHaveBeenCalled(); document.removeEventListener('keydown', onDocumentKeydown); wrapper.unmount(); }); it('locks and unlocks scroll when scroll=false and open changes', async () => { const wrapper = mount(MDrawer, { props: { title: 'Scroll Test', open: false, scroll: false, }, global: { stubs }, }); expect(document.body.style.overflow).toBe(''); await wrapper.setProps({ open: true }); expect(document.body.style.overflow).toBe('hidden'); await wrapper.setProps({ open: false }); expect(document.body.style.overflow).toBe(''); }); it('restores scroll when unmounted', async () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Unmount Test', scroll: false, }, global: { stubs }, }); await wrapper.setProps({ open: true }); expect(document.body.style.overflow).toBe('hidden'); wrapper.unmount(); expect(document.body.style.overflow).toBe(''); }); it('sets inert on section when closed', async () => { const wrapper = mount(MDrawer, { props: { open: false, title: 'Test' }, global: { stubs }, }); // JSDOM renders :inert="true" as "true" — not.toBeUndefined() is the correct check expect( wrapper.find('section.mc-drawer').attributes('inert'), ).not.toBeUndefined(); await wrapper.setProps({ open: true }); expect( wrapper.find('section.mc-drawer').attributes('inert'), ).toBeUndefined(); }); it('does not render aria-modal when closed', async () => { const wrapper = mount(MDrawer, { props: { open: false, title: 'Test' }, global: { stubs }, }); expect( wrapper.find('section.mc-drawer').attributes('aria-modal'), ).toBeUndefined(); await wrapper.setProps({ open: true }); expect(wrapper.find('section.mc-drawer').attributes('aria-modal')).toBe( 'true', ); }); it('traps focus forward: Tab from last focusable wraps to first', async () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test', back: true }, attachTo: document.body, global: { stubs }, }); const buttons = wrapper.findAll('button'); const lastEl = buttons[buttons.length - 1].element as HTMLElement; lastEl.focus(); await wrapper .find('section.mc-drawer') .trigger('keydown', { key: 'Tab', shiftKey: false }); // focus should wrap to the first focusable button (back button) expect(document.activeElement).toBe(buttons[0].element); wrapper.unmount(); }); it('traps focus backward: Shift+Tab from first focusable wraps to last', async () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Test', back: true }, attachTo: document.body, global: { stubs }, }); const buttons = wrapper.findAll('button'); const firstEl = buttons[0].element as HTMLElement; firstEl.focus(); await wrapper .find('section.mc-drawer') .trigger('keydown', { key: 'Tab', shiftKey: true }); // focus should wrap to the last focusable button (close button) expect(document.activeElement).toBe(buttons[buttons.length - 1].element); wrapper.unmount(); }); it('emits update:open on mount reflecting initial state', () => { const wrapper = mount(MDrawer, { props: { open: true, title: 'Initial Test', }, global: { stubs }, }); expect(wrapper.emitted('update:open')).toBeTruthy(); expect(wrapper.emitted('update:open')![0]).toEqual([true]); }); });