diff --git a/backend/tests/Unit/Auth/Middleware/AuthMiddlewareTest.php b/backend/tests/Unit/Auth/Middleware/AuthMiddlewareTest.php new file mode 100644 index 0000000..7f844c9 --- /dev/null +++ b/backend/tests/Unit/Auth/Middleware/AuthMiddlewareTest.php @@ -0,0 +1,142 @@ +now = new DateTimeImmutable( + '2026-05-06T12:00:00', + new DateTimeZone('UTC') + ); + $this->sessionRepo = new FakeSessionRepository; + $this->clock = new FakeClock($this->now); + $this->middleware = new AuthMiddleware( + $this->sessionRepo, + $this->clock, + ); + } + + private function makeRequest(?string $token): Request + { + $request = Request::create('/api/anything', 'POST'); + if ($token !== null) { + $request->cookies->set('auth_token', $token); + } + + return $request; + } + + private function nextThatRecords(?Request &$captured): Closure + { + return function (Request $request) use (&$captured) { + $captured = $request; + + return new JsonResponse(['ok' => true], 200); + }; + } + + private function makeUser(int $id = 7): User + { + return new User( + id: $id, + email: new EmailAddress('user@example.com'), + passwordHash: 'hashed:irrelevant', + isAdmin: false, + ); + } + + public function test_missing_cookie_returns_unauthorized_json(): void + { + $captured = null; + $response = $this->middleware->handle( + $this->makeRequest(null), + $this->nextThatRecords($captured), + ); + + $this->assertSame(401, $response->getStatusCode()); + $this->assertSame( + ['error' => 'unauthenticated'], + json_decode($response->getContent(), true), + ); + $this->assertNull($captured); + } + + public function test_unknown_token_returns_unauthorized(): void + { + $captured = null; + $response = $this->middleware->handle( + $this->makeRequest('does-not-exist'), + $this->nextThatRecords($captured), + ); + + $this->assertSame(401, $response->getStatusCode()); + $this->assertNull($captured); + } + + public function test_expired_session_returns_unauthorized_and_is_deleted(): void + { + $this->sessionRepo->create(new CreateSessionDto( + token: 'expired-token', + user: $this->makeUser(), + createdAt: $this->now->modify('-8 days'), + expiresAt: $this->now->modify('-1 day'), + )); + + $captured = null; + $response = $this->middleware->handle( + $this->makeRequest('expired-token'), + $this->nextThatRecords($captured), + ); + + $this->assertSame(401, $response->getStatusCode()); + $this->assertNull($captured); + $this->assertNull( + $this->sessionRepo->findByToken('expired-token') + ); + } + + public function test_valid_session_attaches_user_and_calls_next(): void + { + $this->sessionRepo->create(new CreateSessionDto( + token: 'valid-token', + user: $this->makeUser(id: 7), + createdAt: $this->now, + expiresAt: $this->now->modify('+7 days'), + )); + + $captured = null; + $response = $this->middleware->handle( + $this->makeRequest('valid-token'), + $this->nextThatRecords($captured), + ); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertNotNull($captured); + $attachedUser = $captured->attributes->get('user'); + $this->assertInstanceOf(User::class, $attachedUser); + $this->assertSame(7, $attachedUser->getId()); + } +}