import { mount } from '@vue/test-utils' import { describe, expect, it } from 'vitest' import SegmentedControl from '../../components/SegmentedControl.vue' describe('SegmentedControl', () => { it('defaults to card while allowing an explicit simple variant', async () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'table', options: [{ value: 'table', label: 'Table', description: 'View rows' }], }, }) expect(wrapper.classes()).toContain('mint-segmented-control--card') expect(wrapper.get('button').classes()).toContain('mint-segmented-control__option--card') expect(wrapper.get('.mint-segmented-control__description').text()).toBe('View rows') await wrapper.setProps({ variant: 'simple' }) expect(wrapper.classes()).toContain('mint-segmented-control--simple') expect(wrapper.get('button').classes()).toContain('mint-segmented-control__option--simple') expect(wrapper.find('.mint-segmented-control__description').exists()).toBe(false) }) it('accepts string and number shorthand options', async () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'linear', options: ['linear', 96, { value: 'log', label: 'Log scale' }], }, }) expect(wrapper.findAll('button').map(button => button.text())).toEqual([ 'linear', '96', 'Log scale', ]) await wrapper.findAll('button')[1].trigger('click') expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([96]) }) it('renders option-level disabled tabs without allowing selection', async () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'active', options: [ { value: 'active', label: 'Active' }, { value: 'archived', label: 'Archived', disabled: true }, ], }, }) const buttons = wrapper.findAll('button') expect(buttons).toHaveLength(2) expect(buttons[1].attributes('disabled')).toBeDefined() expect(buttons[1].classes()).toContain('mint-segmented-control__option--disabled') await buttons[1].trigger('click') expect(wrapper.emitted('update:modelValue')).toBeUndefined() }) it('can disable tabs by value while keeping them visible', async () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'table', options: [ { value: 'table', label: 'Table' }, { value: 'chart', label: 'Chart' }, ], disabledValues: ['chart'], }, }) const buttons = wrapper.findAll('button') expect(buttons.map(button => button.text())).toEqual(['Table', 'Chart']) expect(buttons[1].attributes('disabled')).toBeDefined() await buttons[1].trigger('keydown.enter') await buttons[1].trigger('click') expect(wrapper.emitted('update:modelValue')).toBeUndefined() }) describe('roving tabindex', () => { const options = [ { value: 'table', label: 'Table' }, { value: 'chart', label: 'Chart' }, { value: 'raw', label: 'Raw' }, ] it('makes only the checked option tabbable', () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'chart', options }, }) expect(wrapper.findAll('button').map(button => button.attributes('tabindex'))) .toEqual(['-1', '0', '-1']) }) it('falls back to the first selectable option when nothing matches', () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'missing', options }, }) expect(wrapper.findAll('button').map(button => button.attributes('tabindex'))) .toEqual(['0', '-1', '-1']) }) it('activates the adjacent option with the arrow keys, wrapping at the ends', async () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'chart', options }, attachTo: document.body, }) const buttons = wrapper.findAll('button') await buttons[1].trigger('keydown', { key: 'ArrowRight' }) expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['raw']) await buttons[1].trigger('keydown', { key: 'ArrowLeft' }) expect(wrapper.emitted('update:modelValue')?.[1]).toEqual(['table']) await wrapper.setProps({ modelValue: 'raw' }) await wrapper.findAll('button')[2].trigger('keydown', { key: 'ArrowRight' }) expect(wrapper.emitted('update:modelValue')?.[2]).toEqual(['table']) wrapper.unmount() }) it('jumps to the first and last option with Home and End', async () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'chart', options }, }) const buttons = wrapper.findAll('button') await buttons[1].trigger('keydown', { key: 'Home' }) expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['table']) await buttons[1].trigger('keydown', { key: 'End' }) expect(wrapper.emitted('update:modelValue')?.[1]).toEqual(['raw']) }) it('skips disabled options during arrow navigation', async () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'table', options, disabledValues: ['chart'], }, }) await wrapper.findAll('button')[0].trigger('keydown', { key: 'ArrowRight' }) expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['raw']) }) it('moves focus onto the newly activated option', async () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'table', options }, attachTo: document.body, }) await wrapper.findAll('button')[0].trigger('keydown', { key: 'ArrowRight' }) await wrapper.setProps({ modelValue: 'chart' }) await wrapper.vm.$nextTick() expect(document.activeElement).toBe(wrapper.findAll('button')[1].element) wrapper.unmount() }) }) }) describe('SegmentedControl option color (9b)', () => { it('should render a swatch in the option color when the option has a color', () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'a', options: [{ value: 'a', label: 'Control', color: 'var(--mint-sample-2)' }] }, }) expect(wrapper.get('.mint-segmented-control__swatch').attributes('style')).toContain('var(--mint-sample-2)') }) it('should render no swatch when the option has no color', () => { const wrapper = mount(SegmentedControl, { props: { modelValue: 'a', options: ['a'] } }) expect(wrapper.find('.mint-segmented-control__swatch').exists()).toBe(false) }) })