import { describe, it, expect, vi, beforeEach } from 'vitest' const { redirectMock, verifyUserMock, headerGetMock, sessionSaveMock } = vi.hoisted(() => ({ redirectMock: vi.fn((path: string) => { throw new Error(`REDIRECT:${path}`) }), verifyUserMock: vi.fn(), headerGetMock: vi.fn(), sessionSaveMock: vi.fn(), })) vi.mock('next/navigation', () => ({ redirect: redirectMock })) vi.mock('next/headers', () => ({ cookies: vi.fn().mockResolvedValue({}), headers: vi.fn().mockResolvedValue({ get: headerGetMock }), })) vi.mock('iron-session', () => ({ getIronSession: vi.fn().mockResolvedValue({ userId: '', isDemo: false, save: sessionSaveMock, }), })) vi.mock('@/lib/session', () => ({ sessionOptions: { cookieName: 't', password: 't' } })) vi.mock('@/lib/auth', () => ({ verifyUser: verifyUserMock, registerUser: vi.fn(), })) vi.mock('@/lib/rate-limit', () => ({ checkRateLimit: vi.fn().mockReturnValue(true) })) import { loginAction } from '@/actions/auth' const IPHONE_UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) Mobile/15E148 Safari/604.1' const IPAD_UA = 'Mozilla/5.0 (iPad; CPU OS 17_4 like Mac OS X) Safari/604.1' const DESKTOP_UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4) Chrome/124.0.0.0 Safari/537.36' function fd(username: string, password: string) { const f = new FormData() f.set('username', username) f.set('password', password) return f } beforeEach(() => { redirectMock.mockClear() verifyUserMock.mockReset() headerGetMock.mockReset() sessionSaveMock.mockReset() }) describe('loginAction UA-redirect', () => { it('phone-UA + actief product → /m/products/[id]/solo', async () => { verifyUserMock.mockResolvedValue({ id: 'u1', is_demo: false, active_product_id: 'p1' }) headerGetMock.mockReturnValue(IPHONE_UA) await expect(loginAction(undefined, fd('alice', 'secret123'))).rejects.toThrow('REDIRECT:/m/products/p1/solo') }) it('phone-UA zonder actief product → /m/settings', async () => { verifyUserMock.mockResolvedValue({ id: 'u1', is_demo: false, active_product_id: null }) headerGetMock.mockReturnValue(IPHONE_UA) await expect(loginAction(undefined, fd('alice', 'secret123'))).rejects.toThrow('REDIRECT:/m/settings') }) it('tablet-UA (iPad) → /dashboard', async () => { verifyUserMock.mockResolvedValue({ id: 'u1', is_demo: false, active_product_id: 'p1' }) headerGetMock.mockReturnValue(IPAD_UA) await expect(loginAction(undefined, fd('alice', 'secret123'))).rejects.toThrow('REDIRECT:/dashboard') }) it('desktop-UA → /dashboard', async () => { verifyUserMock.mockResolvedValue({ id: 'u1', is_demo: false, active_product_id: 'p1' }) headerGetMock.mockReturnValue(DESKTOP_UA) await expect(loginAction(undefined, fd('alice', 'secret123'))).rejects.toThrow('REDIRECT:/dashboard') }) it('geen UA-header → /dashboard', async () => { verifyUserMock.mockResolvedValue({ id: 'u1', is_demo: false, active_product_id: 'p1' }) headerGetMock.mockReturnValue(null) await expect(loginAction(undefined, fd('alice', 'secret123'))).rejects.toThrow('REDIRECT:/dashboard') }) it('demo-user op phone volgt dezelfde routing', async () => { verifyUserMock.mockResolvedValue({ id: 'demo', is_demo: true, active_product_id: 'p1' }) headerGetMock.mockReturnValue(IPHONE_UA) await expect(loginAction(undefined, fd('demo', 'demo123pw'))).rejects.toThrow('REDIRECT:/m/products/p1/solo') }) })