diff --git a/backend/tests/Unit/Controllers/AuthControllerTest.php b/backend/tests/Unit/Controllers/AuthControllerTest.php new file mode 100644 index 0000000..9bba649 --- /dev/null +++ b/backend/tests/Unit/Controllers/AuthControllerTest.php @@ -0,0 +1,170 @@ +userRepo = new FakeUserRepository(); + $this->sessionRepo = new FakeSessionRepository(); + $this->hasher = new FakePasswordHasher(); + $this->tokenGenerator = new FakeTokenGenerator([ + 'session-token-1', + 'session-token-2', + ]); + $this->clock = new FakeClock( + new DateTimeImmutable('2026-05-16 12:00:00'), + ); + + $authenticateUser = new AuthenticateUser( + $this->userRepo, + $this->hasher, + ); + $createSession = new CreateSession( + $this->sessionRepo, + $this->tokenGenerator, + $this->clock, + ); + $logout = new Logout($this->sessionRepo); + + $this->controller = new AuthController( + $authenticateUser, + $createSession, + $logout, + ); + + $this->user = $this->userRepo->create(new CreateUserDto( + email: new EmailAddress('user@example.com'), + passwordHash: $this->hasher->hash('correct-password'), + )); + } + + public function testLoginReturnsUserAndSetsCookie(): void + { + $request = $this->jsonRequest('POST', '/login', [ + 'email' => 'user@example.com', + 'password' => 'correct-password', + ]); + + $response = $this->controller->login($request, new Response()); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertStringContainsString( + 'user@example.com', + (string) $response->getBody(), + ); + + $cookieHeader = $response->getHeaderLine('Set-Cookie'); + $this->assertStringContainsString( + AuthMiddleware::COOKIE_NAME.'=session-token-1', + $cookieHeader, + ); + $this->assertStringContainsString('HttpOnly', $cookieHeader); + } + + public function testLoginReturns400ForMissingEmail(): void + { + $request = $this->jsonRequest('POST', '/login', [ + 'password' => 'correct-password', + ]); + + $response = $this->controller->login($request, new Response()); + + $this->assertSame(400, $response->getStatusCode()); + } + + public function testLoginReturns401ForInvalidCredentials(): void + { + $request = $this->jsonRequest('POST', '/login', [ + 'email' => 'user@example.com', + 'password' => 'wrong-password', + ]); + + $response = $this->controller->login($request, new Response()); + + $this->assertSame(401, $response->getStatusCode()); + } + + public function testLogoutClearsCookieAndReturns204(): void + { + $request = $this->createRequest() + ->withCookieParams([ + AuthMiddleware::COOKIE_NAME => 'session-token-1', + ]); + + $response = $this->controller->logout($request, new Response()); + + $this->assertSame(204, $response->getStatusCode()); + + $cookieHeader = $response->getHeaderLine('Set-Cookie'); + $this->assertStringContainsString( + AuthMiddleware::COOKIE_NAME.'=', + $cookieHeader, + ); + } + + public function testMeReturnsUserFromAttribute(): void + { + $request = $this->createRequest() + ->withAttribute('user', $this->user); + + $response = $this->controller->me($request, new Response()); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertStringContainsString( + 'user@example.com', + (string) $response->getBody(), + ); + } + + private function jsonRequest( + string $method, + string $path, + array $body, + ): ServerRequestInterface { + $request = $this->createRequest($method, $path) + ->withHeader('Content-Type', 'application/json'); + $request->getBody()->write(json_encode($body)); + $request->getBody()->rewind(); + + return $request; + } + + private function createRequest( + string $method = 'POST', + string $path = '/', + ): ServerRequestInterface { + $factory = new ServerRequestFactory(); + + return $factory->createServerRequest($method, $path); + } +}