import { describe, it, expect, beforeEach, vi } from 'vitest'; import { mockNuxtImport } from '@nuxt/test-utils/runtime'; import type { RouteLocationNormalized } from 'vue-router'; /** * Tests for auth middleware * Based on specs from private/specs.md: * * Scenario: Access protected page without auth * Given I am not logged in * When I try to access "/dashboard" * Then I should be redirected to "/login" */ // Create mocks at module level to avoid hoisting issues const mockState = { isAuthenticated: false, navigateToSpy: vi.fn(), }; // Mock useAuth mockNuxtImport('useAuth', () => { return () => ({ isAuthenticated: { get value() { return mockState.isAuthenticated; }, }, }); }); // Mock navigateTo mockNuxtImport('navigateTo', () => { return (path: string) => mockState.navigateToSpy(path); }); describe('auth middleware', () => { beforeEach(async () => { // Reset state mockState.isAuthenticated = false; mockState.navigateToSpy.mockClear(); }); it('should redirect to /login when user is not authenticated', async () => { mockState.isAuthenticated = false; const { default: authMiddleware } = await import('../auth.global'); const to = { path: '/dashboard', fullPath: '/dashboard', } as RouteLocationNormalized; const from = { path: '/', fullPath: '/', } as RouteLocationNormalized; await authMiddleware(to, from); expect(mockState.navigateToSpy).toHaveBeenCalledWith({ path: '/login', query: { redirect: '/dashboard', }, }); }); it('should allow access when user is authenticated', async () => { mockState.isAuthenticated = true; const { default: authMiddleware } = await import('../auth.global'); const to = { path: '/dashboard', fullPath: '/dashboard', } as RouteLocationNormalized; const from = { path: '/login', fullPath: '/login', } as RouteLocationNormalized; const result = await authMiddleware(to, from); expect(mockState.navigateToSpy).not.toHaveBeenCalled(); expect(result).toBeUndefined(); // No redirect = allow access }); it('should not redirect if already on login page', async () => { mockState.isAuthenticated = false; const { default: authMiddleware } = await import('../auth.global'); const to = { path: '/login', fullPath: '/login', } as RouteLocationNormalized; const from = { path: '/dashboard', fullPath: '/dashboard', } as RouteLocationNormalized; const result = await authMiddleware(to, from); expect(mockState.navigateToSpy).not.toHaveBeenCalled(); expect(result).toBeUndefined(); }); it('should allow access to home page without authentication', async () => { mockState.isAuthenticated = false; const { default: authMiddleware } = await import('../auth.global'); const to = { path: '/', fullPath: '/', } as RouteLocationNormalized; const from = { path: '/somewhere', fullPath: '/somewhere', } as RouteLocationNormalized; const result = await authMiddleware(to, from); expect(mockState.navigateToSpy).not.toHaveBeenCalled(); expect(result).toBeUndefined(); }); it('should redirect to /login for any protected route', async () => { mockState.isAuthenticated = false; const { default: authMiddleware } = await import('../auth.global'); const to = { path: '/projects', fullPath: '/projects', } as RouteLocationNormalized; const from = { path: '/', fullPath: '/', } as RouteLocationNormalized; await authMiddleware(to, from); expect(mockState.navigateToSpy).toHaveBeenCalledWith({ path: '/login', query: { redirect: '/projects', }, }); }); });