File size: 2,717 Bytes
6137fac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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: '<div/>' } },
      { path: '/admin/dashboard', component: { template: '<div>dashboard</div>' } },
      { path: '/admin/posts', component: { template: '<div/>' } },
    ],
  })
  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()
  })
})