import { readSessionTimeouts, sessionCookieName, sessionCookieOptions } from './session-cookie'; describe('session-cookie', () => { const originalNodeEnv = process.env['NODE_ENV']; const originalIdle = process.env['SESSION_IDLE_TIMEOUT_SECONDS']; const originalAbsolute = process.env['SESSION_ABSOLUTE_TIMEOUT_SECONDS']; afterEach(() => { restore('NODE_ENV', originalNodeEnv); restore('SESSION_IDLE_TIMEOUT_SECONDS', originalIdle); restore('SESSION_ABSOLUTE_TIMEOUT_SECONDS', originalAbsolute); }); describe('sessionCookieName', () => { it('uses the __Host- prefix in production', () => { process.env['NODE_ENV'] = 'production'; expect(sessionCookieName()).toBe('__Host-portal_session'); }); it('drops the __Host- prefix outside production (dev HTTP server)', () => { process.env['NODE_ENV'] = 'development'; expect(sessionCookieName()).toBe('portal_session'); }); }); describe('sessionCookieOptions', () => { it('sets Secure only in production', () => { process.env['NODE_ENV'] = 'production'; expect(sessionCookieOptions(1800).secure).toBe(true); process.env['NODE_ENV'] = 'development'; expect(sessionCookieOptions(1800).secure).toBe(false); }); it('converts the idle timeout into milliseconds', () => { expect(sessionCookieOptions(1800).maxAge).toBe(1_800_000); }); it('pins httpOnly, sameSite=lax, and path=/', () => { const opts = sessionCookieOptions(1800); expect(opts.httpOnly).toBe(true); expect(opts.sameSite).toBe('lax'); expect(opts.path).toBe('/'); }); }); describe('readSessionTimeouts', () => { it('returns the ADR-0010 defaults when env vars are unset', () => { delete process.env['SESSION_IDLE_TIMEOUT_SECONDS']; delete process.env['SESSION_ABSOLUTE_TIMEOUT_SECONDS']; expect(readSessionTimeouts()).toEqual({ idleSeconds: 1800, absoluteSeconds: 43200 }); }); it('parses positive integer overrides', () => { process.env['SESSION_IDLE_TIMEOUT_SECONDS'] = '900'; process.env['SESSION_ABSOLUTE_TIMEOUT_SECONDS'] = '7200'; expect(readSessionTimeouts()).toEqual({ idleSeconds: 900, absoluteSeconds: 7200 }); }); it('rejects non-numeric values', () => { process.env['SESSION_IDLE_TIMEOUT_SECONDS'] = 'half-an-hour'; expect(() => readSessionTimeouts()).toThrow(/must be a positive integer/); }); it('rejects zero and negative values', () => { process.env['SESSION_IDLE_TIMEOUT_SECONDS'] = '0'; expect(() => readSessionTimeouts()).toThrow(/must be a positive integer/); process.env['SESSION_IDLE_TIMEOUT_SECONDS'] = '-1'; expect(() => readSessionTimeouts()).toThrow(/must be a positive integer/); }); it('rejects fractional values', () => { process.env['SESSION_IDLE_TIMEOUT_SECONDS'] = '1800.5'; expect(() => readSessionTimeouts()).toThrow(/must be a positive integer/); }); }); }); function restore(name: string, value: string | undefined): void { if (value === undefined) { delete process.env[name]; } else { process.env[name] = value; } }