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)
})
})