@mozaic-ds/vue
Version:
Mozaic-Vue is the Vue.js implementation of ADEO Design system
143 lines (117 loc) • 4.49 kB
text/typescript
import { describe, it, expect, vi } from 'vitest';
import { mount } from '@vue/test-utils';
import { defineComponent, ref, type Component } from 'vue';
import MAccordionListItem from './MAccordionListItem.vue';
import {
AccordionStateKey,
AccordionToggleFnKey,
} from '../accordionlist/m-accordion-list.const';
type Props = {
id: string;
title: string;
subtitle?: string;
content?: string;
icon?: Component;
};
describe('MAccordionListItem', () => {
function mountItem(props: Props, openIds: string[] = []) {
const state = ref(openIds);
const toggle = vi.fn();
const wrapper = mount(MAccordionListItem, {
props,
global: {
provide: {
[AccordionStateKey as symbol]: state,
[AccordionToggleFnKey as symbol]: toggle,
},
},
});
return { wrapper, state, toggle };
}
it('renders title and content', () => {
const { wrapper } = mountItem({
id: '1',
title: 'My Title',
content: 'My Content',
});
expect(wrapper.find('.mc-accordion__title span').text()).toBe('My Title');
expect(wrapper.find('.mc-accordion__content p').text()).toBe('My Content');
});
it('renders subtitle if provided', () => {
const { wrapper } = mountItem({
id: '1',
title: 'Title',
subtitle: 'Subtitle',
});
expect(wrapper.find('.mc-accordion__subtitle').text()).toBe('Subtitle');
});
it('renders slot content instead of default content', () => {
const wrapper = mount(MAccordionListItem, {
props: { id: '1', title: 'Title', content: 'Default' },
slots: { default: '<div class="slot-content">Custom Slot</div>' },
global: {
provide: {
[AccordionStateKey as symbol]: ref([]),
[AccordionToggleFnKey as symbol]: vi.fn(),
},
},
});
expect(wrapper.find('.slot-content').exists()).toBe(true);
expect(wrapper.find('p').exists()).toBe(false);
});
it('sets aria-expanded correctly based on openIds', async () => {
const { wrapper, state } = mountItem({ id: 'item-1', title: 'Title' }, []);
const button = wrapper.find('button');
expect(button.attributes('aria-expanded')).toBe('false');
state.value.push('item-1');
await wrapper.vm.$nextTick();
expect(button.attributes('aria-expanded')).toBe('true');
});
it('sets inert correctly for content', async () => {
const { wrapper, state } = mountItem({ id: 'item-1', title: 'Title' }, []);
const content = wrapper.find('.mc-accordion__content');
expect(content.attributes('inert')).not.toBeUndefined();
state.value.push('item-1');
await wrapper.vm.$nextTick();
expect(content.attributes('inert')).toBeUndefined();
});
it('renders heading with default level h2', () => {
const { wrapper } = mountItem({ id: '1', title: 'Title' });
expect(wrapper.find('h2.mc-accordion__title').exists()).toBe(true);
});
it('renders heading with custom headingLevel prop', () => {
const wrapper = mount(MAccordionListItem, {
props: { id: '1', title: 'Title', tag: 'h3' },
global: {
provide: {
[AccordionStateKey as symbol]: ref([]),
[AccordionToggleFnKey as symbol]: vi.fn(),
},
},
});
expect(wrapper.find('h3.mc-accordion__title').exists()).toBe(true);
expect(wrapper.find('h2').exists()).toBe(false);
});
it('calls toggleItem when button is clicked', async () => {
const { wrapper, toggle } = mountItem({ id: 'item-1', title: 'Title' });
await wrapper.find('button').trigger('click');
expect(toggle).toHaveBeenCalledOnce();
expect(toggle).toHaveBeenCalledWith('item-1');
});
it('renders icon if provided', () => {
const DummyIcon = defineComponent({
template: '<svg class="dummy-icon" />',
});
const { wrapper } = mountItem({ id: '1', title: 'Title', icon: DummyIcon });
expect(wrapper.find('.mc-accordion__icon').exists()).toBe(true);
expect(wrapper.find('svg.dummy-icon').exists()).toBe(true);
});
it('sets correct aria-controls and aria-labelledby attributes', () => {
const { wrapper } = mountItem({ id: '42', title: 'Title' });
const button = wrapper.find('button');
const content = wrapper.find('.mc-accordion__content');
expect(button.attributes('aria-controls')).toBe('content-42');
expect(content.attributes('aria-labelledby')).toBe('accordion-42');
expect(content.attributes('role')).toBe('region');
});
});