Files
Space-Theme/server/tests/Integration/AuthFlowTest.php
2026-02-03 09:18:15 +01:00

183 lines
6.7 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Integration;
use App\Shared\Clock\FixedTimeProvider;
use App\Tests\Support\TestAppFactory;
use App\Tests\Support\TestDatabase;
use PHPUnit\Framework\TestCase;
use Slim\Psr7\Factory\ServerRequestFactory;
final class AuthFlowTest extends TestCase
{
protected function setUp(): void
{
if (session_status() === PHP_SESSION_ACTIVE) {
$_SESSION = [];
session_destroy();
}
}
public function testRegistrationFlowCreatesUserAndLogsIn(): void
{
$pdo = TestDatabase::create();
TestDatabase::reset($pdo);
TestDatabase::seedMinimal($pdo);
$time = new FixedTimeProvider(new \DateTimeImmutable('2026-02-03 00:00:00'));
$app = TestAppFactory::create($pdo, $time);
$factory = new ServerRequestFactory();
$cookie = null;
$step1 = $this->jsonRequest($factory, 'POST', '/auth/register/step1', [
'race_key' => 'human',
], $cookie);
$response1 = $app->handle($step1);
self::assertSame(200, $response1->getStatusCode());
$cookie = $this->extractCookie($response1, $cookie);
$body1 = json_decode((string)$response1->getBody(), true);
self::assertSame('human', $body1['draft']['race_key']);
$step2 = $this->jsonRequest($factory, 'POST', '/auth/register/step2', [
'avatar_key' => 'avatar-01',
'title' => 'Pionier',
], $cookie);
$response2 = $app->handle($step2);
self::assertSame(200, $response2->getStatusCode());
$cookie = $this->extractCookie($response2, $cookie);
$body2 = json_decode((string)$response2->getBody(), true);
self::assertSame('avatar-01', $body2['draft']['avatar_key']);
$step3 = $this->jsonRequest($factory, 'POST', '/auth/register/step3', [
'username' => 'neo',
'email' => 'neo@example.test',
'password' => 'change-me',
], $cookie);
$response3 = $app->handle($step3);
self::assertSame(201, $response3->getStatusCode());
$cookie = $this->extractCookie($response3, $cookie);
$meRequest = $factory->createServerRequest('GET', '/me');
if ($cookie) {
$meRequest = $meRequest->withHeader('Cookie', $cookie);
}
$meResponse = $app->handle($meRequest);
self::assertSame(200, $meResponse->getStatusCode());
$meBody = json_decode((string)$meResponse->getBody(), true);
self::assertSame('neo', $meBody['user']['username']);
self::assertSame('human', $meBody['user']['race_key']);
$draftCheck = $this->jsonRequest($factory, 'POST', '/auth/register/step2', [
'avatar_key' => 'avatar-01',
'title' => 'Test',
], $cookie);
$draftResponse = $app->handle($draftCheck);
self::assertSame(409, $draftResponse->getStatusCode());
}
public function testLoginSuccessAndFailure(): void
{
$pdo = TestDatabase::create();
TestDatabase::reset($pdo);
TestDatabase::seedMinimal($pdo);
$time = new FixedTimeProvider(new \DateTimeImmutable('2026-02-03 00:00:00'));
$app = TestAppFactory::create($pdo, $time);
$factory = new ServerRequestFactory();
$badLogin = $this->jsonRequest($factory, 'POST', '/auth/login', [
'username_or_email' => 'tester',
'password' => 'wrong-pass',
]);
$badResponse = $app->handle($badLogin);
self::assertSame(401, $badResponse->getStatusCode());
$goodLogin = $this->jsonRequest($factory, 'POST', '/auth/login', [
'username_or_email' => 'tester',
'password' => 'change-me',
]);
$goodResponse = $app->handle($goodLogin);
self::assertSame(200, $goodResponse->getStatusCode());
$cookie = $this->extractCookie($goodResponse, null);
$meRequest = $factory->createServerRequest('GET', '/me');
if ($cookie) {
$meRequest = $meRequest->withHeader('Cookie', $cookie);
}
$meResponse = $app->handle($meRequest);
self::assertSame(200, $meResponse->getStatusCode());
}
public function testRegistrationRejectsDuplicates(): void
{
$pdo = TestDatabase::create();
TestDatabase::reset($pdo);
TestDatabase::seedMinimal($pdo);
$time = new FixedTimeProvider(new \DateTimeImmutable('2026-02-03 00:00:00'));
$app = TestAppFactory::create($pdo, $time);
$factory = new ServerRequestFactory();
$cookie = null;
$step1 = $this->jsonRequest($factory, 'POST', '/auth/register/step1', [
'race_key' => 'human',
], $cookie);
$response1 = $app->handle($step1);
$cookie = $this->extractCookie($response1, $cookie);
$step2 = $this->jsonRequest($factory, 'POST', '/auth/register/step2', [
'avatar_key' => 'avatar-01',
'title' => 'Pilot',
], $cookie);
$response2 = $app->handle($step2);
$cookie = $this->extractCookie($response2, $cookie);
$dupUsername = $this->jsonRequest($factory, 'POST', '/auth/register/step3', [
'username' => 'tester',
'email' => 'unique@example.test',
'password' => 'change-me',
], $cookie);
$dupResponse = $app->handle($dupUsername);
self::assertSame(409, $dupResponse->getStatusCode());
$dupEmail = $this->jsonRequest($factory, 'POST', '/auth/register/step3', [
'username' => 'unique-user',
'email' => 'tester@example.test',
'password' => 'change-me',
], $cookie);
$dupEmailResponse = $app->handle($dupEmail);
self::assertSame(409, $dupEmailResponse->getStatusCode());
}
/**
* @param array<string,mixed> $payload
*/
private function jsonRequest(ServerRequestFactory $factory, string $method, string $path, array $payload = [], ?string $cookie = null): \Psr\Http\Message\ServerRequestInterface
{
$request = $factory->createServerRequest($method, $path)
->withHeader('Content-Type', 'application/json');
if ($cookie) {
$request = $request->withHeader('Cookie', $cookie);
}
if ($payload !== []) {
$request->getBody()->write(json_encode($payload));
$request->getBody()->rewind();
}
return $request;
}
private function extractCookie(\Psr\Http\Message\ResponseInterface $response, ?string $fallback): ?string
{
$setCookie = $response->getHeaderLine('Set-Cookie');
if ($setCookie === '') {
return $fallback;
}
$parts = explode(';', $setCookie);
return trim($parts[0]);
}
}