import { afterEach, beforeEach, describe, expect, it } from 'vitest' import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils' import SettingsPanel from '../../src/components/shell/SettingsPanel.vue' import { SIDEBAR_KEY, setCollapsed, sidebarCollapsed } from '../../src/state/useSidebar' import { setSettings, settingsEntry, settingsLinkFor, settingsSectionOf, type SettingsSection, } from '../../src/state/useSettings' import { settingsFixture } from '../fixtures/typed' import { resetState, routerAt, signIn } from '../helpers' beforeEach(() => { resetState() setCollapsed(false) }) afterEach(() => { setCollapsed(false) document.body.innerHTML = '' }) enableAutoUnmount(afterEach) const locales = { ...settingsFixture.list.data[0]!, code: 'locales', label: 'Locales', model: '', controller: 'acme.lang.locales', order: 15, } async function mountPanel(path: string, section: SettingsSection) { await signIn() const router = await routerAt(path) const wrapper = mount(SettingsPanel, { props: { section }, global: { plugins: [router] }, attachTo: document.body }) await flushPromises() return wrapper } describe('settings panel', () => { it('is a labelled region with the category and its pages in section order', async () => { setSettings(settingsFixture.list.data) const wrapper = await mountPanel('/settings/search', settingsSectionOf(settingsEntry('search'))!) const aside = wrapper.find('aside') expect(aside.attributes('aria-label')).toBe('Sekcje') expect(aside.attributes('data-settings-panel')).toBeDefined() expect(aside.find('span').text()).toBe('System') const links = wrapper.findAll('a') expect(links.map((link) => [link.text(), link.attributes('href'), link.attributes('data-settings-panel-item')])).toEqual([ ['Mail', '/settings/mail', 'mail'], ['Search', '/settings/search', 'search'], ]) expect(links[0]!.attributes('aria-current')).toBeUndefined() expect(links[1]!.attributes('aria-current')).toBe('page') }) it('links a settings link entry to its controller and highlights only it', async () => { setSettings([...settingsFixture.list.data, locales]) const wrapper = await mountPanel('/acme/lang/locales', settingsSectionOf(settingsLinkFor('acme.lang.locales'))!) const links = wrapper.findAll('a') expect(links.map((link) => [link.text(), link.attributes('href')])).toEqual([ ['Mail', '/settings/mail'], ['Locales', '/acme/lang/locales'], ['Search', '/settings/search'], ]) expect(links.filter((link) => link.attributes('aria-current') === 'page').map((link) => link.text())).toEqual([ 'Locales', ]) }) it('falls back to "Ustawienia" for an empty category', async () => { const [search, mail] = settingsFixture.list.data const section: SettingsSection = { category: '', current: { ...mail!, category: '' }, entries: [ { ...mail!, category: '' }, { ...search!, category: '' }, ], } const wrapper = await mountPanel('/settings/mail', section) expect(wrapper.find('aside span').text()).toBe('Ustawienia') }) it('collapses on "Zwiń menu" and persists the choice', async () => { setSettings(settingsFixture.list.data) const wrapper = await mountPanel('/settings/mail', settingsSectionOf(settingsEntry('mail'))!) const button = wrapper.find('[data-sidebar-collapse]') expect(button.attributes('aria-label')).toBe('Zwiń menu') expect(button.attributes('type')).toBe('button') await button.trigger('click') expect(sidebarCollapsed.value).toBe(true) expect(window.localStorage.getItem(SIDEBAR_KEY)).toBe('true') }) })