/**
* Component tests for SvAccordion: single vs multiple expand, ARIA wiring
* (aria-expanded / aria-controls / region), and toggle behavior.
*/
import { describe, expect, it } from 'vitest'
import { mount, unmount, flushSync } from 'svelte'
import { createRawSnippet } from 'svelte'
import SvAccordion from './SvAccordion.svelte'
const items = [
{ id: 'a', label: 'First' },
{ id: 'b', label: 'Second' },
{ id: 'c', label: 'Third' },
]
// A trivial panel snippet so the body renders.
const panel = createRawSnippet((item: () => { id: string; label: string }) => ({
render: () => `
body-${item().id}
`,
}))
function mountAcc(props: Record) {
const target = document.createElement('div')
document.body.appendChild(target)
const app = mount(SvAccordion, { target, props: { panel, ...props } as any })
flushSync()
return { target, destroy: () => { unmount(app); target.remove() } }
}
describe('SvAccordion', () => {
it('renders headers with aria-expanded + aria-controls and shows only the open panel', () => {
const { target, destroy } = mountAcc({ items, expanded: ['a'] })
try {
const headers = [...target.querySelectorAll('.sv-acc__header')]
expect(headers).toHaveLength(3)
expect(headers[0]!.getAttribute('aria-expanded')).toBe('true')
expect(headers[1]!.getAttribute('aria-expanded')).toBe('false')
const region = target.querySelector('.sv-acc__panel')!
expect(region.getAttribute('role')).toBe('region')
expect(region.getAttribute('aria-labelledby')).toBe(headers[0]!.id)
// Only one panel region is rendered (the open one).
expect(target.querySelectorAll('.sv-acc__panel')).toHaveLength(1)
} finally { destroy() }
})
it('single mode: opening one closes the previous', () => {
let got: string[] | undefined
const { target, destroy } = mountAcc({ items, expanded: ['a'], expandMode: 'single', onChange: (ids: string[]) => (got = ids) })
try {
const headers = target.querySelectorAll('.sv-acc__header')
headers[1]!.click()
flushSync()
expect(got).toEqual(['b'])
} finally { destroy() }
})
it('multiple mode: toggling accumulates open panels', () => {
let got: string[] | undefined
const { target, destroy } = mountAcc({ items, expanded: ['a'], expandMode: 'multiple', onChange: (ids: string[]) => (got = ids) })
try {
const headers = target.querySelectorAll('.sv-acc__header')
headers[2]!.click()
flushSync()
expect(got).toEqual(['a', 'c'])
} finally { destroy() }
})
})