import { describe, it, expect } from 'vitest' import { h } from 'vue' import { mount } from '@vue/test-utils' import { Primitive } from '../src/lib/primitive' import SlotPassthrough from './fixtures/SlotPassthrough.vue' describe('Primitive', () => { it('renders the "as" tag with forwarded attrs when asChild is false', () => { const wrapper = mount(Primitive, { props: { as: 'a' }, attrs: { href: '/somewhere', class: 'link' }, slots: { default: () => 'Go' }, }) const el = wrapper.get('a') expect(el.attributes('href')).toBe('/somewhere') expect(el.classes()).toContain('link') expect(el.text()).toBe('Go') }) it('clones the single child and merges attrs onto it when asChild is true', async () => { let clicked = false const wrapper = mount(Primitive, { props: { asChild: true }, attrs: { class: 'from-parent', 'data-slot': 'button', onClick: () => { clicked = true } }, slots: { default: () => h('button', { class: 'from-child', type: 'button' }, 'Click'), }, }) const el = wrapper.get('button') expect(el.attributes('data-slot')).toBe('button') expect(el.attributes('type')).toBe('button') expect(el.classes()).toContain('from-parent') expect(el.classes()).toContain('from-child') await el.trigger('click') expect(clicked).toBe(true) }) it('throws if asChild is true with zero or multiple children', () => { expect(() => mount(Primitive, { props: { asChild: true }, slots: { default: () => [h('span', 'a'), h('span', 'b')] }, }), ).toThrow() }) it('merges attrs through a real SFC that forwards `` as asChild content', async () => { // Regression test: `` used as a passthrough outlet inside an SFC // template resolves through Vue's renderSlot() helper, which wraps the // forwarded content in a Fragment vnode even when there's exactly one // real child. Slot must unwrap that Fragment before cloning, or the // merged attrs silently vanish onto the inert wrapper instead of the // real child element. let clicked = false const wrapper = mount(SlotPassthrough, { props: { asChild: true }, attrs: { onClick: () => { clicked = true } }, slots: { default: () => h('a', { href: '/somewhere' }, 'Click'), }, }) const el = wrapper.get('a') expect(el.attributes('data-slot')).toBe('passthrough-wrapper') expect(el.attributes('type')).toBe('button') expect(el.attributes('href')).toBe('/somewhere') await el.trigger('click') expect(clicked).toBe(true) }) })