Files
nuxt4/tests/auth.plugin.spec.ts
2026-05-03 07:26:12 +00:00

153 lines
4.1 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
import { createPinia, setActivePinia } from 'pinia'
import { useAuthStore, type AuthUser } from '../app/stores/auth'
type AuthPlugin = typeof import('../app/plugins/auth').default
function createRuntimeConfig(authMode: string | undefined = undefined) {
return {
public: {
authMode,
authLoginUrl: '/login',
authLogoutUrl: '/logout',
authUserinfoUrl: '/api/auth/me'
}
}
}
async function loadPlugin() {
vi.resetModules()
vi.stubGlobal('defineNuxtPlugin', (setup: AuthPlugin) => setup)
return (await import('../app/plugins/auth')).default
}
describe('auth plugin', () => {
beforeEach(() => {
setActivePinia(createPinia())
vi.restoreAllMocks()
vi.unstubAllGlobals()
})
it('initializes a disabled auth client and keeps auth turned off', async () => {
vi.stubGlobal('useRuntimeConfig', () => createRuntimeConfig())
const plugin = await loadPlugin()
const { provide } = plugin()
const auth = provide.auth
expect(auth.mode).toBe('disabled')
expect(auth.isEnabled).toBe(false)
await auth.ensureInitialized()
const store = useAuthStore()
expect(auth.isReady.value).toBe(true)
expect(auth.isAuthenticated.value).toBe(false)
expect(store.isInitialized).toBe(true)
expect(store.user).toBeNull()
})
it('uses a mock user in mock mode and supports login and logout locally', async () => {
vi.stubGlobal('useRuntimeConfig', () => createRuntimeConfig('mock'))
const plugin = await loadPlugin()
const { provide } = plugin()
const auth = provide.auth
await auth.ensureInitialized()
const store = useAuthStore()
expect(auth.mode).toBe('mock')
expect(auth.isEnabled).toBe(true)
expect(auth.isAuthenticated.value).toBe(true)
expect(store.user).toMatchObject({
id: 'mock-user',
email: 'mock@example.com',
roles: ['USER']
})
auth.logout()
expect(store.user).toBeNull()
auth.login()
expect(store.user).toMatchObject({
id: 'mock-user',
email: 'mock@example.com'
})
})
it('loads the current user from the userinfo endpoint in userinfo mode', async () => {
const fetchMock = vi.fn().mockResolvedValue({
id: 'user-1',
email: 'john@example.com',
roles: ['USER']
} satisfies AuthUser)
vi.stubGlobal('useRuntimeConfig', () => createRuntimeConfig('userinfo'))
vi.stubGlobal('$fetch', fetchMock)
const plugin = await loadPlugin()
const { provide } = plugin()
const auth = provide.auth
await auth.ensureInitialized()
const store = useAuthStore()
expect(fetchMock).toHaveBeenCalledWith('/api/auth/me', {
credentials: 'include'
})
expect(auth.isAuthenticated.value).toBe(true)
expect(store.user).toMatchObject({
id: 'user-1',
email: 'john@example.com'
})
})
it('falls back to an anonymous session when userinfo loading fails', async () => {
const fetchMock = vi.fn().mockRejectedValue(new Error('network error'))
vi.stubGlobal('useRuntimeConfig', () => createRuntimeConfig('userinfo'))
vi.stubGlobal('$fetch', fetchMock)
const plugin = await loadPlugin()
const { provide } = plugin()
const auth = provide.auth
await auth.ensureInitialized()
const store = useAuthStore()
expect(auth.isReady.value).toBe(true)
expect(auth.isAuthenticated.value).toBe(false)
expect(store.isInitialized).toBe(true)
expect(store.user).toBeNull()
})
it('redirects login and logout in userinfo mode', async () => {
vi.stubGlobal('useRuntimeConfig', () => createRuntimeConfig('userinfo'))
vi.stubGlobal('$fetch', vi.fn().mockResolvedValue(null))
vi.stubGlobal('window', {
location: {
href: ''
}
})
const plugin = await loadPlugin()
const { provide } = plugin()
const auth = provide.auth
auth.login()
expect(window.location.href).toBe('/login')
const store = useAuthStore()
store.setUser({
id: 'user-2',
roles: ['USER']
})
auth.logout()
expect(window.location.href).toBe('/logout')
expect(store.user).toBeNull()
})
})