diff --git a/apps/app/src/components-v2/layout/__tests__/AppSidebar.spec.ts b/apps/app/src/components-v2/layout/__tests__/AppSidebar.spec.ts index 399c68c8..d23ebcda 100644 --- a/apps/app/src/components-v2/layout/__tests__/AppSidebar.spec.ts +++ b/apps/app/src/components-v2/layout/__tests__/AppSidebar.spec.ts @@ -56,7 +56,7 @@ vi.mock('@vueuse/core', () => ({ */ const DrawerStub = { name: 'Drawer', - props: ['visible', 'position', 'pt'], + props: ['visible', 'position', 'pt', 'showCloseIcon'], emits: ['update:visible'], template: '
', } @@ -138,6 +138,70 @@ describe('AppSidebar', () => { expect(wrapper.find('.drawer-stub').exists()).toBe(true) }) + // ------------------------------------------------------------------------- + // MOBILE-SHELL-PARITY — drawer chrome pt contract + // ------------------------------------------------------------------------- + + it('mobile: drawer force-hides the PrimeVue default header (!hidden) so the default close-X cannot overlap', async () => { + mockIsMobileRef.value = true + + const wrapper = mountSidebar() + + await wrapper.vm.$nextTick() + + const pt = wrapper.findComponent(DrawerStub).props('pt') as { + header: { class: string } + content: { class: string } + } + + // defect 2: PrimeVue's default header (which holds the default close-X) + // is suppressed with the important variant so base styles cannot win. + expect(pt.header.class).toContain('!hidden') + }) + + it('mobile: drawer content is a full-height flex column (WorkspaceSwitcher bottom-anchor)', async () => { + mockIsMobileRef.value = true + + const wrapper = mountSidebar() + + await wrapper.vm.$nextTick() + + const pt = wrapper.findComponent(DrawerStub).props('pt') as { + content: { class: string } + } + + // defect 3: full-height flex column so SidebarNav claims the slack and + // WorkspaceSwitcher (flex-shrink-0) anchors at the bottom. + expect(pt.content.class).toContain('flex-col') + expect(pt.content.class).toContain('h-full') + expect(pt.content.class).toContain('min-h-0') + }) + + it('mobile: drawer does NOT suppress the close affordance via showCloseIcon=false', async () => { + mockIsMobileRef.value = true + + const wrapper = mountSidebar() + + await wrapper.vm.$nextTick() + + // The mobile close control lives in SidebarHeader's brand row; the Drawer + // is left at its default showCloseIcon (never forced to false). + expect(wrapper.findComponent(DrawerStub).props('showCloseIcon')).not.toBe(false) + }) + + it('mobile: WorkspaceSwitcher renders inside the drawer', async () => { + mockIsMobileRef.value = true + + const wrapper = mountSidebar() + + await wrapper.vm.$nextTick() + + const drawer = wrapper.find('.drawer-stub') + + expect(drawer.exists()).toBe(true) + expect(drawer.find('.workspace-switcher-stub').exists()).toBe(true) + }) + // ------------------------------------------------------------------------- // Desktop