import { describe, it, expect, vi, beforeEach } from 'vitest' import { createRouter, createWebHistory } from 'vue-router' // Use plain objects — the guard only reads `.value`, so full Vue refs are unnecessary const { isAuthReadyMock, isUserLoggedInMock, isParentAuthenticatedMock } = vi.hoisted(() => ({ isAuthReadyMock: { value: true }, isUserLoggedInMock: { value: false }, isParentAuthenticatedMock: { value: false }, })) vi.mock('@/stores/auth', () => ({ isAuthReady: isAuthReadyMock, isUserLoggedIn: isUserLoggedInMock, isParentAuthenticated: isParentAuthenticatedMock, })) // Import router AFTER mocks are in place const { default: router } = await import('../index') // Helper — navigate and return the resolved path async function navigate(path: string): Promise { await router.push(path) return router.currentRoute.value.path } describe('router auth guard', () => { beforeEach(async () => { isAuthReadyMock.value = true // Park at /auth/reset-password as a neutral starting point: // - it is always reachable when logged out // - it doesn't match any route a test assertion lands on isUserLoggedInMock.value = false isParentAuthenticatedMock.value = false await router.push('/auth/reset-password') }) // ── Redirect logged-in users away from /auth ────────────────────────────── it('redirects logged-in parent user from /auth to /parent', async () => { isUserLoggedInMock.value = true isParentAuthenticatedMock.value = true const path = await navigate('/auth') expect(path).toBe('/parent') }) it('redirects logged-in child user from /auth to /child', async () => { isUserLoggedInMock.value = true isParentAuthenticatedMock.value = false const path = await navigate('/auth') expect(path).toBe('/child') }) it('redirects logged-in parent user from /auth/login to /parent', async () => { isUserLoggedInMock.value = true isParentAuthenticatedMock.value = true const path = await navigate('/auth/login') expect(path).toBe('/parent') }) it('redirects logged-in child user from /auth/signup to /child', async () => { isUserLoggedInMock.value = true isParentAuthenticatedMock.value = false const path = await navigate('/auth/signup') expect(path).toBe('/child') }) it('redirects logged-in child user from /auth/forgot-password to /child', async () => { isUserLoggedInMock.value = true isParentAuthenticatedMock.value = false const path = await navigate('/auth/forgot-password') expect(path).toBe('/child') }) // ── Unauthenticated users may access /auth ──────────────────────────────── it('allows unauthenticated user to access /auth', async () => { isUserLoggedInMock.value = false const path = await navigate('/auth') expect(path).toBe('/auth') }) it('allows unauthenticated user to access /auth/login', async () => { isUserLoggedInMock.value = false const path = await navigate('/auth/login') expect(path).toBe('/auth/login') }) // ── Unauthenticated users are redirected to /auth from protected routes ─── it('redirects unauthenticated user from /parent to /auth', async () => { isUserLoggedInMock.value = false const path = await navigate('/parent') expect(path).toBe('/auth') }) it('redirects unauthenticated user from /child to /auth', async () => { isUserLoggedInMock.value = false const path = await navigate('/child') expect(path).toBe('/auth') }) // ── Authenticated users are routed to the correct section ───────────────── it('allows parent-authenticated user to access /parent', async () => { isUserLoggedInMock.value = true isParentAuthenticatedMock.value = true const path = await navigate('/parent') expect(path).toBe('/parent') }) it('allows child user to access /child', async () => { isUserLoggedInMock.value = true isParentAuthenticatedMock.value = false const path = await navigate('/child') expect(path).toBe('/child') }) it('redirects child user away from /parent to /child', async () => { isUserLoggedInMock.value = true isParentAuthenticatedMock.value = false const path = await navigate('/parent') expect(path).toBe('/child') }) it('redirects parent user away from /child to /parent', async () => { isUserLoggedInMock.value = true isParentAuthenticatedMock.value = true const path = await navigate('/child') expect(path).toBe('/parent') }) // ── ParentPinSetup is always accessible ─────────────────────────────────── it('allows access to /parent/pin-setup regardless of auth state', async () => { isUserLoggedInMock.value = false const path = await navigate('/parent/pin-setup') expect(path).toBe('/parent/pin-setup') }) })