import { afterEach, beforeEach, describe, expect, it } from 'vitest' import { enableAutoUnmount, flushPromises, mount } from '@vue/test-utils' import AppShell from '../../src/components/shell/AppShell.vue' import { setNavigation } from '../../src/state/useNavigation' import { NARROW_QUERY, setCollapsed } from '../../src/state/useSidebar' import { showToast } from '../../src/state/useToasts' import { navigationFixture } from '../fixtures/typed' import { fakeMedia, resetState, routerAt, signIn } from '../helpers' async function mountShell(path: string) { await signIn() setNavigation(navigationFixture.data) const router = await routerAt(path) const wrapper = mount(AppShell, { slots: { default: '
content
' }, global: { plugins: [router] }, attachTo: document.body, }) await flushPromises() return wrapper } beforeEach(() => { resetState() setCollapsed(false) }) afterEach(() => { setCollapsed(false) document.body.innerHTML = '' }) enableAutoUnmount(afterEach) describe('app shell', () => { it('renders rail, section panel, header landmarks and the page in main', async () => { const wrapper = await mountShell('/acme/demo/widgets') expect(wrapper.find('nav[aria-label="Wtyczki"]').exists()).toBe(true) expect(wrapper.find('aside[aria-label="Sekcje"]').exists()).toBe(true) expect(wrapper.find('header nav[aria-label="Ścieżka nawigacji"]').exists()).toBe(true) expect(wrapper.find('header [data-user-menu]').exists()).toBe(true) expect(wrapper.find('main [data-page]').text()).toBe('content') }) it('has no section panel outside a permitted plugin', async () => { const wrapper = await mountShell('/settings') expect(wrapper.find('aside').exists()).toBe(false) }) it('hides the section panel when collapsed by the admin or by the viewport', async () => { const wrapper = await mountShell('/acme/demo/widgets') setCollapsed(true) await flushPromises() expect(wrapper.find('aside').exists()).toBe(false) setCollapsed(false) await flushPromises() expect(wrapper.find('aside').exists()).toBe(true) }) it('follows the viewport while mounted and stops listening on unmount', async () => { const media = fakeMedia({ [NARROW_QUERY]: false }) const wrapper = await mountShell('/acme/demo/widgets') expect(media.listeners(NARROW_QUERY)).toBe(1) media.change(NARROW_QUERY, true) await flushPromises() expect(wrapper.find('aside').exists()).toBe(false) wrapper.unmount() expect(media.listeners(NARROW_QUERY)).toBe(0) }) it('mounts the toast queue with status and alert roles', async () => { const wrapper = await mountShell('/acme/demo/widgets') showToast('Saved') showToast('Broken', 'danger') await flushPromises() expect(wrapper.find('[role="status"]').text()).toContain('Saved') expect(wrapper.find('[role="alert"]').text()).toContain('Broken') }) })