import { describe, it, expect, beforeEach } from 'vitest' import { mount, flushPromises } from '@vue/test-utils' import { setActivePinia, createPinia } from 'pinia' import { createRouter, createMemoryHistory, type Router } from 'vue-router' import BottomNav from '@/components/BottomNav.vue' import { useImagesStore } from '@/stores/images' const Stub = { template: '
' } function makeRouter(): Router { return createRouter({ history: createMemoryHistory(), routes: [ { path: '/', component: Stub }, { path: '/library', component: Stub }, { path: '/settings', component: Stub }, ], }) } async function mountAt(router: Router, path: string) { await router.push(path) await router.isReady() return mount(BottomNav, { global: { plugins: [router] } }) } function activeTabName(wrapper: ReturnType): string | undefined { const active = wrapper.find('.bottom-nav__tab--active') if (!active.exists()) return undefined return active.find('.bottom-nav__label').text() } describe('BottomNav', () => { let router: Router beforeEach(() => { setActivePinia(createPinia()) router = makeRouter() }) it('renders three tabs (Home, Library, Settings)', async () => { const wrapper = await mountAt(router, '/') const labels = wrapper.findAll('.bottom-nav__label').map(n => n.text()) expect(labels).toEqual(['Home', 'Library', 'Settings']) }) it('marks Home active on /', async () => { const wrapper = await mountAt(router, '/') expect(activeTabName(wrapper)).toBe('Home') }) it('marks Library active on /library', async () => { const wrapper = await mountAt(router, '/library') expect(activeTabName(wrapper)).toBe('Library') }) it('marks Library active on /library?tab=shared', async () => { const wrapper = await mountAt(router, '/library?tab=shared') expect(activeTabName(wrapper)).toBe('Library') }) it('marks Settings active on /settings', async () => { const wrapper = await mountAt(router, '/settings') expect(activeTabName(wrapper)).toBe('Settings') }) it('does not mark Home active on /library (regression: startsWith bug)', async () => { const wrapper = await mountAt(router, '/library') const homeTab = wrapper.findAll('.bottom-nav__tab') .find(t => t.find('.bottom-nav__label').text() === 'Home') expect(homeTab?.classes()).not.toContain('bottom-nav__tab--active') }) it('updates active tab when route changes', async () => { const wrapper = await mountAt(router, '/') expect(activeTabName(wrapper)).toBe('Home') await router.push('/library') await flushPromises() expect(activeTabName(wrapper)).toBe('Library') }) it('shows the pending-share count as a badge on the Library tab', async () => { const images = useImagesStore() images.pendingCount = 3 const wrapper = await mountAt(router, '/') const libraryTab = wrapper.findAll('.bottom-nav__tab') .find(t => t.find('.bottom-nav__label').text() === 'Library')! const badge = libraryTab.find('.bottom-nav__badge') expect(badge.exists()).toBe(true) expect(badge.text()).toBe('3') }) it('clamps the badge count to "9+" when 10 or more are pending', async () => { const images = useImagesStore() images.pendingCount = 12 const wrapper = await mountAt(router, '/') expect(wrapper.find('.bottom-nav__badge').text()).toBe('9+') }) it('hides the badge when no shares are pending', async () => { const images = useImagesStore() images.pendingCount = 0 const wrapper = await mountAt(router, '/') expect(wrapper.find('.bottom-nav__badge').exists()).toBe(false) }) })