@mozaic-ds/vue
Version:
Mozaic-Vue is the Vue.js implementation of ADEO Design system
156 lines (130 loc) • 4.06 kB
text/typescript
import { mount } from '@vue/test-utils';
import { describe, it, expect, vi } from 'vitest';
import { nextTick } from 'vue';
import MPageHeaderContext from './MPageHeaderContext.vue';
const options = [
{ label: 'Option 1', value: 1 },
{ label: 'Option 2', value: 2 },
];
const stubs = {
MOptionListbox: {
name: 'MOptionListbox',
props: ['modelValue', 'options', 'multiple', 'id'],
emits: ['update:modelValue'],
template: '<div class="option-listbox-stub" />',
},
};
describe('MPageHeaderContext', () => {
it('renders selected option label in single mode', () => {
const wrapper = mount(MPageHeaderContext, {
props: {
modelValue: 2,
options,
},
global: { stubs },
});
expect(wrapper.find('.mc-page-header__context-switcher').text()).toContain(
'Option 2',
);
});
it('falls back to provided label when no option matches modelValue', () => {
const wrapper = mount(MPageHeaderContext, {
props: {
modelValue: 999,
options,
label: 'Fallback context',
},
global: { stubs },
});
expect(wrapper.find('.mc-page-header__context-switcher').text()).toContain(
'Fallback context',
);
});
it('always uses label in multiple mode', () => {
const wrapper = mount(MPageHeaderContext, {
props: {
modelValue: [1],
options,
multiple: true,
label: 'Multi context',
},
global: { stubs },
});
expect(wrapper.find('.mc-page-header__context-switcher').text()).toContain(
'Multi context',
);
});
it('toggles listbox visibility when switcher button is clicked', async () => {
const wrapper = mount(MPageHeaderContext, {
props: {
modelValue: null,
options,
},
global: { stubs },
});
const listbox = wrapper.find('.mc-page-header__context-switcher-listbox');
expect(listbox.classes()).toContain(
'mc-page-header__context-switcher-listbox--hidden',
);
await wrapper.find('.mc-page-header__context-switcher').trigger('click');
expect(listbox.classes()).not.toContain(
'mc-page-header__context-switcher-listbox--hidden',
);
});
it('emits update:modelValue when the listbox emits an update', async () => {
const wrapper = mount(MPageHeaderContext, {
props: {
modelValue: null,
options,
},
global: { stubs },
});
wrapper
.findComponent({ name: 'MOptionListbox' })
.vm.$emit('update:modelValue', 1);
await nextTick();
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([1]);
});
it('closes the listbox on outside click', async () => {
const wrapper = mount(MPageHeaderContext, {
props: {
modelValue: null,
options,
},
global: { stubs },
attachTo: document.body,
});
await wrapper.find('.mc-page-header__context-switcher').trigger('click');
expect(
wrapper
.find('.mc-page-header__context-switcher-listbox')
.classes()
.includes('mc-page-header__context-switcher-listbox--hidden'),
).toBe(false);
document.body.dispatchEvent(new MouseEvent('click', { bubbles: true }));
await nextTick();
expect(
wrapper
.find('.mc-page-header__context-switcher-listbox')
.classes()
.includes('mc-page-header__context-switcher-listbox--hidden'),
).toBe(true);
wrapper.unmount();
});
it('registers and removes click listener on mount lifecycle', () => {
const addSpy = vi.spyOn(document, 'addEventListener');
const removeSpy = vi.spyOn(document, 'removeEventListener');
const wrapper = mount(MPageHeaderContext, {
props: {
modelValue: null,
options,
},
global: { stubs },
});
expect(addSpy).toHaveBeenCalledWith('click', expect.any(Function));
wrapper.unmount();
expect(removeSpy).toHaveBeenCalledWith('click', expect.any(Function));
addSpy.mockRestore();
removeSpy.mockRestore();
});
});