/** * SessionGateway tests * * TDD: All tests mock cookies() from 'next/headers' and global.fetch */ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { SessionGateway } from './SessionGateway'; import type { AuthSessionDTO } from '../types/generated/AuthSessionDTO'; // Mock next/headers vi.mock('next/headers', () => ({ cookies: vi.fn(), })); // Mock global.fetch const mockFetch = vi.fn(); global.fetch = mockFetch; describe('SessionGateway', () => { let gateway: SessionGateway; let mockCookies: ReturnType; beforeEach(async () => { vi.clearAllMocks(); const nextHeaders = await import('next/headers'); mockCookies = vi.mocked(nextHeaders.cookies); gateway = new SessionGateway(); }); describe('getSession()', () => { it('should return null when no cookies are present', async () => { // Arrange mockCookies.mockReturnValue({ toString: () => '', } as any); // Act const result = await gateway.getSession(); // Assert expect(result).toBeNull(); expect(mockFetch).not.toHaveBeenCalled(); }); it('should return session object when valid gp_session cookie exists', async () => { // Arrange const mockSession: AuthSessionDTO = { token: 'valid-token', user: { userId: 'user-123', email: 'test@example.com', displayName: 'Test User', role: 'driver', }, }; mockCookies.mockReturnValue({ toString: () => 'gp_session=valid-token; other=value', } as any); mockFetch.mockResolvedValueOnce({ ok: true, status: 200, json: async () => mockSession, } as Response); // Act const result = await gateway.getSession(); // Assert expect(result).toEqual(mockSession); expect(mockFetch).toHaveBeenCalledWith('http://localhost:3101/auth/session', { headers: { cookie: 'gp_session=valid-token; other=value' }, cache: 'no-store', credentials: 'include', }); }); it('should return null when session is invalid or expired', async () => { // Arrange mockCookies.mockReturnValue({ toString: () => 'gp_session=expired-token', } as any); mockFetch.mockResolvedValueOnce({ ok: false, status: 401, statusText: 'Unauthorized', } as Response); // Act const result = await gateway.getSession(); // Assert expect(result).toBeNull(); expect(mockFetch).toHaveBeenCalled(); }); it('should return null on non-2xx response', async () => { // Arrange mockCookies.mockReturnValue({ toString: () => 'gp_session=some-token', } as any); mockFetch.mockResolvedValueOnce({ ok: false, status: 500, statusText: 'Internal Server Error', } as Response); // Act const result = await gateway.getSession(); // Assert expect(result).toBeNull(); expect(mockFetch).toHaveBeenCalled(); }); it('should return null on network error', async () => { // Arrange mockCookies.mockReturnValue({ toString: () => 'gp_session=some-token', } as any); mockFetch.mockRejectedValueOnce(new Error('Network error')); // Act const result = await gateway.getSession(); // Assert expect(result).toBeNull(); expect(mockFetch).toHaveBeenCalled(); }); it('should return null when fetch throws any error', async () => { // Arrange mockCookies.mockReturnValue({ toString: () => 'gp_session=some-token', } as any); mockFetch.mockRejectedValueOnce(new Error('Connection timeout')); // Act const result = await gateway.getSession(); // Assert expect(result).toBeNull(); }); }); });