environment = new Environment([ EnvKey::APP_ENV->value => 'development' ]); $this->service = new CookieService($this->environment); }); describe('create()', function () { it('creates a standard cookie', function () { $cookie = $this->service->create( name: 'session', value: 'abc123' ); expect($cookie->name)->toBe('session'); expect($cookie->value)->toBe('abc123'); expect($cookie->partitioned)->toBeFalse(); expect($cookie->sameSite)->toBe(SameSite::Lax); expect($cookie->httpOnly)->toBeTrue(); }); it('sets secure flag in production', function () { $prodEnv = new Environment([ EnvKey::APP_ENV->value => 'production' ]); $service = new CookieService($prodEnv); $cookie = $service->create('test', 'value'); expect($cookie->secure)->toBeTrue(); }); it('does not set secure flag in development by default', function () { $cookie = $this->service->create('test', 'value'); expect($cookie->secure)->toBeFalse(); }); it('respects explicit secure parameter', function () { $cookie = $this->service->create( name: 'test', value: 'value', secure: true ); expect($cookie->secure)->toBeTrue(); }); it('sets expiration with maxAge', function () { $cookie = $this->service->create( name: 'test', value: 'value', maxAge: Duration::fromHours(1) ); expect($cookie->expires)->toBeInt(); expect($cookie->expires)->toBeGreaterThan(time()); }); }); describe('createPartitioned()', function () { it('creates CHIPS partitioned cookie', function () { $cookie = $this->service->createPartitioned( name: 'widget', value: 'state123' ); expect($cookie->partitioned)->toBeTrue(); expect($cookie->secure)->toBeTrue(); expect($cookie->sameSite)->toBe(SameSite::None); expect($cookie->httpOnly)->toBeTrue(); }); it('creates partitioned cookie with custom duration', function () { $cookie = $this->service->createPartitioned( name: 'analytics', value: 'user123', maxAge: Duration::fromDays(365) ); expect($cookie->expires)->toBeInt(); expect($cookie->partitioned)->toBeTrue(); }); it('allows httpOnly=false for JavaScript access', function () { $cookie = $this->service->createPartitioned( name: 'js_widget', value: 'data', httpOnly: false ); expect($cookie->httpOnly)->toBeFalse(); expect($cookie->partitioned)->toBeTrue(); }); }); describe('createSessionCookie()', function () { it('creates session cookie without expiration', function () { $cookie = $this->service->createSessionCookie( name: 'session_id', value: 'xyz789' ); expect($cookie->expires)->toBeNull(); expect($cookie->httpOnly)->toBeTrue(); expect($cookie->sameSite)->toBe(SameSite::Lax); }); it('allows custom SameSite', function () { $cookie = $this->service->createSessionCookie( name: 'session', value: 'value', sameSite: SameSite::Strict ); expect($cookie->sameSite)->toBe(SameSite::Strict); }); }); describe('createPartitionedSession()', function () { it('creates partitioned session cookie', function () { $cookie = $this->service->createPartitionedSession( name: 'widget_session', value: 'session123' ); expect($cookie->expires)->toBeNull(); expect($cookie->partitioned)->toBeTrue(); expect($cookie->secure)->toBeTrue(); expect($cookie->sameSite)->toBe(SameSite::None); }); }); describe('createRememberMeCookie()', function () { it('creates remember-me cookie with 30 day default', function () { $cookie = $this->service->createRememberMeCookie('token123'); expect($cookie->name)->toBe('remember_me'); expect($cookie->value)->toBe('token123'); expect($cookie->httpOnly)->toBeTrue(); expect($cookie->sameSite)->toBe(SameSite::Strict); expect($cookie->expires)->toBeInt(); }); it('allows custom duration', function () { $cookie = $this->service->createRememberMeCookie( value: 'token', maxAge: Duration::fromDays(7) ); expect($cookie->expires)->toBeInt(); }); }); describe('createAnalyticsCookie()', function () { it('creates partitioned analytics cookie', function () { $cookie = $this->service->createAnalyticsCookie('user123'); expect($cookie->name)->toBe('_analytics'); expect($cookie->value)->toBe('user123'); expect($cookie->partitioned)->toBeTrue(); expect($cookie->httpOnly)->toBeFalse(); // JS access needed }); }); describe('createWidgetStateCookie()', function () { it('creates partitioned widget state cookie', function () { $cookie = $this->service->createWidgetStateCookie( widgetId: 'chat', state: '{"minimized":false}' ); expect($cookie->name)->toBe('widget_chat'); expect($cookie->value)->toBe('{"minimized":false}'); expect($cookie->partitioned)->toBeTrue(); expect($cookie->httpOnly)->toBeTrue(); }); }); describe('delete()', function () { it('creates deletion cookie with past expiration', function () { $cookie = $this->service->delete('session'); expect($cookie->name)->toBe('session'); expect($cookie->value)->toBe(''); expect($cookie->expires)->toBeLessThan(time()); }); it('respects custom path', function () { $cookie = $this->service->delete('session', '/admin'); expect($cookie->path)->toBe('/admin'); }); }); describe('validateSize()', function () { it('validates cookie within size limit', function () { $cookie = new Cookie( name: 'test', value: 'small_value' ); expect($this->service->validateSize($cookie))->toBeTrue(); }); it('rejects oversized cookie', function () { $cookie = new Cookie( name: 'huge', value: str_repeat('x', 5000) // Exceeds 4KB limit ); expect($this->service->validateSize($cookie))->toBeFalse(); }); }); describe('isValidName()', function () { it('validates correct cookie names', function () { expect($this->service->isValidName('session_id'))->toBeTrue(); expect($this->service->isValidName('user-token'))->toBeTrue(); expect($this->service->isValidName('TOKEN123'))->toBeTrue(); }); it('rejects invalid cookie names', function () { expect($this->service->isValidName('session id'))->toBeFalse(); // space expect($this->service->isValidName('user@token'))->toBeFalse(); // @ expect($this->service->isValidName('token=123'))->toBeFalse(); // = expect($this->service->isValidName('token;'))->toBeFalse(); // ; }); }); });