import { describe, it, expect, beforeEach, vi } from 'vitest'
import { mount, RouterLinkStub } from '@vue/test-utils'
import { createRouter, createWebHistory } from 'vue-router'
import { setActivePinia, createPinia } from 'pinia'
import Layout from './Layout.vue'
import { useAuthStore } from '../../stores/auth'
vi.mock('../../api', () => ({
default: { post: vi.fn(), defaults: { headers: { common: {} } } },
}))
async function mountLayout(path = '/admin/dashboard') {
setActivePinia(createPinia())
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/admin/login', component: { template: '
' } },
{ path: '/admin/dashboard', component: { template: 'dashboard
' } },
{ path: '/admin/posts', component: { template: '' } },
],
})
router.push(path)
await router.isReady()
const wrapper = mount(Layout, {
global: { plugins: [router], stubs: { RouterLink: RouterLinkStub } },
})
return { wrapper, router }
}
describe('Layout (admin)', () => {
beforeEach(() => {
localStorage.clear()
vi.clearAllMocks()
})
it('renders the sidebar nav items and the current user', async () => {
const { wrapper } = await mountLayout()
const auth = useAuthStore()
auth.user = { name: 'Admin User', role: 'admin' }
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('Dashboard')
expect(wrapper.text()).toContain('Posts')
expect(wrapper.text()).toContain('Admin User')
})
it('highlights the active nav item', async () => {
const { wrapper } = await mountLayout('/admin/posts')
const links = wrapper.findAllComponents(RouterLinkStub)
const postsLink = links.find(l => l.props('to') === '/admin/posts')
expect(postsLink.classes()).toContain('bg-primary-600')
})
it('logs out and redirects to the login page', async () => {
const { wrapper, router } = await mountLayout()
const pushSpy = vi.spyOn(router, 'push')
const auth = useAuthStore()
const logoutSpy = vi.spyOn(auth, 'logout')
const signOutBtn = wrapper.findAll('button').find(b => b.text().includes('Sign Out'))
await signOutBtn.trigger('click')
expect(logoutSpy).toHaveBeenCalled()
expect(pushSpy).toHaveBeenCalledWith('/admin/login')
})
it('opens and closes the mobile sidebar', async () => {
const { wrapper } = await mountLayout()
const findMobileHeader = () => wrapper.findAll('span').find(s => s.text() === 'Meridian Admin')
expect(findMobileHeader()).toBeUndefined()
const toggleBtn = wrapper.findAll('button').find(b => b.classes().includes('lg:hidden'))
await toggleBtn.trigger('click')
expect(findMobileHeader()).toBeDefined()
})
})