import { describe, it, expect } from 'vitest' import { mount } from '@vue/test-utils' import CollapsibleCard from '../../components/CollapsibleCard.vue' describe('CollapsibleCard', () => { describe('basic rendering', () => { it('should render with required title prop', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card' }, }) expect(wrapper.find('.mint-collapsible-card').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__title').text()).toBe('Test Card') }) it('should render subtitle when provided', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', subtitle: 'Test Subtitle' }, }) expect(wrapper.find('.mint-collapsible-card__subtitle').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__subtitle').text()).toBe('Test Subtitle') }) it('should not render subtitle when not provided', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card' }, }) expect(wrapper.find('.mint-collapsible-card__subtitle').exists()).toBe(false) }) }) describe('icon rendering: SVG paths', () => { it('should render SVG when icon starts with uppercase M', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'M12 2L2 7l10 5 10-5-10-5z', }, }) expect(wrapper.find('.mint-collapsible-card__icon-badge').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon').element.tagName).toBe('svg') expect(wrapper.find('.mint-collapsible-card__icon path').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon-text').exists()).toBe(false) }) it('should render SVG when icon starts with lowercase m', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'm12 2l-10 5 10 5 10-5-10-5z', }, }) expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon').element.tagName).toBe('svg') expect(wrapper.find('.mint-collapsible-card__icon path').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon-text').exists()).toBe(false) }) it('should render single path element with correct d attribute', () => { const pathData = 'M12 2L2 7l10 5 10-5-10-5z' const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: pathData, }, }) const path = wrapper.find('.mint-collapsible-card__icon path') expect(path.exists()).toBe(true) expect(path.attributes('d')).toBe(pathData) }) it('should render SVG with multiple paths when icon is an array', () => { const paths = [ 'M12 2L2 7l10 5 10-5-10-5z', 'M2 17l10 5 10-5M2 12l10 5 10-5', ] const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: paths, }, }) expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon').element.tagName).toBe('svg') const pathElements = wrapper.findAll('.mint-collapsible-card__icon path') expect(pathElements).toHaveLength(2) expect(pathElements[0].attributes('d')).toBe(paths[0]) expect(pathElements[1].attributes('d')).toBe(paths[1]) expect(wrapper.find('.mint-collapsible-card__icon-text').exists()).toBe(false) }) it('should set correct SVG attributes for path icons', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'M12 2L2 7', }, }) const svg = wrapper.find('.mint-collapsible-card__icon') expect(svg.attributes('viewBox')).toBe('0 0 24 24') expect(svg.attributes('fill')).toBe('none') expect(svg.attributes('stroke')).toBe('currentColor') expect(svg.attributes('stroke-width')).toBe('2') expect(svg.attributes('stroke-linecap')).toBe('round') expect(svg.attributes('stroke-linejoin')).toBe('round') }) }) describe('icon rendering: text and emoji', () => { it('should render emoji as text in span element', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'โš™', }, }) expect(wrapper.find('.mint-collapsible-card__icon-badge').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon-text').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon-text').text()).toBe('โš™') expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(false) }) it('should render single letter as text in span element', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'A', }, }) expect(wrapper.find('.mint-collapsible-card__icon-text').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon-text').text()).toBe('A') expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(false) }) it('should render multi-character text as span element', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'AB', }, }) expect(wrapper.find('.mint-collapsible-card__icon-text').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon-text').text()).toBe('AB') expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(false) }) it('should handle various emoji types', () => { const emojis = ['๐Ÿ”ฌ', '๐Ÿ’Š', '๐Ÿงช', '๐Ÿ“Š', 'โญ'] emojis.forEach((emoji) => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: emoji, }, }) expect(wrapper.find('.mint-collapsible-card__icon-text').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon-text').text()).toBe(emoji) expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(false) }) }) }) describe('icon rendering: edge cases', () => { it('should not render icon badge when icon prop is undefined', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card' }, }) expect(wrapper.find('.mint-collapsible-card__icon-badge').exists()).toBe(false) expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(false) expect(wrapper.find('.mint-collapsible-card__icon-text').exists()).toBe(false) }) it('should not render icon badge when icon prop is empty string', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: '' }, }) expect(wrapper.find('.mint-collapsible-card__icon-badge').exists()).toBe(false) }) it('should render empty array as SVG with no paths', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: [], }, }) expect(wrapper.find('.mint-collapsible-card__icon-badge').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(true) expect(wrapper.findAll('.mint-collapsible-card__icon path')).toHaveLength(0) }) it('should render string starting with non-M letter as text', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'Hello', }, }) expect(wrapper.find('.mint-collapsible-card__icon-text').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon-text').text()).toBe('Hello') expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(false) }) it('should render string with M in middle as text', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'AMB', }, }) expect(wrapper.find('.mint-collapsible-card__icon-text').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__icon-text').text()).toBe('AMB') }) }) describe('icon styling', () => { it('should apply custom icon color', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'M12 2L2 7', iconColor: '#ff0000', }, }) const svg = wrapper.find('.mint-collapsible-card__icon') expect(svg.attributes('style')).toContain('color: #ff0000') }) it('should apply custom icon background', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'โš™', iconBg: '#00ff00', }, }) const badge = wrapper.find('.mint-collapsible-card__icon-badge') expect(badge.attributes('style')).toContain('background-color: #00ff00') }) it('should apply color to text icons', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'A', iconColor: '#0000ff', }, }) const textIcon = wrapper.find('.mint-collapsible-card__icon-text') expect(textIcon.attributes('style')).toContain('color: #0000ff') }) it('should use default background when iconBg not provided', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'โš™', }, }) const badge = wrapper.find('.mint-collapsible-card__icon-badge') expect(badge.attributes('style')).toContain('background-color: var(--color-primary-soft)') }) it('should use default color when iconColor not provided', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'M12 2L2 7', }, }) const svg = wrapper.find('.mint-collapsible-card__icon') expect(svg.attributes('style')).toContain('color: var(--color-primary)') }) }) describe('collapsible behavior', () => { it('should be closed by default', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card' }, }) const body = wrapper.find('.mint-collapsible-card__body') expect((body.element as HTMLElement).style.display).toBe('none') expect(wrapper.find('button').attributes('aria-expanded')).toBe('false') }) it('should be open when defaultOpen is true', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', defaultOpen: true }, }) const body = wrapper.find('.mint-collapsible-card__body') expect((body.element as HTMLElement).style.display).not.toBe('none') expect(wrapper.find('button').attributes('aria-expanded')).toBe('true') }) it('should toggle open state when header is clicked', async () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card' }, }) let body = wrapper.find('.mint-collapsible-card__body') expect((body.element as HTMLElement).style.display).toBe('none') await wrapper.find('button').trigger('click') body = wrapper.find('.mint-collapsible-card__body') expect((body.element as HTMLElement).style.display).not.toBe('none') await wrapper.find('button').trigger('click') body = wrapper.find('.mint-collapsible-card__body') expect((body.element as HTMLElement).style.display).toBe('none') }) it('should not toggle when disabled', async () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', disabled: true }, }) let body = wrapper.find('.mint-collapsible-card__body') expect((body.element as HTMLElement).style.display).toBe('none') await wrapper.find('button').trigger('click') body = wrapper.find('.mint-collapsible-card__body') expect((body.element as HTMLElement).style.display).toBe('none') }) it('should apply disabled class and attribute', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', disabled: true }, }) const header = wrapper.find('button') expect(header.attributes('disabled')).toBeDefined() expect(header.classes()).toContain('mint-collapsible-card__header--disabled') }) }) describe('toggle switch', () => { it('should not render toggle by default', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card' }, }) expect(wrapper.find('.mint-collapsible-card__toggle').exists()).toBe(false) }) it('should render toggle when showToggle is true', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', showToggle: true }, }) expect(wrapper.find('.mint-collapsible-card__toggle').exists()).toBe(true) expect(wrapper.find('[role="switch"]').exists()).toBe(true) }) it('should reflect toggle state', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', showToggle: true, toggleValue: true }, }) expect(wrapper.get('[role="switch"]').attributes('aria-checked')).toBe('true') }) it('should render the shared BaseToggle when showToggle is true (10a)', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', showToggle: true }, }) expect(wrapper.find('.mint-collapsible-card__toggle .mint-toggle__track').exists()).toBe(true) }) it('should emit update:toggleValue event', async () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', showToggle: true, toggleValue: false }, }) await wrapper.find('[role="switch"]').trigger('click') expect(wrapper.emitted('update:toggleValue')).toBeTruthy() expect(wrapper.emitted('update:toggleValue')?.[0]).toEqual([true]) }) it('should stop event propagation on toggle click', async () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', showToggle: true, defaultOpen: false }, }) // Click toggle should not expand/collapse the card await wrapper.find('[role="switch"]').trigger('click') const body = wrapper.find('.mint-collapsible-card__body') expect((body.element as HTMLElement).style.display).toBe('none') }) it('should apply custom toggle color when active', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', showToggle: true, toggleValue: true, toggleColor: '#ff0000', }, }) expect(wrapper.get('.mint-collapsible-card__toggle').attributes('style')).toContain('--_cc-toggle-on: #ff0000') }) }) describe('badges and header actions', () => { it('renders a compact badge in the header controls area', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Feature Filters', badge: 3, badgeTone: 'warning' }, }) const badge = wrapper.get('.mint-collapsible-card__badge') expect(badge.text()).toBe('3') expect(badge.classes()).toContain('mint-collapsible-card__badge--warning') }) it('renders icon-only header actions and emits their ids', async () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Feature Filters', actions: [ { id: 'reset', label: 'Reset filters', icon: 'M16.023 9.348h4.992M2.985 19.644v-4.992', tone: 'neutral', }, ], }, }) const action = wrapper.get('.mint-collapsible-card__action') expect(action.attributes('aria-label')).toBe('Reset filters') expect(wrapper.find('.mint-collapsible-card__action-icon').exists()).toBe(true) await action.trigger('click') expect(wrapper.emitted('action')).toEqual([['reset']]) }) it('does not emit disabled actions', async () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Feature Filters', actions: [{ id: 'reset', label: 'Reset filters', disabled: true }], }, }) await wrapper.get('.mint-collapsible-card__action').trigger('click') expect(wrapper.emitted('action')).toBeUndefined() }) }) describe('content slot', () => { it('should render default slot content', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', defaultOpen: true }, slots: { default: '

Card content

', }, }) expect(wrapper.find('.mint-collapsible-card__content').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__content').html()).toContain('Card content') }) }) describe('chevron indicator', () => { it('should render chevron icon', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card' }, }) expect(wrapper.find('.mint-collapsible-card__chevron').exists()).toBe(true) }) it('should toggle chevron class when open', async () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card' }, }) const chevron = wrapper.find('.mint-collapsible-card__chevron') expect(chevron.classes()).not.toContain('mint-collapsible-card__chevron--open') await wrapper.find('button').trigger('click') expect(chevron.classes()).toContain('mint-collapsible-card__chevron--open') }) }) describe('integration: icon with other features', () => { it('should render SVG icon with toggle and custom colors', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', icon: 'M12 2L2 7', iconColor: '#ff0000', iconBg: '#00ff00', showToggle: true, toggleValue: true, toggleColor: '#0000ff', }, }) expect(wrapper.find('.mint-collapsible-card__icon').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__toggle').exists()).toBe(true) const svg = wrapper.find('.mint-collapsible-card__icon') expect(svg.attributes('style')).toContain('color: #ff0000') const badge = wrapper.find('.mint-collapsible-card__icon-badge') expect(badge.attributes('style')).toContain('background-color: #00ff00') }) it('should render emoji icon with subtitle and disabled state', () => { const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', subtitle: 'Subtitle', icon: '๐Ÿ”ฌ', disabled: true, }, }) expect(wrapper.find('.mint-collapsible-card__icon-text').text()).toBe('๐Ÿ”ฌ') expect(wrapper.find('.mint-collapsible-card__subtitle').text()).toBe('Subtitle') expect(wrapper.find('button').attributes('disabled')).toBeDefined() }) it('should render multi-path icon array with all features', () => { const paths = ['M12 2L2 7', 'M2 17l10 5'] const wrapper = mount(CollapsibleCard, { props: { title: 'Test Card', subtitle: 'Subtitle', icon: paths, iconColor: '#ff0000', iconBg: '#00ff00', showToggle: true, defaultOpen: true, }, }) const pathElements = wrapper.findAll('.mint-collapsible-card__icon path') expect(pathElements).toHaveLength(2) expect(wrapper.find('.mint-collapsible-card__subtitle').exists()).toBe(true) expect(wrapper.find('.mint-collapsible-card__toggle').exists()).toBe(true) const body = wrapper.find('.mint-collapsible-card__body') expect((body.element as HTMLElement).style.display).not.toBe('none') }) }) })