293 lines
9.2 KiB
PHP
293 lines
9.2 KiB
PHP
<?php
|
|
|
|
namespace Tests\e2e\Controllers;
|
|
|
|
use App\Auth\AuthController;
|
|
use App\Auth\CreateSessionDto;
|
|
use App\Auth\UseCases\CreateSession;
|
|
use App\User\UseCases\AuthenticateUser;
|
|
use App\User\UseCases\CreateUser;
|
|
use App\User\UseCases\CreateUserRequest;
|
|
use App\User\User;
|
|
use App\ValueObjects\EmailAddress;
|
|
use DateTimeImmutable;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use Slim\Psr7\Factory\ServerRequestFactory;
|
|
use Slim\Psr7\Factory\StreamFactory;
|
|
use Slim\Psr7\Response;
|
|
use Tests\Fakes\FakeClock;
|
|
use Tests\Fakes\FakePasswordHasher;
|
|
use Tests\Fakes\FakeSessionRepository;
|
|
use Tests\Fakes\FakeTokenGenerator;
|
|
use Tests\Fakes\FakeUserRepository;
|
|
|
|
class AuthControllerTest extends TestCase
|
|
{
|
|
private FakeUserRepository $userRepo;
|
|
private FakeSessionRepository $sessionRepo;
|
|
private FakeTokenGenerator $tokenGenerator;
|
|
private FakeClock $clock;
|
|
private FakePasswordHasher $passwordHasher;
|
|
private CreateUser $createUser;
|
|
private AuthenticateUser $authenticateUser;
|
|
private CreateSession $createSession;
|
|
private AuthController $controller;
|
|
|
|
public function setUp(): void
|
|
{
|
|
$this->userRepo = new FakeUserRepository();
|
|
$this->sessionRepo = new FakeSessionRepository();
|
|
$this->tokenGenerator = new FakeTokenGenerator(
|
|
['session-token-xyz']
|
|
);
|
|
$this->clock = new FakeClock(
|
|
new DateTimeImmutable('2025-01-01T12:00:00+00:00')
|
|
);
|
|
$this->passwordHasher = new FakePasswordHasher();
|
|
|
|
$this->createUser = new CreateUser(
|
|
$this->userRepo,
|
|
$this->passwordHasher,
|
|
);
|
|
$this->authenticateUser = new AuthenticateUser(
|
|
$this->userRepo,
|
|
$this->passwordHasher,
|
|
);
|
|
$this->createSession = new CreateSession(
|
|
$this->sessionRepo,
|
|
$this->tokenGenerator,
|
|
$this->clock,
|
|
);
|
|
|
|
$this->createUser->execute(new CreateUserRequest(
|
|
email: 'existing@test.com',
|
|
password: 'password1',
|
|
));
|
|
|
|
$this->controller = new AuthController();
|
|
}
|
|
|
|
private function makeJsonRequest(
|
|
string $method,
|
|
string $path,
|
|
array $data,
|
|
): ServerRequestInterface {
|
|
$body = new StreamFactory()->createStream(json_encode($data));
|
|
return new ServerRequestFactory()
|
|
->createServerRequest($method, 'http://localhost' . $path)
|
|
->withHeader('Content-Type', 'application/json')
|
|
->withBody($body);
|
|
}
|
|
|
|
public function test_login_returns_200_and_user(): void
|
|
{
|
|
$response = $this->controller->login(
|
|
$this->makeJsonRequest('POST', '/api/auth/login', [
|
|
'email' => 'existing@test.com',
|
|
'password' => 'password1',
|
|
]),
|
|
new Response(),
|
|
$this->authenticateUser,
|
|
$this->createSession,
|
|
);
|
|
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
$body = json_decode($response->getBody(), true);
|
|
$this->assertEquals(
|
|
'existing@test.com',
|
|
$body['user']['email']
|
|
);
|
|
}
|
|
|
|
public function test_login_sets_auth_cookie(): void
|
|
{
|
|
$response = $this->controller->login(
|
|
$this->makeJsonRequest('POST', '/api/auth/login', [
|
|
'email' => 'existing@test.com',
|
|
'password' => 'password1',
|
|
]),
|
|
new Response(),
|
|
$this->authenticateUser,
|
|
$this->createSession,
|
|
);
|
|
|
|
$setCookie = $response->getHeaderLine('Set-Cookie');
|
|
$this->assertStringContainsString(
|
|
'auth_token=session-token-xyz',
|
|
$setCookie
|
|
);
|
|
$this->assertStringContainsString('HttpOnly', $setCookie);
|
|
$this->assertStringContainsString('SameSite=Lax', $setCookie);
|
|
$this->assertStringContainsString('Path=/', $setCookie);
|
|
}
|
|
|
|
public function test_login_creates_session(): void
|
|
{
|
|
$this->controller->login(
|
|
$this->makeJsonRequest('POST', '/api/auth/login', [
|
|
'email' => 'existing@test.com',
|
|
'password' => 'password1',
|
|
]),
|
|
new Response(),
|
|
$this->authenticateUser,
|
|
$this->createSession,
|
|
);
|
|
|
|
$this->assertNotNull(
|
|
$this->sessionRepo->findByToken('session-token-xyz')
|
|
);
|
|
}
|
|
|
|
public function test_login_returns_401_on_wrong_password(): void
|
|
{
|
|
$response = $this->controller->login(
|
|
$this->makeJsonRequest('POST', '/api/auth/login', [
|
|
'email' => 'existing@test.com',
|
|
'password' => 'wrongpassword',
|
|
]),
|
|
new Response(),
|
|
$this->authenticateUser,
|
|
$this->createSession,
|
|
);
|
|
|
|
$this->assertEquals(401, $response->getStatusCode());
|
|
}
|
|
|
|
public function test_login_returns_400_when_email_missing(): void
|
|
{
|
|
$response = $this->controller->login(
|
|
$this->makeJsonRequest('POST', '/api/auth/login', [
|
|
'password' => 'password1',
|
|
]),
|
|
new Response(),
|
|
$this->authenticateUser,
|
|
$this->createSession,
|
|
);
|
|
|
|
$this->assertEquals(400, $response->getStatusCode());
|
|
}
|
|
|
|
public function test_register_creates_user_and_logs_in(): void
|
|
{
|
|
$response = $this->controller->register(
|
|
$this->makeJsonRequest('POST', '/api/auth/register', [
|
|
'email' => 'new@test.com',
|
|
'password' => 'password1',
|
|
]),
|
|
new Response(),
|
|
$this->createUser,
|
|
$this->createSession,
|
|
);
|
|
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
$body = json_decode($response->getBody(), true);
|
|
$this->assertEquals('new@test.com', $body['user']['email']);
|
|
$setCookie = $response->getHeaderLine('Set-Cookie');
|
|
$this->assertStringContainsString(
|
|
'auth_token=session-token-xyz',
|
|
$setCookie
|
|
);
|
|
}
|
|
|
|
public function test_register_returns_400_on_short_password(): void
|
|
{
|
|
$response = $this->controller->register(
|
|
$this->makeJsonRequest('POST', '/api/auth/register', [
|
|
'email' => 'new@test.com',
|
|
'password' => 'short',
|
|
]),
|
|
new Response(),
|
|
$this->createUser,
|
|
$this->createSession,
|
|
);
|
|
|
|
$this->assertEquals(400, $response->getStatusCode());
|
|
}
|
|
|
|
public function test_register_returns_400_on_duplicate_email(): void
|
|
{
|
|
$response = $this->controller->register(
|
|
$this->makeJsonRequest('POST', '/api/auth/register', [
|
|
'email' => 'existing@test.com',
|
|
'password' => 'password1',
|
|
]),
|
|
new Response(),
|
|
$this->createUser,
|
|
$this->createSession,
|
|
);
|
|
|
|
$this->assertEquals(400, $response->getStatusCode());
|
|
}
|
|
|
|
public function test_register_ignores_is_admin_in_body(): void
|
|
{
|
|
$this->controller->register(
|
|
$this->makeJsonRequest('POST', '/api/auth/register', [
|
|
'email' => 'sneaky@test.com',
|
|
'password' => 'password1',
|
|
'isAdmin' => true,
|
|
]),
|
|
new Response(),
|
|
$this->createUser,
|
|
$this->createSession,
|
|
);
|
|
|
|
$newUser = $this->userRepo->findByEmail(
|
|
new EmailAddress('sneaky@test.com')
|
|
);
|
|
$this->assertFalse($newUser->isAdmin());
|
|
}
|
|
|
|
public function test_logout_deletes_session_and_clears_cookie(): void
|
|
{
|
|
$this->sessionRepo->create(new CreateSessionDto(
|
|
token: 'existing-session',
|
|
userId: 0,
|
|
createdAt: new DateTimeImmutable('2025-01-01T00:00:00+00:00'),
|
|
expiresAt: new DateTimeImmutable('2025-01-08T00:00:00+00:00'),
|
|
));
|
|
|
|
$request = $this->makeJsonRequest(
|
|
'POST',
|
|
'/api/auth/logout',
|
|
[]
|
|
)->withCookieParams(['auth_token' => 'existing-session']);
|
|
|
|
$response = $this->controller->logout(
|
|
$request,
|
|
new Response(),
|
|
$this->sessionRepo,
|
|
);
|
|
|
|
$this->assertEquals(204, $response->getStatusCode());
|
|
$this->assertNull(
|
|
$this->sessionRepo->findByToken('existing-session')
|
|
);
|
|
$this->assertStringContainsString(
|
|
'auth_token=;',
|
|
$response->getHeaderLine('Set-Cookie')
|
|
);
|
|
}
|
|
|
|
public function test_me_returns_current_user(): void
|
|
{
|
|
$user = new User(
|
|
id: 5,
|
|
email: new EmailAddress('me@test.com'),
|
|
passwordHash: '',
|
|
isAdmin: true,
|
|
);
|
|
$request = new ServerRequestFactory()
|
|
->createServerRequest('GET', 'http://localhost/api/auth/me')
|
|
->withAttribute('user', $user);
|
|
|
|
$response = $this->controller->me($request, new Response());
|
|
|
|
$this->assertEquals(200, $response->getStatusCode());
|
|
$body = json_decode($response->getBody(), true);
|
|
$this->assertEquals(5, $body['user']['id']);
|
|
$this->assertEquals('me@test.com', $body['user']['email']);
|
|
$this->assertTrue($body['user']['isAdmin']);
|
|
}
|
|
}
|