UNPKG

@mozaic-ds/vue

Version:

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

241 lines (201 loc) 8.19 kB
import { mount } from '@vue/test-utils'; import { describe, it, expect } from 'vitest'; import { nextTick } from 'vue'; import MSegmentedControl from './MSegmentedControl.vue'; describe('MSegmentedControl.vue', () => { const segments = [ { id: '1', label: 'First' }, { id: '2', label: 'Second' }, { id: '3', label: 'Third' }, ]; it('renders segments with correct labels', () => { const wrapper = mount(MSegmentedControl, { props: { segments }, }); const buttons = wrapper.findAll('button'); expect(buttons).toHaveLength(segments.length); buttons.forEach((btn, i) => { expect(btn.text()).toBe(segments[i].label); }); }); it('sets default active segment based on modelValue prop', () => { const wrapper = mount(MSegmentedControl, { props: { segments, modelValue: '1' }, }); const buttons = wrapper.findAll('button'); expect(buttons[0].classes()).toContain( 'mc-segmented-control__segment--selected', ); expect(buttons[0].attributes('aria-checked')).toBe('true'); }); describe('Segment selection - string type model', () => { it('emits update:modelValue and changes active segment on click', async () => { const wrapper = mount(MSegmentedControl, { props: { segments, modelValue: '1' }, }); const buttons = wrapper.findAll('button'); await buttons[2].trigger('click'); expect(wrapper.emitted('update:modelValue')).toBeTruthy(); expect(wrapper.emitted('update:modelValue')![0]).toEqual(['3']); expect(buttons[2].classes()).toContain( 'mc-segmented-control__segment--selected', ); expect(buttons[2].attributes('aria-checked')).toBe('true'); }); it('does not emit update event if clicking already active segment', async () => { const wrapper = mount(MSegmentedControl, { props: { segments, modelValue: '2' }, }); const buttons = wrapper.findAll('button'); await buttons[1].trigger('click'); expect(wrapper.emitted('update:modelValue')).toBeFalsy(); }); }); describe('Segment selection - number type model', () => { it('emits update:modelValue and changes active segment on click', async () => { const wrapper = mount(MSegmentedControl, { props: { segments, modelValue: 0 }, }); const buttons = wrapper.findAll('button'); await buttons[2].trigger('click'); expect(wrapper.emitted('update:modelValue')).toBeTruthy(); expect(wrapper.emitted('update:modelValue')![0]).toEqual([2]); expect(buttons[2].classes()).toContain( 'mc-segmented-control__segment--selected', ); expect(buttons[2].attributes('aria-checked')).toBe('true'); }); it('does not emit update event if clicking already active segment', async () => { const wrapper = mount(MSegmentedControl, { props: { segments, modelValue: 1 }, }); const buttons = wrapper.findAll('button'); await buttons[1].trigger('click'); expect(wrapper.emitted('update:modelValue')).toBeFalsy(); }); }); it('applies full width class when full prop is true', () => { const wrapper = mount(MSegmentedControl, { props: { segments, full: true }, }); expect(wrapper.classes()).toContain('mc-segmented-control--full'); }); it('applies size class when size prop is "m"', () => { const wrapper = mount(MSegmentedControl, { props: { segments, size: 'm' }, }); expect(wrapper.classes()).toContain('mc-segmented-control--m'); }); it('does not apply size class when size is "s" (default)', () => { const wrapper = mount(MSegmentedControl, { props: { segments }, }); expect(wrapper.classes()).not.toContain('mc-segmented-control--s'); }); it('updates active segment when modelValue prop changes', async () => { const wrapper = mount(MSegmentedControl, { props: { segments, modelValue: '1' }, }); const buttons = wrapper.findAll('button'); expect(buttons[0].classes()).toContain( 'mc-segmented-control__segment--selected', ); await wrapper.setProps({ modelValue: '3' }); expect(buttons[2].classes()).toContain( 'mc-segmented-control__segment--selected', ); expect(buttons[2].attributes('aria-checked')).toBe('true'); }); it('adds role="radio" attribute to buttons', () => { const wrapper = mount(MSegmentedControl, { props: { segments }, }); const buttons = wrapper.findAll('button'); buttons.forEach((button) => { expect(button.attributes('role')).toBe('radio'); }); }); it('forwards attrs to the radiogroup so callers can name the group', () => { const wrapper = mount(MSegmentedControl, { props: { segments }, attrs: { 'aria-label': 'View options' }, }); expect(wrapper.find('[role="radiogroup"]').attributes('aria-label')).toBe( 'View options', ); }); describe('Keyboard navigation (radiogroup pattern)', () => { it('selected button has tabindex="0", others have tabindex="-1"', () => { const wrapper = mount(MSegmentedControl, { props: { segments, modelValue: '2' }, }); const buttons = wrapper.findAll('button'); expect(buttons[0].attributes('tabindex')).toBe('-1'); expect(buttons[1].attributes('tabindex')).toBe('0'); expect(buttons[2].attributes('tabindex')).toBe('-1'); }); it('keeps the first segment tabbable when modelValue does not match any segment', () => { const wrapper = mount(MSegmentedControl, { props: { segments, modelValue: 'unknown' }, }); const buttons = wrapper.findAll('button'); expect(buttons[0].attributes('tabindex')).toBe('0'); expect(buttons[1].attributes('tabindex')).toBe('-1'); expect(buttons[2].attributes('tabindex')).toBe('-1'); expect(buttons[0].attributes('aria-checked')).toBe('false'); }); it('ArrowRight selects and focuses the next segment', async () => { const wrapper = mount(MSegmentedControl, { attachTo: document.body, props: { segments, modelValue: '1' }, }); const buttons = wrapper.findAll('button'); await buttons[0].element.focus(); await buttons[0].trigger('keydown', { key: 'ArrowRight' }); await nextTick(); expect(wrapper.emitted('update:modelValue')![0]).toEqual(['2']); expect(document.activeElement).toBe(buttons[1].element); wrapper.unmount(); }); it('ArrowLeft selects and focuses the previous segment', async () => { const wrapper = mount(MSegmentedControl, { attachTo: document.body, props: { segments, modelValue: '2' }, }); const buttons = wrapper.findAll('button'); await buttons[1].trigger('keydown', { key: 'ArrowLeft' }); expect(wrapper.emitted('update:modelValue')![0]).toEqual(['1']); wrapper.unmount(); }); it('ArrowRight wraps around from last to first segment', async () => { const wrapper = mount(MSegmentedControl, { attachTo: document.body, props: { segments, modelValue: '3' }, }); const buttons = wrapper.findAll('button'); await buttons[2].trigger('keydown', { key: 'ArrowRight' }); expect(wrapper.emitted('update:modelValue')![0]).toEqual(['1']); wrapper.unmount(); }); it('Home selects the first segment', async () => { const wrapper = mount(MSegmentedControl, { attachTo: document.body, props: { segments, modelValue: '3' }, }); const buttons = wrapper.findAll('button'); await buttons[2].trigger('keydown', { key: 'Home' }); expect(wrapper.emitted('update:modelValue')![0]).toEqual(['1']); wrapper.unmount(); }); it('End selects the last segment', async () => { const wrapper = mount(MSegmentedControl, { attachTo: document.body, props: { segments, modelValue: '1' }, }); const buttons = wrapper.findAll('button'); await buttons[0].trigger('keydown', { key: 'End' }); expect(wrapper.emitted('update:modelValue')![0]).toEqual(['3']); wrapper.unmount(); }); }); });