115 lines
3.3 KiB
TypeScript
115 lines
3.3 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { computed } from 'vue'
|
|
import { createPinia, setActivePinia } from 'pinia'
|
|
import { useAuthStore } from '../app/stores/auth'
|
|
|
|
async function loadMiddleware() {
|
|
vi.resetModules()
|
|
vi.stubGlobal('defineNuxtRouteMiddleware', (setup: unknown) => setup)
|
|
|
|
return (await import('../app/middleware/auth.global')).default
|
|
}
|
|
|
|
function createAuthClient(overrides: Partial<ReturnType<typeof buildAuthClient>> = {}) {
|
|
return {
|
|
...buildAuthClient(),
|
|
...overrides
|
|
}
|
|
}
|
|
|
|
function buildAuthClient() {
|
|
return {
|
|
isEnabled: true,
|
|
isAuthenticated: computed(() => false),
|
|
ensureInitialized: vi.fn().mockResolvedValue(undefined),
|
|
login: vi.fn().mockResolvedValue(undefined)
|
|
}
|
|
}
|
|
|
|
describe('auth middleware', () => {
|
|
beforeEach(() => {
|
|
setActivePinia(createPinia())
|
|
vi.restoreAllMocks()
|
|
vi.unstubAllGlobals()
|
|
vi.stubGlobal('useAuthStore', useAuthStore)
|
|
})
|
|
|
|
it('skips public routes and disabled auth', async () => {
|
|
const publicAuth = createAuthClient()
|
|
vi.stubGlobal('useAuth', () => publicAuth)
|
|
|
|
const middleware = await loadMiddleware()
|
|
|
|
await expect(middleware({ meta: { public: true } })).resolves.toBeUndefined()
|
|
expect(publicAuth.ensureInitialized).not.toHaveBeenCalled()
|
|
|
|
const disabledAuth = createAuthClient({ isEnabled: false })
|
|
vi.stubGlobal('useAuth', () => disabledAuth)
|
|
|
|
await expect(middleware({ meta: { requiresAuth: true } })).resolves.toBeUndefined()
|
|
expect(disabledAuth.ensureInitialized).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('requests login for unauthenticated protected routes', async () => {
|
|
const auth = createAuthClient({
|
|
isAuthenticated: computed(() => false)
|
|
})
|
|
vi.stubGlobal('useAuth', () => auth)
|
|
|
|
const middleware = await loadMiddleware()
|
|
|
|
await expect(middleware({ meta: { requiresAuth: true } })).resolves.toBeUndefined()
|
|
|
|
expect(auth.ensureInitialized).toHaveBeenCalledOnce()
|
|
expect(auth.login).toHaveBeenCalledOnce()
|
|
})
|
|
|
|
it('allows authenticated users with a matching role', async () => {
|
|
const authStore = useAuthStore()
|
|
authStore.setUser({
|
|
id: 'user-1',
|
|
roles: ['ADMIN']
|
|
})
|
|
|
|
const auth = createAuthClient({
|
|
isAuthenticated: computed(() => true)
|
|
})
|
|
vi.stubGlobal('useAuth', () => auth)
|
|
|
|
const middleware = await loadMiddleware()
|
|
|
|
await expect(middleware({ meta: { roles: ['ADMIN'] } })).resolves.toBeUndefined()
|
|
|
|
expect(auth.ensureInitialized).toHaveBeenCalledOnce()
|
|
expect(auth.login).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('throws a 403 error for authenticated users without a required role', async () => {
|
|
const authStore = useAuthStore()
|
|
authStore.setUser({
|
|
id: 'user-2',
|
|
roles: ['USER']
|
|
})
|
|
|
|
const createErrorMock = vi.fn((error: { statusCode: number; statusMessage: string }) => error)
|
|
vi.stubGlobal('createError', createErrorMock)
|
|
|
|
const auth = createAuthClient({
|
|
isAuthenticated: computed(() => true)
|
|
})
|
|
vi.stubGlobal('useAuth', () => auth)
|
|
|
|
const middleware = await loadMiddleware()
|
|
|
|
await expect(middleware({ meta: { roles: ['ADMIN'] } })).rejects.toMatchObject({
|
|
statusCode: 403,
|
|
statusMessage: 'Forbidden'
|
|
})
|
|
|
|
expect(createErrorMock).toHaveBeenCalledWith({
|
|
statusCode: 403,
|
|
statusMessage: 'Forbidden'
|
|
})
|
|
})
|
|
})
|