Goal-Calibration/tests/Unit/Auth/Middleware/AuthMiddlewareTest.php

161 lines
5 KiB
PHP

<?php
namespace Tests\Unit\Auth\Middleware;
use App\Auth\AuthMiddleware;
use App\Auth\CreateSessionDto;
use App\User\UseCases\CreateUserDto;
use App\User\User;
use App\ValueObjects\EmailAddress;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Psr7\Factory\ServerRequestFactory;
use Slim\Psr7\Response;
use Tests\Fakes\FakeClock;
use Tests\Fakes\FakeSessionRepository;
use Tests\Fakes\FakeUserRepository;
class AuthMiddlewareTest extends TestCase
{
private FakeUserRepository $userRepo;
private FakeSessionRepository $sessionRepo;
private FakeClock $clock;
private AuthMiddleware $middleware;
private User $user;
public function setUp(): void
{
$this->userRepo = new FakeUserRepository();
$this->sessionRepo = new FakeSessionRepository();
$this->clock = new FakeClock(
new DateTimeImmutable('2025-01-01T12:00:00+00:00')
);
$this->user = $this->userRepo->create(new CreateUserDto(
email: new EmailAddress('test@test.com'),
passwordHash: '',
));
$this->middleware = new AuthMiddleware(
$this->sessionRepo,
$this->userRepo,
$this->clock,
);
}
private function makeApiRequest(
?string $cookieToken = null
): ServerRequestInterface {
$request = new ServerRequestFactory()
->createServerRequest('GET', 'http://localhost/api/texts');
if ($cookieToken !== null) {
$request = $request->withCookieParams([
'auth_token' => $cookieToken,
]);
}
return $request;
}
private function makeHtmlRequest(
?string $cookieToken = null
): ServerRequestInterface {
$request = new ServerRequestFactory()
->createServerRequest('GET', 'http://localhost/home')
->withHeader('Accept', 'text/html');
if ($cookieToken !== null) {
$request = $request->withCookieParams([
'auth_token' => $cookieToken,
]);
}
return $request;
}
private function makeHandler(): RequestHandlerInterface
{
return new class implements RequestHandlerInterface {
public ?ServerRequestInterface $capturedRequest = null;
public function handle(
ServerRequestInterface $request
): \Psr\Http\Message\ResponseInterface {
$this->capturedRequest = $request;
return new Response(200);
}
};
}
public function test_returns_401_json_when_cookie_missing(): void
{
$response = $this->middleware->process(
$this->makeApiRequest(),
$this->makeHandler(),
);
$this->assertEquals(401, $response->getStatusCode());
$this->assertStringContainsString(
'application/json',
$response->getHeaderLine('Content-Type')
);
}
public function test_returns_401_when_token_not_in_repo(): void
{
$response = $this->middleware->process(
$this->makeApiRequest('unknown-token'),
$this->makeHandler(),
);
$this->assertEquals(401, $response->getStatusCode());
}
public function test_returns_401_when_token_expired(): void
{
$this->sessionRepo->create(new CreateSessionDto(
token: 'expired-token',
userId: $this->user->getId(),
createdAt: new DateTimeImmutable('2024-12-01T00:00:00+00:00'),
expiresAt: new DateTimeImmutable('2024-12-08T00:00:00+00:00'),
));
$response = $this->middleware->process(
$this->makeApiRequest('expired-token'),
$this->makeHandler(),
);
$this->assertEquals(401, $response->getStatusCode());
}
public function test_attaches_user_to_request_on_success(): void
{
$this->sessionRepo->create(new CreateSessionDto(
token: 'valid-token',
userId: $this->user->getId(),
createdAt: new DateTimeImmutable('2025-01-01T00:00:00+00:00'),
expiresAt: new DateTimeImmutable('2025-01-08T00:00:00+00:00'),
));
$handler = $this->makeHandler();
$this->middleware->process(
$this->makeApiRequest('valid-token'),
$handler,
);
$attached = $handler->capturedRequest->getAttribute('user');
$this->assertInstanceOf(User::class, $attached);
$this->assertEquals(
'test@test.com',
$attached->getEmail()->value()
);
}
public function test_redirects_to_login_when_html_unauthenticated(): void
{
$response = $this->middleware->process(
$this->makeHtmlRequest(),
$this->makeHandler(),
);
$this->assertEquals(302, $response->getStatusCode());
$this->assertEquals('/login', $response->getHeaderLine('Location'));
}
}